diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx5/core')
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 139 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/cq.c | 17 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 47 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/eq.c | 15 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/main.c | 102 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 30 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/mr.c | 136 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 226 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/port.c | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/qp.c | 9 | 
11 files changed, 525 insertions, 200 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index 157fe8df2c3..8ff57e8e3e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -4,5 +4,5 @@  config MLX5_CORE  	tristate -	depends on PCI && X86 +	depends on PCI  	default n diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 5472cbd3402..87d1b018a9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -32,7 +32,6 @@  #include <asm-generic/kmap_types.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/errno.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> @@ -98,6 +97,7 @@ enum {  static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,  					   struct mlx5_cmd_msg *in,  					   struct mlx5_cmd_msg *out, +					   void *uout, int uout_size,  					   mlx5_cmd_cbk_t cbk,  					   void *context, int page_queue)  { @@ -110,6 +110,8 @@ static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd,  	ent->in		= in;  	ent->out	= out; +	ent->uout	= uout; +	ent->uout_size	= uout_size;  	ent->callback	= cbk;  	ent->context	= context;  	ent->cmd	= cmd; @@ -180,28 +182,32 @@ static int verify_block_sig(struct mlx5_cmd_prot_block *block)  	return 0;  } -static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token) +static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token, +			   int csum)  {  	block->token = token; -	block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 2); -	block->sig = ~xor8_buf(block, sizeof(*block) - 1); +	if (csum) { +		block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) - +					    sizeof(block->data) - 2); +		block->sig = ~xor8_buf(block, sizeof(*block) - 1); +	}  } -static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token) +static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum)  {  	struct mlx5_cmd_mailbox *next = msg->next;  	while (next) { -		calc_block_sig(next->buf, token); +		calc_block_sig(next->buf, token, csum);  		next = next->next;  	}  } -static void set_signature(struct mlx5_cmd_work_ent *ent) +static void set_signature(struct mlx5_cmd_work_ent *ent, int csum)  {  	ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay)); -	calc_chain_sig(ent->in, ent->token); -	calc_chain_sig(ent->out, ent->token); +	calc_chain_sig(ent->in, ent->token, csum); +	calc_chain_sig(ent->out, ent->token, csum);  }  static void poll_timeout(struct mlx5_cmd_work_ent *ent) @@ -530,6 +536,7 @@ static void cmd_work_handler(struct work_struct *work)  	ent->lay = lay;  	memset(lay, 0, sizeof(*lay));  	memcpy(lay->in, ent->in->first.data, sizeof(lay->in)); +	ent->op = be32_to_cpu(lay->in[0]) >> 16;  	if (ent->in->next)  		lay->in_ptr = cpu_to_be64(ent->in->next->dma);  	lay->inlen = cpu_to_be32(ent->in->len); @@ -539,8 +546,7 @@ static void cmd_work_handler(struct work_struct *work)  	lay->type = MLX5_PCI_CMD_XPORT;  	lay->token = ent->token;  	lay->status_own = CMD_OWNER_HW; -	if (!cmd->checksum_disabled) -		set_signature(ent); +	set_signature(ent, !cmd->checksum_disabled);  	dump_command(dev, ent, 1);  	ktime_get_ts(&ent->ts1); @@ -614,8 +620,8 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)  			       mlx5_command_str(msg_to_opcode(ent->in)),  			       msg_to_opcode(ent->in));  	} -	mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", err, -		      deliv_status_to_str(ent->status), ent->status); +	mlx5_core_dbg(dev, "err %d, delivery status %s(%d)\n", +		      err, deliv_status_to_str(ent->status), ent->status);  	return err;  } @@ -625,7 +631,8 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)   *    2. page queue commands do not support asynchrous completion   */  static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, -			   struct mlx5_cmd_msg *out, mlx5_cmd_cbk_t callback, +			   struct mlx5_cmd_msg *out, void *uout, int uout_size, +			   mlx5_cmd_cbk_t callback,  			   void *context, int page_queue, u8 *status)  {  	struct mlx5_cmd *cmd = &dev->cmd; @@ -639,7 +646,8 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,  	if (callback && page_queue)  		return -EINVAL; -	ent = alloc_cmd(cmd, in, out, callback, context, page_queue); +	ent = alloc_cmd(cmd, in, out, uout, uout_size, callback, context, +			page_queue);  	if (IS_ERR(ent))  		return PTR_ERR(ent); @@ -667,10 +675,10 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,  		op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);  		if (op < ARRAY_SIZE(cmd->stats)) {  			stats = &cmd->stats[op]; -			spin_lock(&stats->lock); +			spin_lock_irq(&stats->lock);  			stats->sum += ds;  			++stats->n; -			spin_unlock(&stats->lock); +			spin_unlock_irq(&stats->lock);  		}  		mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,  				   "fw exec time for %s is %lld nsec\n", @@ -773,8 +781,6 @@ static int mlx5_copy_from_msg(void *to, struct mlx5_cmd_msg *from, int size)  		copy = min_t(int, size, MLX5_CMD_DATA_BLOCK_SIZE);  		block = next->buf; -		if (xor8_buf(block, sizeof(*block)) != 0xff) -			return -EINVAL;  		memcpy(to, block->data, copy);  		to += copy; @@ -825,7 +831,7 @@ static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,  	int n;  	int i; -	msg = kzalloc(sizeof(*msg), GFP_KERNEL); +	msg = kzalloc(sizeof(*msg), flags);  	if (!msg)  		return ERR_PTR(-ENOMEM); @@ -1108,6 +1114,19 @@ void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)  		up(&cmd->sem);  } +static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg) +{ +	unsigned long flags; + +	if (msg->cache) { +		spin_lock_irqsave(&msg->cache->lock, flags); +		list_add_tail(&msg->list, &msg->cache->head); +		spin_unlock_irqrestore(&msg->cache->lock, flags); +	} else { +		mlx5_free_cmd_msg(dev, msg); +	} +} +  void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)  {  	struct mlx5_cmd *cmd = &dev->cmd; @@ -1116,6 +1135,10 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)  	void *context;  	int err;  	int i; +	ktime_t t1, t2, delta; +	s64 ds; +	struct mlx5_cmd_stats *stats; +	unsigned long flags;  	for (i = 0; i < (1 << cmd->log_sz); i++) {  		if (test_bit(i, &vector)) { @@ -1140,9 +1163,29 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)  			}  			free_ent(cmd, ent->idx);  			if (ent->callback) { +				t1 = timespec_to_ktime(ent->ts1); +				t2 = timespec_to_ktime(ent->ts2); +				delta = ktime_sub(t2, t1); +				ds = ktime_to_ns(delta); +				if (ent->op < ARRAY_SIZE(cmd->stats)) { +					stats = &cmd->stats[ent->op]; +					spin_lock_irqsave(&stats->lock, flags); +					stats->sum += ds; +					++stats->n; +					spin_unlock_irqrestore(&stats->lock, flags); +				} +  				callback = ent->callback;  				context = ent->context;  				err = ent->ret; +				if (!err) +					err = mlx5_copy_from_msg(ent->uout, +								 ent->out, +								 ent->uout_size); + +				mlx5_free_cmd_msg(dev, ent->out); +				free_msg(dev, ent->in); +  				free_cmd(ent);  				callback(err, context);  			} else { @@ -1159,7 +1202,8 @@ static int status_to_err(u8 status)  	return status ? -1 : 0; /* TBD more meaningful codes */  } -static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size) +static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size, +				      gfp_t gfp)  {  	struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM);  	struct mlx5_cmd *cmd = &dev->cmd; @@ -1171,7 +1215,7 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size)  		ent = &cmd->cache.med;  	if (ent) { -		spin_lock(&ent->lock); +		spin_lock_irq(&ent->lock);  		if (!list_empty(&ent->head)) {  			msg = list_entry(ent->head.next, typeof(*msg), list);  			/* For cached lists, we must explicitly state what is @@ -1180,43 +1224,34 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size)  			msg->len = in_size;  			list_del(&msg->list);  		} -		spin_unlock(&ent->lock); +		spin_unlock_irq(&ent->lock);  	}  	if (IS_ERR(msg)) -		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, in_size); +		msg = mlx5_alloc_cmd_msg(dev, gfp, in_size);  	return msg;  } -static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg) -{ -	if (msg->cache) { -		spin_lock(&msg->cache->lock); -		list_add_tail(&msg->list, &msg->cache->head); -		spin_unlock(&msg->cache->lock); -	} else { -		mlx5_free_cmd_msg(dev, msg); -	} -} -  static int is_manage_pages(struct mlx5_inbox_hdr *in)  {  	return be16_to_cpu(in->opcode) == MLX5_CMD_OP_MANAGE_PAGES;  } -int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, -		  int out_size) +static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, +		    int out_size, mlx5_cmd_cbk_t callback, void *context)  {  	struct mlx5_cmd_msg *inb;  	struct mlx5_cmd_msg *outb;  	int pages_queue; +	gfp_t gfp;  	int err;  	u8 status = 0;  	pages_queue = is_manage_pages(in); +	gfp = callback ? GFP_ATOMIC : GFP_KERNEL; -	inb = alloc_msg(dev, in_size); +	inb = alloc_msg(dev, in_size, gfp);  	if (IS_ERR(inb)) {  		err = PTR_ERR(inb);  		return err; @@ -1228,13 +1263,14 @@ int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,  		goto out_in;  	} -	outb = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, out_size); +	outb = mlx5_alloc_cmd_msg(dev, gfp, out_size);  	if (IS_ERR(outb)) {  		err = PTR_ERR(outb);  		goto out_in;  	} -	err = mlx5_cmd_invoke(dev, inb, outb, NULL, NULL, pages_queue, &status); +	err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context, +			      pages_queue, &status);  	if (err)  		goto out_out; @@ -1247,14 +1283,30 @@ int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,  	err = mlx5_copy_from_msg(out, outb, out_size);  out_out: -	mlx5_free_cmd_msg(dev, outb); +	if (!callback) +		mlx5_free_cmd_msg(dev, outb);  out_in: -	free_msg(dev, inb); +	if (!callback) +		free_msg(dev, inb);  	return err;  } + +int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, +		  int out_size) +{ +	return cmd_exec(dev, in, in_size, out, out_size, NULL, NULL); +}  EXPORT_SYMBOL(mlx5_cmd_exec); +int mlx5_cmd_exec_cb(struct mlx5_core_dev *dev, void *in, int in_size, +		     void *out, int out_size, mlx5_cmd_cbk_t callback, +		     void *context) +{ +	return cmd_exec(dev, in, in_size, out, out_size, callback, context); +} +EXPORT_SYMBOL(mlx5_cmd_exec_cb); +  static void destroy_msg_cache(struct mlx5_core_dev *dev)  {  	struct mlx5_cmd *cmd = &dev->cmd; @@ -1361,6 +1413,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)  		goto err_map;  	} +	cmd->checksum_disabled = 1;  	cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;  	cmd->bitmask = (1 << cmd->max_reg_cmds) - 1; @@ -1510,7 +1563,7 @@ int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr)  	case MLX5_CMD_STAT_BAD_SYS_STATE_ERR:		return -EIO;  	case MLX5_CMD_STAT_BAD_RES_ERR:			return -EINVAL;  	case MLX5_CMD_STAT_RES_BUSY:			return -EBUSY; -	case MLX5_CMD_STAT_LIM_ERR:			return -EINVAL; +	case MLX5_CMD_STAT_LIM_ERR:			return -ENOMEM;  	case MLX5_CMD_STAT_BAD_RES_STATE_ERR:		return -EINVAL;  	case MLX5_CMD_STAT_IX_ERR:			return -EINVAL;  	case MLX5_CMD_STAT_NO_RES_ERR:			return -EAGAIN; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index c2d660be6f7..43c5f480952 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -201,10 +201,23 @@ EXPORT_SYMBOL(mlx5_core_query_cq);  int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, -			int type, struct mlx5_cq_modify_params *params) +			struct mlx5_modify_cq_mbox_in *in, int in_sz)  { -	return -ENOSYS; +	struct mlx5_modify_cq_mbox_out out; +	int err; + +	memset(&out, 0, sizeof(out)); +	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MODIFY_CQ); +	err = mlx5_cmd_exec(dev, in, in_sz, &out, sizeof(out)); +	if (err) +		return err; + +	if (out.hdr.status) +		return mlx5_cmd_status_to_err(&out.hdr); + +	return 0;  } +EXPORT_SYMBOL(mlx5_core_modify_cq);  int mlx5_init_cq_table(struct mlx5_core_dev *dev)  { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 9c7194b26ee..10e1f1a1825 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -154,10 +154,10 @@ static ssize_t average_read(struct file *filp, char __user *buf, size_t count,  		return 0;  	stats = filp->private_data; -	spin_lock(&stats->lock); +	spin_lock_irq(&stats->lock);  	if (stats->n)  		field = div64_u64(stats->sum, stats->n); -	spin_unlock(&stats->lock); +	spin_unlock_irq(&stats->lock);  	ret = snprintf(tbuf, sizeof(tbuf), "%llu\n", field);  	if (ret > 0) {  		if (copy_to_user(buf, tbuf, ret)) @@ -175,10 +175,10 @@ static ssize_t average_write(struct file *filp, const char __user *buf,  	struct mlx5_cmd_stats *stats;  	stats = filp->private_data; -	spin_lock(&stats->lock); +	spin_lock_irq(&stats->lock);  	stats->sum = 0;  	stats->n = 0; -	spin_unlock(&stats->lock); +	spin_unlock_irq(&stats->lock);  	*pos += count; @@ -275,7 +275,7 @@ void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev)  }  static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, -			 int index) +			 int index, int *is_str)  {  	struct mlx5_query_qp_mbox_out *out;  	struct mlx5_qp_context *ctx; @@ -293,19 +293,40 @@ static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,  		goto out;  	} +	*is_str = 0;  	ctx = &out->ctx;  	switch (index) {  	case QP_PID:  		param = qp->pid;  		break;  	case QP_STATE: -		param = be32_to_cpu(ctx->flags) >> 28; +		param = (u64)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28); +		*is_str = 1;  		break;  	case QP_XPORT: -		param = (be32_to_cpu(ctx->flags) >> 16) & 0xff; +		param = (u64)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff); +		*is_str = 1;  		break;  	case QP_MTU: -		param = ctx->mtu_msgmax >> 5; +		switch (ctx->mtu_msgmax >> 5) { +		case IB_MTU_256: +			param = 256; +			break; +		case IB_MTU_512: +			param = 512; +			break; +		case IB_MTU_1024: +			param = 1024; +			break; +		case IB_MTU_2048: +			param = 2048; +			break; +		case IB_MTU_4096: +			param = 4096; +			break; +		default: +			param = 0; +		}  		break;  	case QP_N_RECV:  		param = 1 << ((ctx->rq_size_stride >> 3) & 0xf); @@ -414,6 +435,7 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,  	struct mlx5_field_desc *desc;  	struct mlx5_rsc_debug *d;  	char tbuf[18]; +	int is_str = 0;  	u64 field;  	int ret; @@ -424,7 +446,7 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,  	d = (void *)(desc - desc->i) - sizeof(*d);  	switch (d->type) {  	case MLX5_DBG_RSC_QP: -		field = qp_read_field(d->dev, d->object, desc->i); +		field = qp_read_field(d->dev, d->object, desc->i, &is_str);  		break;  	case MLX5_DBG_RSC_EQ: @@ -440,7 +462,12 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,  		return -EINVAL;  	} -	ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); + +	if (is_str) +		ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)field); +	else +		ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); +  	if (ret > 0) {  		if (copy_to_user(buf, tbuf, ret))  			return -EFAULT; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 443cc4d7b02..7f39ebcd6ad 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -208,7 +208,8 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)  		 */  		rmb(); -		mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type)); +		mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", +			      eq->eqn, eqe_type_str(eqe->type));  		switch (eqe->type) {  		case MLX5_EVENT_TYPE_COMP:  			cqn = be32_to_cpu(eqe->data.comp.cqn) & 0xffffff; @@ -270,14 +271,16 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)  				u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id);  				s32 npages = be32_to_cpu(eqe->data.req_pages.num_pages); -				mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages); +				mlx5_core_dbg(dev, "page request for func 0x%x, npages %d\n", +					      func_id, npages);  				mlx5_core_req_pages_handler(dev, func_id, npages);  			}  			break;  		default: -			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn); +			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", +				       eqe->type, eq->eqn);  			break;  		} @@ -354,7 +357,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,  	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_EQ);  	in->ctx.log_sz_usr_page = cpu_to_be32(ilog2(eq->nent) << 24 | uar->index);  	in->ctx.intr = vecidx; -	in->ctx.log_page_size = PAGE_SHIFT - 12; +	in->ctx.log_page_size = eq->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT;  	in->events_mask = cpu_to_be64(mask);  	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); @@ -366,9 +369,11 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,  		goto err_in;  	} +	snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s", +		 name, pci_name(dev->pdev));  	eq->eqn = out.eq_number;  	err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0, -			  name, eq); +			  eq->name, eq);  	if (err)  		goto err_eq; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index b47739b0b5f..ee24f132e31 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -46,8 +46,8 @@  #include "mlx5_core.h"  #define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "1.0" -#define DRIVER_RELDATE	"June 2013" +#define DRIVER_VERSION "2.2-1" +#define DRIVER_RELDATE	"Feb 2014"  MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");  MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library"); @@ -66,10 +66,10 @@ static int set_dma_caps(struct pci_dev *pdev)  	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));  	if (err) { -		dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); +		dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask\n");  		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));  		if (err) { -			dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); +			dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting\n");  			return err;  		}  	} @@ -77,11 +77,11 @@ static int set_dma_caps(struct pci_dev *pdev)  	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));  	if (err) {  		dev_warn(&pdev->dev, -			 "Warning: couldn't set 64-bit consistent PCI DMA mask.\n"); +			 "Warning: couldn't set 64-bit consistent PCI DMA mask\n");  		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));  		if (err) {  			dev_err(&pdev->dev, -				"Can't set consistent PCI DMA mask, aborting.\n"); +				"Can't set consistent PCI DMA mask, aborting\n");  			return err;  		}  	} @@ -95,7 +95,7 @@ static int request_bar(struct pci_dev *pdev)  	int err = 0;  	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { -		dev_err(&pdev->dev, "Missing registers BAR, aborting.\n"); +		dev_err(&pdev->dev, "Missing registers BAR, aborting\n");  		return -ENODEV;  	} @@ -116,7 +116,6 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)  	struct mlx5_eq_table *table = &dev->priv.eq_table;  	int num_eqs = 1 << dev->caps.log_max_eq;  	int nvec; -	int err;  	int i;  	nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; @@ -131,17 +130,12 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)  	for (i = 0; i < nvec; i++)  		table->msix_arr[i].entry = i; -retry: -	table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE; -	err = pci_enable_msix(dev->pdev, table->msix_arr, nvec); -	if (err <= 0) { -		return err; -	} else if (err > 2) { -		nvec = err; -		goto retry; -	} +	nvec = pci_enable_msix_range(dev->pdev, table->msix_arr, +				     MLX5_EQ_VEC_COMP_BASE, nvec); +	if (nvec < 0) +		return nvec; -	mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec); +	table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;  	return 0;  } @@ -159,15 +153,43 @@ struct mlx5_reg_host_endianess {  	u8      rsvd[15];  }; + +#define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos)) + +enum { +	MLX5_CAP_BITS_RW_MASK	= CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) | +				  CAP_MASK(MLX5_CAP_OFF_DCT, 1), +}; + +/* selectively copy writable fields clearing any reserved area + */ +static void copy_rw_fields(struct mlx5_hca_cap *to, struct mlx5_hca_cap *from) +{ +	u64 v64; + +	to->log_max_qp = from->log_max_qp & 0x1f; +	to->log_max_ra_req_dc = from->log_max_ra_req_dc & 0x3f; +	to->log_max_ra_res_dc = from->log_max_ra_res_dc & 0x3f; +	to->log_max_ra_req_qp = from->log_max_ra_req_qp & 0x3f; +	to->log_max_ra_res_qp = from->log_max_ra_res_qp & 0x3f; +	to->log_max_atomic_size_qp = from->log_max_atomic_size_qp; +	to->log_max_atomic_size_dc = from->log_max_atomic_size_dc; +	v64 = be64_to_cpu(from->flags) & MLX5_CAP_BITS_RW_MASK; +	to->flags = cpu_to_be64(v64); +} + +enum { +	HCA_CAP_OPMOD_GET_MAX	= 0, +	HCA_CAP_OPMOD_GET_CUR	= 1, +}; +  static int handle_hca_cap(struct mlx5_core_dev *dev)  {  	struct mlx5_cmd_query_hca_cap_mbox_out *query_out = NULL;  	struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL;  	struct mlx5_cmd_query_hca_cap_mbox_in query_ctx;  	struct mlx5_cmd_set_hca_cap_mbox_out set_out; -	struct mlx5_profile *prof = dev->profile;  	u64 flags; -	int csum = 1;  	int err;  	memset(&query_ctx, 0, sizeof(query_ctx)); @@ -182,7 +204,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)  	}  	query_ctx.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP); -	query_ctx.hdr.opmod  = cpu_to_be16(0x1); +	query_ctx.hdr.opmod  = cpu_to_be16(HCA_CAP_OPMOD_GET_CUR);  	err = mlx5_cmd_exec(dev, &query_ctx, sizeof(query_ctx),  				 query_out, sizeof(*query_out));  	if (err) @@ -194,23 +216,16 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)  		goto query_ex;  	} -	memcpy(&set_ctx->hca_cap, &query_out->hca_cap, -	       sizeof(set_ctx->hca_cap)); - -	if (prof->mask & MLX5_PROF_MASK_CMDIF_CSUM) { -		csum = !!prof->cmdif_csum; -		flags = be64_to_cpu(set_ctx->hca_cap.flags); -		if (csum) -			flags |= MLX5_DEV_CAP_FLAG_CMDIF_CSUM; -		else -			flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; - -		set_ctx->hca_cap.flags = cpu_to_be64(flags); -	} +	copy_rw_fields(&set_ctx->hca_cap, &query_out->hca_cap);  	if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE)  		set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp; +	flags = be64_to_cpu(query_out->hca_cap.flags); +	/* disable checksum */ +	flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; + +	set_ctx->hca_cap.flags = cpu_to_be64(flags);  	memset(&set_out, 0, sizeof(set_out));  	set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12);  	set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP); @@ -225,9 +240,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)  	if (err)  		goto query_ex; -	if (!csum) -		dev->cmd.checksum_disabled = 1; -  query_ex:  	kfree(query_out);  	kfree(set_ctx); @@ -307,13 +319,13 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)  	err = pci_enable_device(pdev);  	if (err) { -		dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n"); +		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");  		goto err_dbg;  	}  	err = request_bar(pdev);  	if (err) { -		dev_err(&pdev->dev, "error requesting BARs, aborting.\n"); +		dev_err(&pdev->dev, "error requesting BARs, aborting\n");  		goto err_disable;  	} @@ -428,6 +440,7 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)  	mlx5_init_cq_table(dev);  	mlx5_init_qp_table(dev);  	mlx5_init_srq_table(dev); +	mlx5_init_mr_table(dev);  	return 0; @@ -442,7 +455,10 @@ disable_msix:  err_stop_poll:  	mlx5_stop_health_poll(dev); -	mlx5_cmd_teardown_hca(dev); +	if (mlx5_cmd_teardown_hca(dev)) { +		dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n"); +		return err; +	}  err_pagealloc_stop:  	mlx5_pagealloc_stop(dev); @@ -485,7 +501,10 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev)  	mlx5_eq_cleanup(dev);  	mlx5_disable_msix(dev);  	mlx5_stop_health_poll(dev); -	mlx5_cmd_teardown_hca(dev); +	if (mlx5_cmd_teardown_hca(dev)) { +		dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n"); +		return; +	}  	mlx5_pagealloc_stop(dev);  	mlx5_reclaim_startup_pages(dev);  	mlx5_core_disable_hca(dev); @@ -513,7 +532,6 @@ static int __init init(void)  	return 0; -	mlx5_health_cleanup();  err_debug:  	mlx5_unregister_debugfs();  	return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 68b74e1ae1b..f0c9f9a7a36 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -39,24 +39,26 @@  extern int mlx5_core_debug_mask; -#define mlx5_core_dbg(dev, format, arg...)				       \ -pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,   \ -	 current->pid, ##arg) +#define mlx5_core_dbg(dev, format, ...)					\ +	pr_debug("%s:%s:%d:(pid %d): " format,				\ +		 (dev)->priv.name, __func__, __LINE__, current->pid,	\ +		 ##__VA_ARGS__) -#define mlx5_core_dbg_mask(dev, mask, format, arg...)			       \ -do {									       \ -	if ((mask) & mlx5_core_debug_mask)				       \ -		pr_debug("%s:%s:%d:(pid %d): " format, (dev)->priv.name,       \ -			 __func__, __LINE__, current->pid, ##arg);	       \ +#define mlx5_core_dbg_mask(dev, mask, format, ...)			\ +do {									\ +	if ((mask) & mlx5_core_debug_mask)				\ +		mlx5_core_dbg(dev, format, ##__VA_ARGS__);		\  } while (0) -#define mlx5_core_err(dev, format, arg...) \ -pr_err("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,     \ -	current->pid, ##arg) +#define mlx5_core_err(dev, format, ...)					\ +	pr_err("%s:%s:%d:(pid %d): " format,				\ +	       (dev)->priv.name, __func__, __LINE__, current->pid,	\ +	       ##__VA_ARGS__) -#define mlx5_core_warn(dev, format, arg...) \ -pr_warn("%s:%s:%d:(pid %d): " format, (dev)->priv.name, __func__, __LINE__,    \ -	current->pid, ##arg) +#define mlx5_core_warn(dev, format, ...)				\ +	pr_warn("%s:%s:%d:(pid %d): " format,				\ +		(dev)->priv.name, __func__, __LINE__, current->pid,	\ +		##__VA_ARGS__)  enum {  	MLX5_CMD_DATA, /* print command payload only */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 5b44e2e46da..184c3615f47 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -36,32 +36,69 @@  #include <linux/mlx5/cmd.h>  #include "mlx5_core.h" +void mlx5_init_mr_table(struct mlx5_core_dev *dev) +{ +	struct mlx5_mr_table *table = &dev->priv.mr_table; + +	rwlock_init(&table->lock); +	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); +} + +void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev) +{ +} +  int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, -			  struct mlx5_create_mkey_mbox_in *in, int inlen) +			  struct mlx5_create_mkey_mbox_in *in, int inlen, +			  mlx5_cmd_cbk_t callback, void *context, +			  struct mlx5_create_mkey_mbox_out *out)  { -	struct mlx5_create_mkey_mbox_out out; +	struct mlx5_mr_table *table = &dev->priv.mr_table; +	struct mlx5_create_mkey_mbox_out lout;  	int err;  	u8 key; -	memset(&out, 0, sizeof(out)); -	spin_lock(&dev->priv.mkey_lock); +	memset(&lout, 0, sizeof(lout)); +	spin_lock_irq(&dev->priv.mkey_lock);  	key = dev->priv.mkey_key++; -	spin_unlock(&dev->priv.mkey_lock); +	spin_unlock_irq(&dev->priv.mkey_lock);  	in->seg.qpn_mkey7_0 |= cpu_to_be32(key);  	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY); -	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); +	if (callback) { +		err = mlx5_cmd_exec_cb(dev, in, inlen, out, sizeof(*out), +				       callback, context); +		return err; +	} else { +		err = mlx5_cmd_exec(dev, in, inlen, &lout, sizeof(lout)); +	} +  	if (err) { -		mlx5_core_dbg(dev, "cmd exec faile %d\n", err); +		mlx5_core_dbg(dev, "cmd exec failed %d\n", err);  		return err;  	} -	if (out.hdr.status) { -		mlx5_core_dbg(dev, "status %d\n", out.hdr.status); -		return mlx5_cmd_status_to_err(&out.hdr); +	if (lout.hdr.status) { +		mlx5_core_dbg(dev, "status %d\n", lout.hdr.status); +		return mlx5_cmd_status_to_err(&lout.hdr);  	} -	mr->key = mlx5_idx_to_mkey(be32_to_cpu(out.mkey) & 0xffffff) | key; -	mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", be32_to_cpu(out.mkey), key, mr->key); +	mr->iova = be64_to_cpu(in->seg.start_addr); +	mr->size = be64_to_cpu(in->seg.len); +	mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key; +	mr->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff; + +	mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", +		      be32_to_cpu(lout.mkey), key, mr->key); + +	/* connect to MR tree */ +	write_lock_irq(&table->lock); +	err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr); +	write_unlock_irq(&table->lock); +	if (err) { +		mlx5_core_warn(dev, "failed radix tree insert of mr 0x%x, %d\n", +			       mlx5_base_mkey(mr->key), err); +		mlx5_core_destroy_mkey(dev, mr); +	}  	return err;  } @@ -69,13 +106,25 @@ EXPORT_SYMBOL(mlx5_core_create_mkey);  int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)  { +	struct mlx5_mr_table *table = &dev->priv.mr_table;  	struct mlx5_destroy_mkey_mbox_in in;  	struct mlx5_destroy_mkey_mbox_out out; +	struct mlx5_core_mr *deleted_mr; +	unsigned long flags;  	int err;  	memset(&in, 0, sizeof(in));  	memset(&out, 0, sizeof(out)); +	write_lock_irqsave(&table->lock, flags); +	deleted_mr = radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key)); +	write_unlock_irqrestore(&table->lock, flags); +	if (!deleted_mr) { +		mlx5_core_warn(dev, "failed radix tree delete of mr 0x%x\n", +			       mlx5_base_mkey(mr->key)); +		return -ENOENT; +	} +  	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY);  	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));  	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); @@ -134,3 +183,66 @@ int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,  	return err;  }  EXPORT_SYMBOL(mlx5_core_dump_fill_mkey); + +int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn, +			 int npsvs, u32 *sig_index) +{ +	struct mlx5_allocate_psv_in in; +	struct mlx5_allocate_psv_out out; +	int i, err; + +	if (npsvs > MLX5_MAX_PSVS) +		return -EINVAL; + +	memset(&in, 0, sizeof(in)); +	memset(&out, 0, sizeof(out)); + +	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_PSV); +	in.npsv_pd = cpu_to_be32((npsvs << 28) | pdn); +	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); +	if (err) { +		mlx5_core_err(dev, "cmd exec failed %d\n", err); +		return err; +	} + +	if (out.hdr.status) { +		mlx5_core_err(dev, "create_psv bad status %d\n", +			      out.hdr.status); +		return mlx5_cmd_status_to_err(&out.hdr); +	} + +	for (i = 0; i < npsvs; i++) +		sig_index[i] = be32_to_cpu(out.psv_idx[i]) & 0xffffff; + +	return err; +} +EXPORT_SYMBOL(mlx5_core_create_psv); + +int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num) +{ +	struct mlx5_destroy_psv_in in; +	struct mlx5_destroy_psv_out out; +	int err; + +	memset(&in, 0, sizeof(in)); +	memset(&out, 0, sizeof(out)); + +	in.psv_number = cpu_to_be32(psv_num); +	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_PSV); +	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); +	if (err) { +		mlx5_core_err(dev, "destroy_psv cmd exec failed %d\n", err); +		goto out; +	} + +	if (out.hdr.status) { +		mlx5_core_err(dev, "destroy_psv bad status %d\n", +			      out.hdr.status); +		err = mlx5_cmd_status_to_err(&out.hdr); +		goto out; +	} + +out: +	return err; +} +EXPORT_SYMBOL(mlx5_core_destroy_psv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 3a2408d4482..c2a953ef0e6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -57,10 +57,13 @@ struct mlx5_pages_req {  };  struct fw_page { -	struct rb_node	rb_node; -	u64		addr; -	struct page	*page; -	u16		func_id; +	struct rb_node		rb_node; +	u64			addr; +	struct page	       *page; +	u16			func_id; +	unsigned long		bitmask; +	struct list_head	list; +	unsigned		free_count;  };  struct mlx5_query_pages_inbox { @@ -90,6 +93,15 @@ struct mlx5_manage_pages_outbox {  	__be64			pas[0];  }; +enum { +	MAX_RECLAIM_TIME_MSECS	= 5000, +}; + +enum { +	MLX5_MAX_RECLAIM_TIME_MILI	= 5000, +	MLX5_NUM_4K_IN_PAGE		= PAGE_SIZE / MLX5_ADAPTER_PAGE_SIZE, +}; +  static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u16 func_id)  {  	struct rb_root *root = &dev->priv.page_root; @@ -97,6 +109,7 @@ static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u  	struct rb_node *parent = NULL;  	struct fw_page *nfp;  	struct fw_page *tfp; +	int i;  	while (*new) {  		parent = *new; @@ -109,25 +122,29 @@ static int insert_page(struct mlx5_core_dev *dev, u64 addr, struct page *page, u  			return -EEXIST;  	} -	nfp = kmalloc(sizeof(*nfp), GFP_KERNEL); +	nfp = kzalloc(sizeof(*nfp), GFP_KERNEL);  	if (!nfp)  		return -ENOMEM;  	nfp->addr = addr;  	nfp->page = page;  	nfp->func_id = func_id; +	nfp->free_count = MLX5_NUM_4K_IN_PAGE; +	for (i = 0; i < MLX5_NUM_4K_IN_PAGE; i++) +		set_bit(i, &nfp->bitmask);  	rb_link_node(&nfp->rb_node, parent, new);  	rb_insert_color(&nfp->rb_node, root); +	list_add(&nfp->list, &dev->priv.free_list);  	return 0;  } -static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr) +static struct fw_page *find_fw_page(struct mlx5_core_dev *dev, u64 addr)  {  	struct rb_root *root = &dev->priv.page_root;  	struct rb_node *tmp = root->rb_node; -	struct page *result = NULL; +	struct fw_page *result = NULL;  	struct fw_page *tfp;  	while (tmp) { @@ -137,9 +154,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)  		} else if (tfp->addr > addr) {  			tmp = tmp->rb_right;  		} else { -			rb_erase(&tfp->rb_node, root); -			result = tfp->page; -			kfree(tfp); +			result = tfp;  			break;  		}  	} @@ -172,12 +187,97 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,  	return err;  } +static int alloc_4k(struct mlx5_core_dev *dev, u64 *addr) +{ +	struct fw_page *fp; +	unsigned n; + +	if (list_empty(&dev->priv.free_list)) +		return -ENOMEM; + +	fp = list_entry(dev->priv.free_list.next, struct fw_page, list); +	n = find_first_bit(&fp->bitmask, 8 * sizeof(fp->bitmask)); +	if (n >= MLX5_NUM_4K_IN_PAGE) { +		mlx5_core_warn(dev, "alloc 4k bug\n"); +		return -ENOENT; +	} +	clear_bit(n, &fp->bitmask); +	fp->free_count--; +	if (!fp->free_count) +		list_del(&fp->list); + +	*addr = fp->addr + n * MLX5_ADAPTER_PAGE_SIZE; + +	return 0; +} + +static void free_4k(struct mlx5_core_dev *dev, u64 addr) +{ +	struct fw_page *fwp; +	int n; + +	fwp = find_fw_page(dev, addr & PAGE_MASK); +	if (!fwp) { +		mlx5_core_warn(dev, "page not found\n"); +		return; +	} + +	n = (addr & ~PAGE_MASK) >> MLX5_ADAPTER_PAGE_SHIFT; +	fwp->free_count++; +	set_bit(n, &fwp->bitmask); +	if (fwp->free_count == MLX5_NUM_4K_IN_PAGE) { +		rb_erase(&fwp->rb_node, &dev->priv.page_root); +		if (fwp->free_count != 1) +			list_del(&fwp->list); +		dma_unmap_page(&dev->pdev->dev, addr & PAGE_MASK, PAGE_SIZE, +			       DMA_BIDIRECTIONAL); +		__free_page(fwp->page); +		kfree(fwp); +	} else if (fwp->free_count == 1) { +		list_add(&fwp->list, &dev->priv.free_list); +	} +} + +static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) +{ +	struct page *page; +	u64 addr; +	int err; + +	page = alloc_page(GFP_HIGHUSER); +	if (!page) { +		mlx5_core_warn(dev, "failed to allocate page\n"); +		return -ENOMEM; +	} +	addr = dma_map_page(&dev->pdev->dev, page, 0, +			    PAGE_SIZE, DMA_BIDIRECTIONAL); +	if (dma_mapping_error(&dev->pdev->dev, addr)) { +		mlx5_core_warn(dev, "failed dma mapping page\n"); +		err = -ENOMEM; +		goto out_alloc; +	} +	err = insert_page(dev, addr, page, func_id); +	if (err) { +		mlx5_core_err(dev, "failed to track allocated page\n"); +		goto out_mapping; +	} + +	return 0; + +out_mapping: +	dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + +out_alloc: +	__free_page(page); + +	return err; +}  static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,  		      int notify_fail)  {  	struct mlx5_manage_pages_inbox *in;  	struct mlx5_manage_pages_outbox out; -	struct page *page; +	struct mlx5_manage_pages_inbox *nin;  	int inlen;  	u64 addr;  	int err; @@ -192,27 +292,15 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,  	memset(&out, 0, sizeof(out));  	for (i = 0; i < npages; i++) { -		page = alloc_page(GFP_HIGHUSER); -		if (!page) { -			err = -ENOMEM; -			mlx5_core_warn(dev, "failed to allocate page\n"); -			goto out_alloc; -		} -		addr = dma_map_page(&dev->pdev->dev, page, 0, -				    PAGE_SIZE, DMA_BIDIRECTIONAL); -		if (dma_mapping_error(&dev->pdev->dev, addr)) { -			mlx5_core_warn(dev, "failed dma mapping page\n"); -			__free_page(page); -			err = -ENOMEM; -			goto out_alloc; -		} -		err = insert_page(dev, addr, page, func_id); +retry: +		err = alloc_4k(dev, &addr);  		if (err) { -			mlx5_core_err(dev, "failed to track allocated page\n"); -			dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); -			__free_page(page); -			err = -ENOMEM; -			goto out_alloc; +			if (err == -ENOMEM) +				err = alloc_system_page(dev, func_id); +			if (err) +				goto out_4k; + +			goto retry;  		}  		in->pas[i] = cpu_to_be64(addr);  	} @@ -222,9 +310,9 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,  	in->func_id = cpu_to_be16(func_id);  	in->num_entries = cpu_to_be32(npages);  	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); -	mlx5_core_dbg(dev, "err %d\n", err);  	if (err) { -		mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", func_id, npages, err); +		mlx5_core_warn(dev, "func_id 0x%x, npages %d, err %d\n", +			       func_id, npages, err);  		goto out_alloc;  	}  	dev->priv.fw_pages += npages; @@ -232,7 +320,8 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,  	if (out.hdr.status) {  		err = mlx5_cmd_status_to_err(&out.hdr);  		if (err) { -			mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", func_id, npages, out.hdr.status); +			mlx5_core_warn(dev, "func_id 0x%x, npages %d, status %d\n", +				       func_id, npages, out.hdr.status);  			goto out_alloc;  		}  	} @@ -243,25 +332,22 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,  out_alloc:  	if (notify_fail) { -		memset(in, 0, inlen); -		memset(&out, 0, sizeof(out)); -		in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); -		in->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE); -		if (mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out))) -			mlx5_core_warn(dev, "\n"); -	} -	for (i--; i >= 0; i--) { -		addr = be64_to_cpu(in->pas[i]); -		page = remove_page(dev, addr); -		if (!page) { -			mlx5_core_err(dev, "BUG: can't remove page at addr 0x%llx\n", -				      addr); -			continue; +		nin = kzalloc(sizeof(*nin), GFP_KERNEL); +		if (!nin) { +			mlx5_core_warn(dev, "allocation failed\n"); +			goto out_4k;  		} -		dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); -		__free_page(page); +		memset(&out, 0, sizeof(out)); +		nin->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); +		nin->hdr.opmod = cpu_to_be16(MLX5_PAGES_CANT_GIVE); +		if (mlx5_cmd_exec(dev, nin, sizeof(*nin), &out, sizeof(out))) +			mlx5_core_warn(dev, "page notify failed\n"); +		kfree(nin);  	} +out_4k: +	for (i--; i >= 0; i--) +		free_4k(dev, be64_to_cpu(in->pas[i]));  out_free:  	mlx5_vfree(in);  	return err; @@ -272,13 +358,15 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,  {  	struct mlx5_manage_pages_inbox   in;  	struct mlx5_manage_pages_outbox *out; -	struct page *page;  	int num_claimed;  	int outlen;  	u64 addr;  	int err;  	int i; +	if (nclaimed) +		*nclaimed = 0; +  	memset(&in, 0, sizeof(in));  	outlen = sizeof(*out) + npages * sizeof(out->pas[0]);  	out = mlx5_vzalloc(outlen); @@ -292,7 +380,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,  	mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);  	err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);  	if (err) { -		mlx5_core_err(dev, "failed recliaming pages\n"); +		mlx5_core_err(dev, "failed reclaiming pages\n");  		goto out_free;  	}  	dev->priv.fw_pages -= npages; @@ -308,13 +396,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,  	for (i = 0; i < num_claimed; i++) {  		addr = be64_to_cpu(out->pas[i]); -		page = remove_page(dev, addr); -		if (!page) { -			mlx5_core_warn(dev, "FW reported unknown DMA address 0x%llx\n", addr); -		} else { -			dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL); -			__free_page(page); -		} +		free_4k(dev, addr);  	}  out_free: @@ -334,8 +416,8 @@ static void pages_work_handler(struct work_struct *work)  		err = give_pages(dev, req->func_id, req->npages, 1);  	if (err) -		mlx5_core_warn(dev, "%s fail %d\n", req->npages < 0 ? -			       "reclaim" : "give", err); +		mlx5_core_warn(dev, "%s fail %d\n", +			       req->npages < 0 ? "reclaim" : "give", err);  	kfree(req);  } @@ -374,34 +456,45 @@ int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)  	return give_pages(dev, func_id, npages, 0);  } +enum { +	MLX5_BLKS_FOR_RECLAIM_PAGES = 12 +}; +  static int optimal_reclaimed_pages(void)  {  	struct mlx5_cmd_prot_block *block;  	struct mlx5_cmd_layout *lay;  	int ret; -	ret = (sizeof(lay->in) + sizeof(block->data) - -	       sizeof(struct mlx5_manage_pages_outbox)) / 8; +	ret = (sizeof(lay->out) + MLX5_BLKS_FOR_RECLAIM_PAGES * sizeof(block->data) - +	       sizeof(struct mlx5_manage_pages_outbox)) / +	       FIELD_SIZEOF(struct mlx5_manage_pages_outbox, pas[0]);  	return ret;  }  int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)  { -	unsigned long end = jiffies + msecs_to_jiffies(5000); +	unsigned long end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);  	struct fw_page *fwp;  	struct rb_node *p; +	int nclaimed = 0;  	int err;  	do {  		p = rb_first(&dev->priv.page_root);  		if (p) {  			fwp = rb_entry(p, struct fw_page, rb_node); -			err = reclaim_pages(dev, fwp->func_id, optimal_reclaimed_pages(), NULL); +			err = reclaim_pages(dev, fwp->func_id, +					    optimal_reclaimed_pages(), +					    &nclaimed);  			if (err) { -				mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err); +				mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", +					       err);  				return err;  			} +			if (nclaimed) +				end = jiffies + msecs_to_jiffies(MAX_RECLAIM_TIME_MSECS);  		}  		if (time_after(jiffies, end)) {  			mlx5_core_warn(dev, "FW did not return all pages. giving up...\n"); @@ -415,6 +508,7 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)  void mlx5_pagealloc_init(struct mlx5_core_dev *dev)  {  	dev->priv.page_root = RB_ROOT; +	INIT_LIST_HEAD(&dev->priv.free_list);  }  void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index f6afe7b5a67..8c9ac870ecb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -57,7 +57,7 @@ int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,  	in->arg = cpu_to_be32(arg);  	in->register_id = cpu_to_be16(reg_num);  	err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out, -			    sizeof(out) + size_out); +			    sizeof(*out) + size_out);  	if (err)  		goto ex2; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 54faf8bfcaf..8145b466822 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -74,17 +74,18 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev,  	struct mlx5_destroy_qp_mbox_out dout;  	int err; -	memset(&dout, 0, sizeof(dout)); +	memset(&out, 0, sizeof(out));  	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP);  	err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));  	if (err) { -		mlx5_core_warn(dev, "ret %d", err); +		mlx5_core_warn(dev, "ret %d\n", err);  		return err;  	}  	if (out.hdr.status) { -		pr_warn("current num of QPs 0x%x\n", atomic_read(&dev->num_qps)); +		mlx5_core_warn(dev, "current num of QPs 0x%x\n", +			       atomic_read(&dev->num_qps));  		return mlx5_cmd_status_to_err(&out.hdr);  	} @@ -95,7 +96,7 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev,  	err = radix_tree_insert(&table->tree, qp->qpn, qp);  	spin_unlock_irq(&table->lock);  	if (err) { -		mlx5_core_warn(dev, "err %d", err); +		mlx5_core_warn(dev, "err %d\n", err);  		goto err_cmd;  	}  | 
