Commit 3d515209 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rdma updates from Jason Gunthorpe:
 "Usual collection of small improvements and fixes:

   - Bug fixes and minor improvments in efa, irdma, mlx4, mlx5, rxe,
     hf1, qib, ocrdma

   - bnxt_re support for MSN, which is a new retransmit logic

   - Initial mana support for RC qps

   - Use after free bug and cleanups in iwcm

   - Reduce resource usage in mlx5 when RDMA verbs features are not used

   - New verb to drain shared recieve queues, similar to normal recieve
     queues. This is necessary to allow ULPs a clean shutdown. Used in
     the iscsi rdma target

   - mlx5 support for more than 16 bits of doorbell indexes

   - Doorbell moderation support for bnxt_re

   - IB multi-plane support for mlx5

   - New EFA adaptor PCI IDs

   - RDMA_NAME_ASSIGN_TYPE_USER to hint to userspace that it shouldn't
     rename the device

   - A collection of hns bugs

   - Fix long standing bug in bnxt_re with incorrect endian handling of
     immediate data"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma: (65 commits)
  IB/hfi1: Constify struct flag_table
  RDMA/mana_ib: Set correct device into ib
  bnxt_re: Fix imm_data endianness
  RDMA: Fix netdev tracker in ib_device_set_netdev
  RDMA/hns: Fix mbx timing out before CMD execution is completed
  RDMA/hns: Fix insufficient extend DB for VFs.
  RDMA/hns: Fix undifined behavior caused by invalid max_sge
  RDMA/hns: Fix shift-out-bounds when max_inline_data is 0
  RDMA/hns: Fix missing pagesize and alignment check in FRMR
  RDMA/hns: Fix unmatch exception handling when init eq table fails
  RDMA/hns: Fix soft lockup under heavy CEQE load
  RDMA/hns: Check atomic wr length
  RDMA/ocrdma: Don't inline statistics functions
  RDMA/core: Introduce "name_assign_type" for an IB device
  RDMA/qib: Fix truncation compilation warnings in qib_verbs.c
  RDMA/qib: Fix truncation compilation warnings in qib_init.c
  RDMA/efa: Add EFA 0xefa3 PCI ID
  RDMA/mlx5: Support per-plane port IB counters by querying PPCNT register
  net/mlx5: mlx5_ifc update for accessing ppcnt register of plane ports
  RDMA/mlx5: Add plane index support when querying PTYS registers
  ...
parents ef7c8f2b 887cd308
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11207,7 +11207,7 @@ F: include/linux/net/intel/iidc.h
INTEL ETHERNET PROTOCOL DRIVER FOR RDMA
M:	Mustafa Ismail <mustafa.ismail@intel.com>
M:	Shiraz Saleem <shiraz.saleem@intel.com>
M:	Tatyana Nikolova <tatyana.e.nikolova@intel.com>
L:	linux-rdma@vger.kernel.org
S:	Supported
F:	drivers/infiniband/hw/irdma/
+22 −10
Original line number Diff line number Diff line
@@ -59,7 +59,16 @@ __ib_get_agent_port(const struct ib_device *device, int port_num)
	struct ib_agent_port_private *entry;

	list_for_each_entry(entry, &ib_agent_port_list, port_list) {
		if (entry->agent[1]->device == device &&
		/* Need to check both agent[0] and agent[1], as an agent port
		 * may only have one of them
		 */
		if (entry->agent[0] &&
		    entry->agent[0]->device == device &&
		    entry->agent[0]->port_num == port_num)
			return entry;

		if (entry->agent[1] &&
		    entry->agent[1]->device == device &&
		    entry->agent[1]->port_num == port_num)
			return entry;
	}
@@ -172,6 +181,7 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
		}
	}

	if (rdma_cap_ib_cm(device, port_num)) {
		/* Obtain send only MAD agent for GSI QP */
		port_priv->agent[1] = ib_register_mad_agent(device, port_num,
							    IB_QPT_GSI, NULL, 0,
@@ -181,6 +191,7 @@ int ib_agent_port_open(struct ib_device *device, int port_num)
			ret = PTR_ERR(port_priv->agent[1]);
			goto error3;
		}
	}

	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
	list_add_tail(&port_priv->port_list, &ib_agent_port_list);
@@ -212,6 +223,7 @@ int ib_agent_port_close(struct ib_device *device, int port_num)
	list_del(&port_priv->port_list);
	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);

	if (port_priv->agent[1])
		ib_unregister_mad_agent(port_priv->agent[1]);
	if (port_priv->agent[0])
		ib_unregister_mad_agent(port_priv->agent[0]);
+5 −9
Original line number Diff line number Diff line
@@ -794,7 +794,6 @@ static struct ib_gid_table *alloc_gid_table(int sz)
static void release_gid_table(struct ib_device *device,
			      struct ib_gid_table *table)
{
	bool leak = false;
	int i;

	if (!table)
@@ -803,15 +802,12 @@ static void release_gid_table(struct ib_device *device,
	for (i = 0; i < table->sz; i++) {
		if (is_gid_entry_free(table->data_vec[i]))
			continue;
		if (kref_read(&table->data_vec[i]->kref) > 1) {
			dev_err(&device->dev,
				"GID entry ref leak for index %d ref=%u\n", i,

		WARN_ONCE(true,
			  "GID entry ref leak for dev %s index %d ref=%u\n",
			  dev_name(&device->dev), i,
			  kref_read(&table->data_vec[i]->kref));
			leak = true;
		}
	}
	if (leak)
		return;

	mutex_destroy(&table->lock);
	kfree(table->data_vec);
+74 −9
Original line number Diff line number Diff line
@@ -503,6 +503,7 @@ static void ib_device_release(struct device *device)
			  rcu_head);
	}

	mutex_destroy(&dev->subdev_lock);
	mutex_destroy(&dev->unregistration_lock);
	mutex_destroy(&dev->compat_devs_mutex);

@@ -641,6 +642,11 @@ struct ib_device *_ib_alloc_device(size_t size)
		BIT_ULL(IB_USER_VERBS_CMD_REG_MR) |
		BIT_ULL(IB_USER_VERBS_CMD_REREG_MR) |
		BIT_ULL(IB_USER_VERBS_CMD_RESIZE_CQ);

	mutex_init(&device->subdev_lock);
	INIT_LIST_HEAD(&device->subdev_list_head);
	INIT_LIST_HEAD(&device->subdev_list);

	return device;
}
EXPORT_SYMBOL(_ib_alloc_device);
@@ -1461,6 +1467,18 @@ EXPORT_SYMBOL(ib_register_device);
/* Callers must hold a get on the device. */
static void __ib_unregister_device(struct ib_device *ib_dev)
{
	struct ib_device *sub, *tmp;

	mutex_lock(&ib_dev->subdev_lock);
	list_for_each_entry_safe_reverse(sub, tmp,
					 &ib_dev->subdev_list_head,
					 subdev_list) {
		list_del(&sub->subdev_list);
		ib_dev->ops.del_sub_dev(sub);
		ib_device_put(ib_dev);
	}
	mutex_unlock(&ib_dev->subdev_lock);

	/*
	 * We have a registration lock so that all the calls to unregister are
	 * fully fenced, once any unregister returns the device is truely
@@ -2146,6 +2164,9 @@ int ib_device_set_netdev(struct ib_device *ib_dev, struct net_device *ndev,
	unsigned long flags;
	int ret;

	if (!rdma_is_port_valid(ib_dev, port))
		return -EINVAL;

	/*
	 * Drivers wish to call this before ib_register_driver, so we have to
	 * setup the port data early.
@@ -2154,9 +2175,6 @@ int ib_device_set_netdev(struct ib_device *ib_dev, struct net_device *ndev,
	if (ret)
		return ret;

	if (!rdma_is_port_valid(ib_dev, port))
		return -EINVAL;

	pdata = &ib_dev->port_data[port];
	spin_lock_irqsave(&pdata->netdev_lock, flags);
	old_ndev = rcu_dereference_protected(
@@ -2166,16 +2184,12 @@ int ib_device_set_netdev(struct ib_device *ib_dev, struct net_device *ndev,
		return 0;
	}

	if (old_ndev)
		netdev_tracker_free(ndev, &pdata->netdev_tracker);
	if (ndev)
		netdev_hold(ndev, &pdata->netdev_tracker, GFP_ATOMIC);
	rcu_assign_pointer(pdata->netdev, ndev);
	netdev_put(old_ndev, &pdata->netdev_tracker);
	netdev_hold(ndev, &pdata->netdev_tracker, GFP_ATOMIC);
	spin_unlock_irqrestore(&pdata->netdev_lock, flags);

	add_ndev_hash(pdata);
	__dev_put(old_ndev);

	return 0;
}
EXPORT_SYMBOL(ib_device_set_netdev);
@@ -2597,6 +2611,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
		ops->uverbs_no_driver_id_binding;

	SET_DEVICE_OP(dev_ops, add_gid);
	SET_DEVICE_OP(dev_ops, add_sub_dev);
	SET_DEVICE_OP(dev_ops, advise_mr);
	SET_DEVICE_OP(dev_ops, alloc_dm);
	SET_DEVICE_OP(dev_ops, alloc_hw_device_stats);
@@ -2631,6 +2646,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
	SET_DEVICE_OP(dev_ops, dealloc_ucontext);
	SET_DEVICE_OP(dev_ops, dealloc_xrcd);
	SET_DEVICE_OP(dev_ops, del_gid);
	SET_DEVICE_OP(dev_ops, del_sub_dev);
	SET_DEVICE_OP(dev_ops, dereg_mr);
	SET_DEVICE_OP(dev_ops, destroy_ah);
	SET_DEVICE_OP(dev_ops, destroy_counters);
@@ -2727,6 +2743,55 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
}
EXPORT_SYMBOL(ib_set_device_ops);

int ib_add_sub_device(struct ib_device *parent,
		      enum rdma_nl_dev_type type,
		      const char *name)
{
	struct ib_device *sub;
	int ret = 0;

	if (!parent->ops.add_sub_dev || !parent->ops.del_sub_dev)
		return -EOPNOTSUPP;

	if (!ib_device_try_get(parent))
		return -EINVAL;

	sub = parent->ops.add_sub_dev(parent, type, name);
	if (IS_ERR(sub)) {
		ib_device_put(parent);
		return PTR_ERR(sub);
	}

	sub->type = type;
	sub->parent = parent;

	mutex_lock(&parent->subdev_lock);
	list_add_tail(&parent->subdev_list_head, &sub->subdev_list);
	mutex_unlock(&parent->subdev_lock);

	return ret;
}
EXPORT_SYMBOL(ib_add_sub_device);

int ib_del_sub_device_and_put(struct ib_device *sub)
{
	struct ib_device *parent = sub->parent;

	if (!parent)
		return -EOPNOTSUPP;

	mutex_lock(&parent->subdev_lock);
	list_del(&sub->subdev_list);
	mutex_unlock(&parent->subdev_lock);

	ib_device_put(sub);
	parent->ops.del_sub_dev(sub);
	ib_device_put(parent);

	return 0;
}
EXPORT_SYMBOL(ib_del_sub_device_and_put);

#ifdef CONFIG_INFINIBAND_VIRT_DMA
int ib_dma_virt_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents)
{
+18 −23
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ static struct iwcm_work *get_work(struct iwcm_id_private *cm_id_priv)

	if (list_empty(&cm_id_priv->work_free_list))
		return NULL;
	work = list_entry(cm_id_priv->work_free_list.next, struct iwcm_work,
	work = list_first_entry(&cm_id_priv->work_free_list, struct iwcm_work,
				free_list);
	list_del_init(&work->free_list);
	return work;
@@ -206,17 +206,17 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv)

/*
 * Release a reference on cm_id. If the last reference is being
 * released, free the cm_id and return 1.
 * released, free the cm_id and return 'true'.
 */
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
static bool iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
{
	if (refcount_dec_and_test(&cm_id_priv->refcount)) {
		BUG_ON(!list_empty(&cm_id_priv->work_list));
		free_cm_id(cm_id_priv);
		return 1;
		return true;
	}

	return 0;
	return false;
}

static void add_ref(struct iw_cm_id *cm_id)
@@ -368,8 +368,10 @@ EXPORT_SYMBOL(iw_cm_disconnect);
 *
 * Clean up all resources associated with the connection and release
 * the initial reference taken by iw_create_cm_id.
 *
 * Returns true if and only if the last cm_id_priv reference has been dropped.
 */
static void destroy_cm_id(struct iw_cm_id *cm_id)
static bool destroy_cm_id(struct iw_cm_id *cm_id)
{
	struct iwcm_id_private *cm_id_priv;
	struct ib_qp *qp;
@@ -439,7 +441,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
		iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
	}

	(void)iwcm_deref_id(cm_id_priv);
	return iwcm_deref_id(cm_id_priv);
}

/*
@@ -450,7 +452,8 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
 */
void iw_destroy_cm_id(struct iw_cm_id *cm_id)
{
	destroy_cm_id(cm_id);
	if (!destroy_cm_id(cm_id))
		flush_workqueue(iwcm_wq);
}
EXPORT_SYMBOL(iw_destroy_cm_id);

@@ -1017,16 +1020,13 @@ static void cm_work_handler(struct work_struct *_work)
	struct iw_cm_event levent;
	struct iwcm_id_private *cm_id_priv = work->cm_id;
	unsigned long flags;
	int empty;
	int ret = 0;

	spin_lock_irqsave(&cm_id_priv->lock, flags);
	empty = list_empty(&cm_id_priv->work_list);
	while (!empty) {
		work = list_entry(cm_id_priv->work_list.next,
	while (!list_empty(&cm_id_priv->work_list)) {
		work = list_first_entry(&cm_id_priv->work_list,
					struct iwcm_work, list);
		list_del_init(&work->list);
		empty = list_empty(&cm_id_priv->work_list);
		levent = work->event;
		put_work(work);
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -1034,13 +1034,11 @@ static void cm_work_handler(struct work_struct *_work)
		if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
			ret = process_event(cm_id_priv, &levent);
			if (ret)
				destroy_cm_id(&cm_id_priv->id);
				WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id));
		} else
			pr_debug("dropping event %d\n", levent.event);
		if (iwcm_deref_id(cm_id_priv))
			return;
		if (empty)
			return;
		spin_lock_irqsave(&cm_id_priv->lock, flags);
	}
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -1093,11 +1091,8 @@ static int cm_event_handler(struct iw_cm_id *cm_id,
	}

	refcount_inc(&cm_id_priv->refcount);
	if (list_empty(&cm_id_priv->work_list)) {
	list_add_tail(&work->list, &cm_id_priv->work_list);
	queue_work(iwcm_wq, &work->work);
	} else
		list_add_tail(&work->list, &cm_id_priv->work_list);
out:
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
	return ret;
Loading