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

Commit 90fecc14 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'mlx5-fixes-2017-07-27-V2' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux



Saeed Mahameed says:

====================
Mellanox, mlx5 fixes 2017-07-27

This series contains some misc fixes to the mlx5 driver.

Please pull and let me know if there's any problem.

V1->V2:
 - removed redundant braces

for -stable:
4.7
net/mlx5: Fix command bad flow on command entry allocation failure

4.9
net/mlx5: Consider tx_enabled in all modes on remap
net/mlx5e: Fix outer_header_zero() check size

4.10
net/mlx5: Fix mlx5_add_flow_rules call with correct num of dests

4.11
net/mlx5: Fix mlx5_ifc_mtpps_reg_bits structure size
net/mlx5e: Add field select to MTPPS register
net/mlx5e: Fix broken disable 1PPS flow
net/mlx5e: Change 1PPS out scheme
net/mlx5e: Add missing support for PTP_CLK_REQ_PPS request
net/mlx5e: Fix wrong delay calculation for overflow check scheduling
net/mlx5e: Schedule overflow check work to mlx5e workqueue

4.12
net/mlx5: Fix command completion after timeout access invalid structure
net/mlx5e: IPoIB, Modify add/remove underlay QPN flows

I hope this is not too much, but most of the patches do apply cleanly on -stable.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 996f6e12 bcec601f
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -786,6 +786,10 @@ static void cb_timeout_handler(struct work_struct *work)
	mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
}

static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
			      struct mlx5_cmd_msg *msg);

static void cmd_work_handler(struct work_struct *work)
{
	struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -796,17 +800,28 @@ static void cmd_work_handler(struct work_struct *work)
	struct semaphore *sem;
	unsigned long flags;
	bool poll_cmd = ent->polling;
	int alloc_ret;


	sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
	down(sem);
	if (!ent->page_queue) {
		ent->idx = alloc_ent(cmd);
		if (ent->idx < 0) {
		alloc_ret = alloc_ent(cmd);
		if (alloc_ret < 0) {
			mlx5_core_err(dev, "failed to allocate command entry\n");
			if (ent->callback) {
				ent->callback(-EAGAIN, ent->context);
				mlx5_free_cmd_msg(dev, ent->out);
				free_msg(dev, ent->in);
				free_cmd(ent);
			} else {
				ent->ret = -EAGAIN;
				complete(&ent->done);
			}
			up(sem);
			return;
		}
		ent->idx = alloc_ret;
	} else {
		ent->idx = cmd->max_reg_cmds;
		spin_lock_irqsave(&cmd->alloc_lock, flags);
@@ -967,7 +982,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,

	err = wait_func(dev, ent);
	if (err == -ETIMEDOUT)
		goto out_free;
		goto out;

	ds = ent->ts2 - ent->ts1;
	op = MLX5_GET(mbox_in, in->first.data, opcode);
@@ -1430,6 +1445,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
					mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
						      ent->idx);
					free_ent(cmd, ent->idx);
					free_cmd(ent);
				}
				continue;
			}
@@ -1488,6 +1504,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
				free_msg(dev, ent->in);

				err = err ? err : ent->status;
				if (!forced)
					free_cmd(ent);
				callback(err, context);
			} else {
+9 −1
Original line number Diff line number Diff line
@@ -266,6 +266,14 @@ struct mlx5e_dcbx {
};
#endif

#define MAX_PIN_NUM	8
struct mlx5e_pps {
	u8                         pin_caps[MAX_PIN_NUM];
	struct work_struct         out_work;
	u64                        start[MAX_PIN_NUM];
	u8                         enabled;
};

struct mlx5e_tstamp {
	rwlock_t                   lock;
	struct cyclecounter        cycles;
@@ -277,7 +285,7 @@ struct mlx5e_tstamp {
	struct mlx5_core_dev      *mdev;
	struct ptp_clock          *ptp;
	struct ptp_clock_info      ptp_info;
	u8                        *pps_pin_caps;
	struct mlx5e_pps           pps_info;
};

enum {
+159 −63
Original line number Diff line number Diff line
@@ -53,6 +53,15 @@ enum {
	MLX5E_EVENT_MODE_ONCE_TILL_ARM	= 0x2,
};

enum {
	MLX5E_MTPPS_FS_ENABLE			= BIT(0x0),
	MLX5E_MTPPS_FS_PATTERN			= BIT(0x2),
	MLX5E_MTPPS_FS_PIN_MODE			= BIT(0x3),
	MLX5E_MTPPS_FS_TIME_STAMP		= BIT(0x4),
	MLX5E_MTPPS_FS_OUT_PULSE_DURATION	= BIT(0x5),
	MLX5E_MTPPS_FS_ENH_OUT_PER_ADJ		= BIT(0x7),
};

void mlx5e_fill_hwstamp(struct mlx5e_tstamp *tstamp, u64 timestamp,
			struct skb_shared_hwtstamps *hwts)
{
@@ -73,17 +82,46 @@ static u64 mlx5e_read_internal_timer(const struct cyclecounter *cc)
	return mlx5_read_internal_timer(tstamp->mdev) & cc->mask;
}

static void mlx5e_pps_out(struct work_struct *work)
{
	struct mlx5e_pps *pps_info = container_of(work, struct mlx5e_pps,
						  out_work);
	struct mlx5e_tstamp *tstamp = container_of(pps_info, struct mlx5e_tstamp,
						   pps_info);
	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
	unsigned long flags;
	int i;

	for (i = 0; i < tstamp->ptp_info.n_pins; i++) {
		u64 tstart;

		write_lock_irqsave(&tstamp->lock, flags);
		tstart = tstamp->pps_info.start[i];
		tstamp->pps_info.start[i] = 0;
		write_unlock_irqrestore(&tstamp->lock, flags);
		if (!tstart)
			continue;

		MLX5_SET(mtpps_reg, in, pin, i);
		MLX5_SET64(mtpps_reg, in, time_stamp, tstart);
		MLX5_SET(mtpps_reg, in, field_select, MLX5E_MTPPS_FS_TIME_STAMP);
		mlx5_set_mtpps(tstamp->mdev, in, sizeof(in));
	}
}

static void mlx5e_timestamp_overflow(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
						   overflow_work);
	struct mlx5e_priv *priv = container_of(tstamp, struct mlx5e_priv, tstamp);
	unsigned long flags;

	write_lock_irqsave(&tstamp->lock, flags);
	timecounter_read(&tstamp->clock);
	write_unlock_irqrestore(&tstamp->lock, flags);
	schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
	queue_delayed_work(priv->wq, &tstamp->overflow_work,
			   msecs_to_jiffies(tstamp->overflow_period * 1000));
}

int mlx5e_hwstamp_set(struct mlx5e_priv *priv, struct ifreq *ifr)
@@ -213,18 +251,6 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
	int neg_adj = 0;
	struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
						  ptp_info);
	struct mlx5e_priv *priv =
		container_of(tstamp, struct mlx5e_priv, tstamp);

	if (MLX5_CAP_GEN(priv->mdev, pps_modify)) {
		u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};

		/* For future use need to add a loop for finding all 1PPS out pins */
		MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
		MLX5_SET(mtpps_reg, in, out_periodic_adjustment, delta & 0xFFFF);

		mlx5_set_mtpps(priv->mdev, in, sizeof(in));
	}

	if (delta < 0) {
		neg_adj = 1;
@@ -253,12 +279,13 @@ static int mlx5e_extts_configure(struct ptp_clock_info *ptp,
	struct mlx5e_priv *priv =
		container_of(tstamp, struct mlx5e_priv, tstamp);
	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
	u32 field_select = 0;
	u8 pin_mode = 0;
	u8 pattern = 0;
	int pin = -1;
	int err = 0;

	if (!MLX5_CAP_GEN(priv->mdev, pps) ||
	    !MLX5_CAP_GEN(priv->mdev, pps_modify))
	if (!MLX5_PPS_CAP(priv->mdev))
		return -EOPNOTSUPP;

	if (rq->extts.index >= tstamp->ptp_info.n_pins)
@@ -268,15 +295,21 @@ static int mlx5e_extts_configure(struct ptp_clock_info *ptp,
		pin = ptp_find_pin(tstamp->ptp, PTP_PF_EXTTS, rq->extts.index);
		if (pin < 0)
			return -EBUSY;
		pin_mode = MLX5E_PIN_MODE_IN;
		pattern = !!(rq->extts.flags & PTP_FALLING_EDGE);
		field_select = MLX5E_MTPPS_FS_PIN_MODE |
			       MLX5E_MTPPS_FS_PATTERN |
			       MLX5E_MTPPS_FS_ENABLE;
	} else {
		pin = rq->extts.index;
		field_select = MLX5E_MTPPS_FS_ENABLE;
	}

	if (rq->extts.flags & PTP_FALLING_EDGE)
		pattern = 1;

	MLX5_SET(mtpps_reg, in, pin, pin);
	MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_IN);
	MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
	MLX5_SET(mtpps_reg, in, pattern, pattern);
	MLX5_SET(mtpps_reg, in, enable, on);
	MLX5_SET(mtpps_reg, in, field_select, field_select);

	err = mlx5_set_mtpps(priv->mdev, in, sizeof(in));
	if (err)
@@ -295,14 +328,18 @@ static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
	struct mlx5e_priv *priv =
		container_of(tstamp, struct mlx5e_priv, tstamp);
	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
	u64 nsec_now, nsec_delta, time_stamp;
	u64 nsec_now, nsec_delta, time_stamp = 0;
	u64 cycles_now, cycles_delta;
	struct timespec64 ts;
	unsigned long flags;
	u32 field_select = 0;
	u8 pin_mode = 0;
	u8 pattern = 0;
	int pin = -1;
	int err = 0;
	s64 ns;

	if (!MLX5_CAP_GEN(priv->mdev, pps_modify))
	if (!MLX5_PPS_CAP(priv->mdev))
		return -EOPNOTSUPP;

	if (rq->perout.index >= tstamp->ptp_info.n_pins)
@@ -313,14 +350,16 @@ static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
				   rq->perout.index);
		if (pin < 0)
			return -EBUSY;
	}

		pin_mode = MLX5E_PIN_MODE_OUT;
		pattern = MLX5E_OUT_PATTERN_PERIODIC;
		ts.tv_sec = rq->perout.period.sec;
		ts.tv_nsec = rq->perout.period.nsec;
		ns = timespec64_to_ns(&ts);
	if (on)

		if ((ns >> 1) != 500000000LL)
			return -EINVAL;

		ts.tv_sec = rq->perout.start.sec;
		ts.tv_nsec = rq->perout.start.nsec;
		ns = timespec64_to_ns(&ts);
@@ -332,13 +371,39 @@ static int mlx5e_perout_configure(struct ptp_clock_info *ptp,
					 tstamp->cycles.mult);
		write_unlock_irqrestore(&tstamp->lock, flags);
		time_stamp = cycles_now + cycles_delta;
		field_select = MLX5E_MTPPS_FS_PIN_MODE |
			       MLX5E_MTPPS_FS_PATTERN |
			       MLX5E_MTPPS_FS_ENABLE |
			       MLX5E_MTPPS_FS_TIME_STAMP;
	} else {
		pin = rq->perout.index;
		field_select = MLX5E_MTPPS_FS_ENABLE;
	}

	MLX5_SET(mtpps_reg, in, pin, pin);
	MLX5_SET(mtpps_reg, in, pin_mode, MLX5E_PIN_MODE_OUT);
	MLX5_SET(mtpps_reg, in, pattern, MLX5E_OUT_PATTERN_PERIODIC);
	MLX5_SET(mtpps_reg, in, pin_mode, pin_mode);
	MLX5_SET(mtpps_reg, in, pattern, pattern);
	MLX5_SET(mtpps_reg, in, enable, on);
	MLX5_SET64(mtpps_reg, in, time_stamp, time_stamp);
	MLX5_SET(mtpps_reg, in, field_select, field_select);

	err = mlx5_set_mtpps(priv->mdev, in, sizeof(in));
	if (err)
		return err;

	return mlx5_set_mtppse(priv->mdev, pin, 0,
			       MLX5E_EVENT_MODE_REPETETIVE & on);
}

static int mlx5e_pps_configure(struct ptp_clock_info *ptp,
			       struct ptp_clock_request *rq,
			       int on)
{
	struct mlx5e_tstamp *tstamp =
		container_of(ptp, struct mlx5e_tstamp, ptp_info);

	return mlx5_set_mtpps(priv->mdev, in, sizeof(in));
	tstamp->pps_info.enabled = !!on;
	return 0;
}

static int mlx5e_ptp_enable(struct ptp_clock_info *ptp,
@@ -350,6 +415,8 @@ static int mlx5e_ptp_enable(struct ptp_clock_info *ptp,
		return mlx5e_extts_configure(ptp, rq, on);
	case PTP_CLK_REQ_PEROUT:
		return mlx5e_perout_configure(ptp, rq, on);
	case PTP_CLK_REQ_PPS:
		return mlx5e_pps_configure(ptp, rq, on);
	default:
		return -EOPNOTSUPP;
	}
@@ -395,6 +462,7 @@ static int mlx5e_init_pin_config(struct mlx5e_tstamp *tstamp)
		return -ENOMEM;
	tstamp->ptp_info.enable = mlx5e_ptp_enable;
	tstamp->ptp_info.verify = mlx5e_ptp_verify;
	tstamp->ptp_info.pps = 1;

	for (i = 0; i < tstamp->ptp_info.n_pins; i++) {
		snprintf(tstamp->ptp_info.pin_config[i].name,
@@ -422,22 +490,56 @@ static void mlx5e_get_pps_caps(struct mlx5e_priv *priv,
	tstamp->ptp_info.n_per_out = MLX5_GET(mtpps_reg, out,
					      cap_max_num_of_pps_out_pins);

	tstamp->pps_pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
	tstamp->pps_pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
	tstamp->pps_pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
	tstamp->pps_pin_caps[3] = MLX5_GET(mtpps_reg, out, cap_pin_3_mode);
	tstamp->pps_pin_caps[4] = MLX5_GET(mtpps_reg, out, cap_pin_4_mode);
	tstamp->pps_pin_caps[5] = MLX5_GET(mtpps_reg, out, cap_pin_5_mode);
	tstamp->pps_pin_caps[6] = MLX5_GET(mtpps_reg, out, cap_pin_6_mode);
	tstamp->pps_pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
	tstamp->pps_info.pin_caps[0] = MLX5_GET(mtpps_reg, out, cap_pin_0_mode);
	tstamp->pps_info.pin_caps[1] = MLX5_GET(mtpps_reg, out, cap_pin_1_mode);
	tstamp->pps_info.pin_caps[2] = MLX5_GET(mtpps_reg, out, cap_pin_2_mode);
	tstamp->pps_info.pin_caps[3] = MLX5_GET(mtpps_reg, out, cap_pin_3_mode);
	tstamp->pps_info.pin_caps[4] = MLX5_GET(mtpps_reg, out, cap_pin_4_mode);
	tstamp->pps_info.pin_caps[5] = MLX5_GET(mtpps_reg, out, cap_pin_5_mode);
	tstamp->pps_info.pin_caps[6] = MLX5_GET(mtpps_reg, out, cap_pin_6_mode);
	tstamp->pps_info.pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
}

void mlx5e_pps_event_handler(struct mlx5e_priv *priv,
			     struct ptp_clock_event *event)
{
	struct net_device *netdev = priv->netdev;
	struct mlx5e_tstamp *tstamp = &priv->tstamp;
	struct timespec64 ts;
	u64 nsec_now, nsec_delta;
	u64 cycles_now, cycles_delta;
	int pin = event->index;
	s64 ns;
	unsigned long flags;

	switch (tstamp->ptp_info.pin_config[pin].func) {
	case PTP_PF_EXTTS:
		if (tstamp->pps_info.enabled) {
			event->type = PTP_CLOCK_PPSUSR;
			event->pps_times.ts_real = ns_to_timespec64(event->timestamp);
		} else {
			event->type = PTP_CLOCK_EXTTS;
		}
		ptp_clock_event(tstamp->ptp, event);
		break;
	case PTP_PF_PEROUT:
		mlx5e_ptp_gettime(&tstamp->ptp_info, &ts);
		cycles_now = mlx5_read_internal_timer(tstamp->mdev);
		ts.tv_sec += 1;
		ts.tv_nsec = 0;
		ns = timespec64_to_ns(&ts);
		write_lock_irqsave(&tstamp->lock, flags);
		nsec_now = timecounter_cyc2time(&tstamp->clock, cycles_now);
		nsec_delta = ns - nsec_now;
		cycles_delta = div64_u64(nsec_delta << tstamp->cycles.shift,
					 tstamp->cycles.mult);
		tstamp->pps_info.start[pin] = cycles_now + cycles_delta;
		queue_work(priv->wq, &tstamp->pps_info.out_work);
		write_unlock_irqrestore(&tstamp->lock, flags);
		break;
	default:
		netdev_err(netdev, "%s: Unhandled event\n", __func__);
	}
}

void mlx5e_timestamp_init(struct mlx5e_priv *priv)
@@ -473,9 +575,10 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
	do_div(ns, NSEC_PER_SEC / 2 / HZ);
	tstamp->overflow_period = ns;

	INIT_WORK(&tstamp->pps_info.out_work, mlx5e_pps_out);
	INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
	if (tstamp->overflow_period)
		schedule_delayed_work(&tstamp->overflow_work, 0);
		queue_delayed_work(priv->wq, &tstamp->overflow_work, 0);
	else
		mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");

@@ -484,16 +587,10 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
	snprintf(tstamp->ptp_info.name, 16, "mlx5 ptp");

	/* Initialize 1PPS data structures */
#define MAX_PIN_NUM	8
	tstamp->pps_pin_caps = kzalloc(sizeof(u8) * MAX_PIN_NUM, GFP_KERNEL);
	if (tstamp->pps_pin_caps) {
		if (MLX5_CAP_GEN(priv->mdev, pps))
	if (MLX5_PPS_CAP(priv->mdev))
		mlx5e_get_pps_caps(priv, tstamp);
	if (tstamp->ptp_info.n_pins)
		mlx5e_init_pin_config(tstamp);
	} else {
		mlx5_core_warn(priv->mdev, "1PPS initialization failed\n");
	}

	tstamp->ptp = ptp_clock_register(&tstamp->ptp_info,
					 &priv->mdev->pdev->dev);
@@ -516,8 +613,7 @@ void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv)
		priv->tstamp.ptp = NULL;
	}

	kfree(tstamp->pps_pin_caps);
	kfree(tstamp->ptp_info.pin_config);

	cancel_work_sync(&tstamp->pps_info.out_work);
	cancel_delayed_work_sync(&tstamp->overflow_work);
	kfree(tstamp->ptp_info.pin_config);
}
+2 −2
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ static void add_rule_to_list(struct mlx5e_priv *priv,

static bool outer_header_zero(u32 *match_criteria)
{
	int size = MLX5_ST_SZ_BYTES(fte_match_param);
	int size = MLX5_FLD_SZ_BYTES(fte_match_param, outer_headers);
	char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
					     outer_headers);

@@ -320,7 +320,7 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,

	spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria));
	flow_act.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
	rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, 1);
	rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, dst ? 1 : 0);
	if (IS_ERR(rule)) {
		err = PTR_ERR(rule);
		netdev_err(priv->netdev, "%s: failed to add ethtool steering rule: %d\n",
+0 −1
Original line number Diff line number Diff line
@@ -377,7 +377,6 @@ static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
		break;
	case MLX5_DEV_EVENT_PPS:
		eqe = (struct mlx5_eqe *)param;
		ptp_event.type = PTP_CLOCK_EXTTS;
		ptp_event.index = eqe->data.pps.pin;
		ptp_event.timestamp =
			timecounter_cyc2time(&priv->tstamp.clock,
Loading