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

Commit 0cda6113 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull base rdma updates from Doug Ledford:
 "Round one of 4.8 code: while this is mostly normal, there is a new
  driver in here (the driver was hosted outside the kernel for several
  years and is actually a fairly mature and well coded driver).  It
  amounts to 13,000 of the 16,000 lines of added code in here.

  Summary:

   - Updates/fixes for iw_cxgb4 driver
   - Updates/fixes for mlx5 driver
   - Add flow steering and RSS API
   - Add hardware stats to mlx4 and mlx5 drivers
   - Add firmware version API for RDMA driver use
   - Add the rxe driver (this is a software RoCE driver that makes any
     Ethernet device a RoCE device)
   - Fixes for i40iw driver
   - Support for send only multicast joins in the cma layer
   - Other minor fixes"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma: (72 commits)
  Soft RoCE driver
  IB/core: Support for CMA multicast join flags
  IB/sa: Add cached attribute containing SM information to SA port
  IB/uverbs: Fix race between uverbs_close and remove_one
  IB/mthca: Clean up error unwind flow in mthca_reset()
  IB/mthca: NULL arg to pci_dev_put is OK
  IB/hfi1: NULL arg to sc_return_credits is OK
  IB/mlx4: Add diagnostic hardware counters
  net/mlx4: Query performance and diagnostics counters
  net/mlx4: Add diagnostic counters capability bit
  Use smaller 512 byte messages for portmapper messages
  IB/ipoib: Report SG feature regardless of HW UD CSUM capability
  IB/mlx4: Don't use GFP_ATOMIC for CQ resize struct
  IB/hfi1: Disable by default
  IB/rdmavt: Disable by default
  IB/mlx5: Fix port counter ID association to QP offset
  IB/mlx5: Fix iteration overrun in GSI qps
  i40iw: Add NULL check for puda buffer
  i40iw: Change dup_ack_thresh to u8
  i40iw: Remove unnecessary check for moving CQ head
  ...
parents fdf1f7ff 7f1d25b4
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -7647,6 +7647,15 @@ W: http://www.mellanox.com
Q:	http://patchwork.ozlabs.org/project/netdev/list/
Q:	http://patchwork.ozlabs.org/project/netdev/list/
F:	drivers/net/ethernet/mellanox/mlxsw/
F:	drivers/net/ethernet/mellanox/mlxsw/


SOFT-ROCE DRIVER (rxe)
M:	Moni Shoua <monis@mellanox.com>
L:	linux-rdma@vger.kernel.org
S:	Supported
W:	https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
Q:	http://patchwork.kernel.org/project/linux-rdma/list/
F:	drivers/infiniband/hw/rxe/
F:	include/uapi/rdma/rdma_user_rxe.h

MEMBARRIER SUPPORT
MEMBARRIER SUPPORT
M:	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
M:	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+1 −0
Original line number Original line Diff line number Diff line
@@ -84,6 +84,7 @@ source "drivers/infiniband/ulp/iser/Kconfig"
source "drivers/infiniband/ulp/isert/Kconfig"
source "drivers/infiniband/ulp/isert/Kconfig"


source "drivers/infiniband/sw/rdmavt/Kconfig"
source "drivers/infiniband/sw/rdmavt/Kconfig"
source "drivers/infiniband/sw/rxe/Kconfig"


source "drivers/infiniband/hw/hfi1/Kconfig"
source "drivers/infiniband/hw/hfi1/Kconfig"


+92 −6
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ MODULE_DESCRIPTION("Generic RDMA CM Agent");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_LICENSE("Dual BSD/GPL");


#define CMA_CM_RESPONSE_TIMEOUT 20
#define CMA_CM_RESPONSE_TIMEOUT 20
#define CMA_QUERY_CLASSPORT_INFO_TIMEOUT 3000
#define CMA_MAX_CM_RETRIES 15
#define CMA_MAX_CM_RETRIES 15
#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
#define CMA_IBOE_PACKET_LIFETIME 18
#define CMA_IBOE_PACKET_LIFETIME 18
@@ -162,6 +163,14 @@ struct rdma_bind_list {
	unsigned short		port;
	unsigned short		port;
};
};


struct class_port_info_context {
	struct ib_class_port_info	*class_port_info;
	struct ib_device		*device;
	struct completion		done;
	struct ib_sa_query		*sa_query;
	u8				port_num;
};

static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
			struct rdma_bind_list *bind_list, int snum)
			struct rdma_bind_list *bind_list, int snum)
{
{
@@ -306,6 +315,7 @@ struct cma_multicast {
	struct sockaddr_storage	addr;
	struct sockaddr_storage	addr;
	struct kref		mcref;
	struct kref		mcref;
	bool			igmp_joined;
	bool			igmp_joined;
	u8			join_state;
};
};


struct cma_work {
struct cma_work {
@@ -3752,10 +3762,63 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
	}
	}
}
}


static void cma_query_sa_classport_info_cb(int status,
					   struct ib_class_port_info *rec,
					   void *context)
{
	struct class_port_info_context *cb_ctx = context;

	WARN_ON(!context);

	if (status || !rec) {
		pr_debug("RDMA CM: %s port %u failed query ClassPortInfo status: %d\n",
			 cb_ctx->device->name, cb_ctx->port_num, status);
		goto out;
	}

	memcpy(cb_ctx->class_port_info, rec, sizeof(struct ib_class_port_info));

out:
	complete(&cb_ctx->done);
}

static int cma_query_sa_classport_info(struct ib_device *device, u8 port_num,
				       struct ib_class_port_info *class_port_info)
{
	struct class_port_info_context *cb_ctx;
	int ret;

	cb_ctx = kmalloc(sizeof(*cb_ctx), GFP_KERNEL);
	if (!cb_ctx)
		return -ENOMEM;

	cb_ctx->device = device;
	cb_ctx->class_port_info = class_port_info;
	cb_ctx->port_num = port_num;
	init_completion(&cb_ctx->done);

	ret = ib_sa_classport_info_rec_query(&sa_client, device, port_num,
					     CMA_QUERY_CLASSPORT_INFO_TIMEOUT,
					     GFP_KERNEL, cma_query_sa_classport_info_cb,
					     cb_ctx, &cb_ctx->sa_query);
	if (ret < 0) {
		pr_err("RDMA CM: %s port %u failed to send ClassPortInfo query, ret: %d\n",
		       device->name, port_num, ret);
		goto out;
	}

	wait_for_completion(&cb_ctx->done);

out:
	kfree(cb_ctx);
	return ret;
}

static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
				 struct cma_multicast *mc)
				 struct cma_multicast *mc)
{
{
	struct ib_sa_mcmember_rec rec;
	struct ib_sa_mcmember_rec rec;
	struct ib_class_port_info class_port_info;
	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
	ib_sa_comp_mask comp_mask;
	ib_sa_comp_mask comp_mask;
	int ret;
	int ret;
@@ -3774,7 +3837,24 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
	rec.qkey = cpu_to_be32(id_priv->qkey);
	rec.qkey = cpu_to_be32(id_priv->qkey);
	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
	rec.join_state = 1;
	rec.join_state = mc->join_state;

	if (rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) {
		ret = cma_query_sa_classport_info(id_priv->id.device,
						  id_priv->id.port_num,
						  &class_port_info);

		if (ret)
			return ret;

		if (!(ib_get_cpi_capmask2(&class_port_info) &
		      IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT)) {
			pr_warn("RDMA CM: %s port %u Unable to multicast join\n"
				"RDMA CM: SM doesn't support Send Only Full Member option\n",
				id_priv->id.device->name, id_priv->id.port_num);
			return -EOPNOTSUPP;
		}
	}


	comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
	comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
		    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
		    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
@@ -3843,6 +3923,9 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
	struct net_device *ndev = NULL;
	struct net_device *ndev = NULL;
	enum ib_gid_type gid_type;
	enum ib_gid_type gid_type;
	bool send_only;

	send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN);


	if (cma_zero_addr((struct sockaddr *)&mc->addr))
	if (cma_zero_addr((struct sockaddr *)&mc->addr))
		return -EINVAL;
		return -EINVAL;
@@ -3878,11 +3961,13 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
	if (addr->sa_family == AF_INET) {
	if (addr->sa_family == AF_INET) {
		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
			mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
			mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
			if (!send_only) {
				err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
				err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
						    true);
						    true);
				if (!err)
				if (!err)
					mc->igmp_joined = true;
					mc->igmp_joined = true;
			}
			}
		}
	} else {
	} else {
		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
			err = -ENOTSUPP;
			err = -ENOTSUPP;
@@ -3911,7 +3996,7 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
}
}


int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
			void *context)
			u8 join_state, void *context)
{
{
	struct rdma_id_private *id_priv;
	struct rdma_id_private *id_priv;
	struct cma_multicast *mc;
	struct cma_multicast *mc;
@@ -3930,6 +4015,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
	mc->context = context;
	mc->context = context;
	mc->id_priv = id_priv;
	mc->id_priv = id_priv;
	mc->igmp_joined = false;
	mc->igmp_joined = false;
	mc->join_state = join_state;
	spin_lock(&id_priv->lock);
	spin_lock(&id_priv->lock);
	list_add(&mc->list, &id_priv->mc_list);
	list_add(&mc->list, &id_priv->mc_list);
	spin_unlock(&id_priv->lock);
	spin_unlock(&id_priv->lock);
+9 −0
Original line number Original line Diff line number Diff line
@@ -311,6 +311,15 @@ static int read_port_immutable(struct ib_device *device)
	return 0;
	return 0;
}
}


void ib_get_device_fw_str(struct ib_device *dev, char *str, size_t str_len)
{
	if (dev->get_dev_fw_str)
		dev->get_dev_fw_str(dev, str, str_len);
	else
		str[0] = '\0';
}
EXPORT_SYMBOL(ib_get_device_fw_str);

/**
/**
 * ib_register_device - Register an IB device with IB core
 * ib_register_device - Register an IB device with IB core
 * @device:Device to register
 * @device:Device to register
+17 −37
Original line number Original line Diff line number Diff line
@@ -183,15 +183,14 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv)


/*
/*
 * Release a reference on cm_id. If the last reference is being
 * Release a reference on cm_id. If the last reference is being
 * released, enable the waiting thread (in iw_destroy_cm_id) to
 * released, free the cm_id and return 1.
 * get woken up, and return 1 if a thread is already waiting.
 */
 */
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
{
{
	BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
	BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
	if (atomic_dec_and_test(&cm_id_priv->refcount)) {
	if (atomic_dec_and_test(&cm_id_priv->refcount)) {
		BUG_ON(!list_empty(&cm_id_priv->work_list));
		BUG_ON(!list_empty(&cm_id_priv->work_list));
		complete(&cm_id_priv->destroy_comp);
		free_cm_id(cm_id_priv);
		return 1;
		return 1;
	}
	}


@@ -208,19 +207,10 @@ static void add_ref(struct iw_cm_id *cm_id)
static void rem_ref(struct iw_cm_id *cm_id)
static void rem_ref(struct iw_cm_id *cm_id)
{
{
	struct iwcm_id_private *cm_id_priv;
	struct iwcm_id_private *cm_id_priv;
	int cb_destroy;


	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);


	/*
	(void)iwcm_deref_id(cm_id_priv);
	 * Test bit before deref in case the cm_id gets freed on another
	 * thread.
	 */
	cb_destroy = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
	if (iwcm_deref_id(cm_id_priv) && cb_destroy) {
		BUG_ON(!list_empty(&cm_id_priv->work_list));
		free_cm_id(cm_id_priv);
	}
}
}


static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
@@ -370,6 +360,12 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
	wait_event(cm_id_priv->connect_wait,
	wait_event(cm_id_priv->connect_wait,
		   !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
		   !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));


	/*
	 * Since we're deleting the cm_id, drop any events that
	 * might arrive before the last dereference.
	 */
	set_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags);

	spin_lock_irqsave(&cm_id_priv->lock, flags);
	spin_lock_irqsave(&cm_id_priv->lock, flags);
	switch (cm_id_priv->state) {
	switch (cm_id_priv->state) {
	case IW_CM_STATE_LISTEN:
	case IW_CM_STATE_LISTEN:
@@ -433,13 +429,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
	struct iwcm_id_private *cm_id_priv;
	struct iwcm_id_private *cm_id_priv;


	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
	BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags));

	destroy_cm_id(cm_id);
	destroy_cm_id(cm_id);

	wait_for_completion(&cm_id_priv->destroy_comp);

	free_cm_id(cm_id_priv);
}
}
EXPORT_SYMBOL(iw_destroy_cm_id);
EXPORT_SYMBOL(iw_destroy_cm_id);


@@ -809,10 +799,7 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
	ret = cm_id->cm_handler(cm_id, iw_event);
	ret = cm_id->cm_handler(cm_id, iw_event);
	if (ret) {
	if (ret) {
		iw_cm_reject(cm_id, NULL, 0);
		iw_cm_reject(cm_id, NULL, 0);
		set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
		iw_destroy_cm_id(cm_id);
		destroy_cm_id(cm_id);
		if (atomic_read(&cm_id_priv->refcount)==0)
			free_cm_id(cm_id_priv);
	}
	}


out:
out:
@@ -1000,7 +987,6 @@ static void cm_work_handler(struct work_struct *_work)
	unsigned long flags;
	unsigned long flags;
	int empty;
	int empty;
	int ret = 0;
	int ret = 0;
	int destroy_id;


	spin_lock_irqsave(&cm_id_priv->lock, flags);
	spin_lock_irqsave(&cm_id_priv->lock, flags);
	empty = list_empty(&cm_id_priv->work_list);
	empty = list_empty(&cm_id_priv->work_list);
@@ -1013,20 +999,14 @@ static void cm_work_handler(struct work_struct *_work)
		put_work(work);
		put_work(work);
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);


		if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
			ret = process_event(cm_id_priv, &levent);
			ret = process_event(cm_id_priv, &levent);
		if (ret) {
			if (ret)
			set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
				destroy_cm_id(&cm_id_priv->id);
				destroy_cm_id(&cm_id_priv->id);
		}
		} else
		BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
			pr_debug("dropping event %d\n", levent.event);
		destroy_id = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
		if (iwcm_deref_id(cm_id_priv))
		if (iwcm_deref_id(cm_id_priv)) {
			if (destroy_id) {
				BUG_ON(!list_empty(&cm_id_priv->work_list));
				free_cm_id(cm_id_priv);
			}
			return;
			return;
		}
		if (empty)
		if (empty)
			return;
			return;
		spin_lock_irqsave(&cm_id_priv->lock, flags);
		spin_lock_irqsave(&cm_id_priv->lock, flags);
Loading