Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38137a51 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+56 −33
Original line number Diff line number Diff line
@@ -173,12 +173,15 @@ static void start_ep_timer(struct c4iw_ep *ep)
	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);
	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);
		return 0;
	}
	return 1;
}

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)
	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);

	/*
	 * Stop mpa timer.  If it expired, then the state has
	 * changed and we bail since ep_timeout already aborted
	 * the connection.
	 * Stop mpa timer.  If it expired, then
	 * we ignore the MPA reply.  process_timeout()
	 * will abort the connection.
	 */
	stop_ep_timer(ep);
	if (ep->com.state != MPA_REQ_SENT)
	if (stop_ep_timer(ep))
		return;

	/*
@@ -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);

	if (ep->com.state != MPA_REQ_WAIT)
		return;

	/*
	 * If we get more than the supported amount of private data
	 * then we must fail this connection.
	 */
	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);
		return;
	}
@@ -1413,13 +1412,13 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
	if (mpa->revision > mpa_rev) {
		printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d,"
		       " Received = %d\n", __func__, mpa_rev, mpa->revision);
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		abort_connection(ep, skb, GFP_KERNEL);
		return;
	}

	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);
		return;
	}
@@ -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.
	 */
	if (plen > MPA_MAX_PRIVATE_DATA) {
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		abort_connection(ep, skb, GFP_KERNEL);
		return;
	}
@@ -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 (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		abort_connection(ep, skb, GFP_KERNEL);
		return;
	}
@@ -1496,8 +1495,13 @@ 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.p2p_type);

	/*
	 * If the endpoint timer already expired, then we ignore
	 * the start request.  process_timeout() will abort
	 * the connection.
	 */
	if (!stop_ep_timer(ep)) {
		__state_set(&ep->com, MPA_REQ_RCVD);
	stop_ep_timer(ep);

		/* drive upcall */
		mutex_lock(&ep->parent_ep->com.mutex);
@@ -1508,6 +1512,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
			abort_connection(ep, skb, GFP_KERNEL);
		}
		mutex_unlock(&ep->parent_ep->com.mutex);
	}
	return;
}

@@ -2265,7 +2270,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
		disconnect = 0;
		break;
	case MORIBUND:
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		if (ep->com.cm_id && ep->com.qp) {
			attrs.next_state = C4IW_QP_STATE_IDLE;
			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)
	case CONNECTING:
		break;
	case MPA_REQ_WAIT:
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		break;
	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))
			connect_reply_upcall(ep, -ECONNRESET);
		else {
@@ -2433,7 +2438,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
		__state_set(&ep->com, MORIBUND);
		break;
	case MORIBUND:
		stop_ep_timer(ep);
		(void)stop_ep_timer(ep);
		if ((ep->com.cm_id) && (ep->com.qp)) {
			attrs.next_state = C4IW_QP_STATE_IDLE;
			c4iw_modify_qp(ep->com.qp->rhp,
@@ -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)) {
			close = 1;
			if (abrupt) {
				stop_ep_timer(ep);
				(void)stop_ep_timer(ep);
				ep->com.state = ABORTING;
			} else
				ep->com.state = MORIBUND;
@@ -3462,6 +3467,16 @@ static void process_timeout(struct c4iw_ep *ep)
		__state_set(&ep->com, ABORTING);
		close_complete_upcall(ep, -ETIMEDOUT);
		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:
		WARN(1, "%s unexpected state ep %p tid %u state %u\n",
			__func__, ep, ep->hwtid, ep->com.state);
@@ -3483,6 +3498,8 @@ static void process_timedout_eps(void)

		tmp = timeout_list.next;
		list_del(tmp);
		tmp->next = NULL;
		tmp->prev = NULL;
		spin_unlock_irq(&timeout_lock);
		ep = list_entry(tmp, struct c4iw_ep, entry);
		process_timeout(ep);
@@ -3499,6 +3516,7 @@ static void process_work(struct work_struct *work)
	unsigned int opcode;
	int ret;

	process_timedout_eps();
	while ((skb = skb_dequeue(&rxq))) {
		rpl = cplhdr(skb);
		dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
@@ -3508,9 +3526,9 @@ static void process_work(struct work_struct *work)
		ret = work_handlers[opcode](dev, skb);
		if (!ret)
			kfree_skb(skb);
	}
		process_timedout_eps();
	}
}

static DECLARE_WORK(skb_work, process_work);

@@ -3521,9 +3539,14 @@ static void ep_timeout(unsigned long arg)

	spin_lock(&timeout_lock);
	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
		/*
		 * 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);
	if (kickit)
		queue_work(workq, &skb_work);
+9 −15
Original line number Diff line number Diff line
@@ -235,15 +235,12 @@ int c4iw_flush_sq(struct c4iw_qp *qhp)
	struct t4_cq *cq = &chp->cq;
	int idx;
	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)
		wq->sq.flush_cidx = wq->sq.cidx;
	idx = wq->sq.flush_cidx;
	BUG_ON(idx >= wq->sq.size);
	while (idx != wq->sq.pidx) {
		if (error) {
		swsqe = &wq->sq.sw_sq[idx];
		BUG_ON(swsqe->flushed);
		swsqe->flushed = 1;
@@ -253,9 +250,6 @@ int c4iw_flush_sq(struct c4iw_qp *qhp)
			advance_oldest_read(wq);
		}
		flushed++;
		} else {
			t4_sq_consume(wq);
		}
		if (++idx == wq->sq.size)
			idx = 0;
	}
@@ -678,7 +672,7 @@ skip_cqe:
static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
{
	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;
	u32 credit = 0;
	u8 cqe_flushed;
+33 −8
Original line number Diff line number Diff line
@@ -682,6 +682,9 @@ static void c4iw_dealloc(struct uld_ctx *ctx)
	idr_destroy(&ctx->dev->hwtid_idr);
	idr_destroy(&ctx->dev->stid_idr);
	idr_destroy(&ctx->dev->atid_idr);
	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);
	ctx->dev = NULL;
@@ -722,11 +725,31 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *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) -
		 roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size));
	/*
	 * For T5 devices, we map all of BAR2 with WC.
	 * For T4 devices with onchip qp mem, we map only that part
	 * of BAR2 with WC.
	 */
	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: "
	       "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)
static void resume_rc_qp(struct c4iw_qp *qp)
{
	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;
	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;
	spin_unlock(&qp->lock);
}
+2 −0
Original line number Diff line number Diff line
@@ -149,6 +149,8 @@ struct c4iw_rdev {
	struct gen_pool *ocqp_pool;
	u32 flags;
	struct cxgb4_lld_info lldi;
	unsigned long bar2_pa;
	void __iomem *bar2_kva;
	unsigned long oc_mw_pa;
	void __iomem *oc_mw_kva;
	struct c4iw_stats stats;
+5 −1
Original line number Diff line number Diff line
@@ -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)) {
		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;
		}
		mutex_lock(&rdev->stats.lock);
		rdev->stats.stag.cur += 32;
		if (rdev->stats.stag.cur > rdev->stats.stag.max)
Loading