Netdev List
 help / color / mirror / Atom feed
* [PATCH v2 net] net: dsa: mv88e6xxx: prevent interrupt storm caused by mv88e6390x_port_set_cmode
From: Heiner Kallweit @ 2019-02-28  6:39 UTC (permalink / raw)
  To: Vivien Didelot, Andrew Lunn, Florian Fainelli, David Miller
  Cc: netdev@vger.kernel.org

When debugging another issue I faced an interrupt storm in this
driver (88E6390, port 9 in SGMII mode), consisting of alternating
link-up / link-down interrupts. Analysis showed that the driver
wanted to set a cmode that was set already. But so far
mv88e6390x_port_set_cmode() doesn't check this and powers down
SERDES, what causes the link to break, and eventually results in
the described interrupt storm.

Fix this by checking whether the cmode actually changes. We want
that the very first call to mv88e6390x_port_set_cmode() always
configures the registers, therefore initialize port.cmode with
a value that is different from any supported cmode value.
We have to take care that we only init the ports cmode once
chip->info->num_ports is set.

v2:
- add small helper and init the number of actual ports only

Fixes: 364e9d7776a3 ("net: dsa: mv88e6xxx: Power on/off SERDES on cmode change")
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 10 ++++++++++
 drivers/net/dsa/mv88e6xxx/port.c |  4 ++++
 drivers/net/dsa/mv88e6xxx/port.h |  1 +
 3 files changed, 15 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index a3a2eb985..f1f228af0 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4620,6 +4620,14 @@ static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
 	return 0;
 }
 
+static void mv88e6xxx_ports_cmode_init(struct mv88e6xxx_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
+		chip->ports[i].cmode = MV88E6XXX_PORT_STS_CMODE_INVALID;
+}
+
 static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
 							int port)
 {
@@ -4656,6 +4664,8 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
 	if (err)
 		goto free;
 
+	mv88e6xxx_ports_cmode_init(chip);
+
 	mutex_lock(&chip->reg_lock);
 	err = mv88e6xxx_switch_reset(chip);
 	mutex_unlock(&chip->reg_lock);
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index ee7029f4e..e12e0bdfc 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -398,6 +398,10 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
 		cmode = 0;
 	}
 
+	/* cmode doesn't change, nothing to do for us */
+	if (cmode == chip->ports[port].cmode)
+		return 0;
+
 	lane = mv88e6390x_serdes_get_lane(chip, port);
 	if (lane < 0)
 		return lane;
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index e583641de..4aadf321e 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -52,6 +52,7 @@
 #define MV88E6185_PORT_STS_CMODE_1000BASE_X	0x0005
 #define MV88E6185_PORT_STS_CMODE_PHY		0x0006
 #define MV88E6185_PORT_STS_CMODE_DISABLED	0x0007
+#define MV88E6XXX_PORT_STS_CMODE_INVALID	0xff
 
 /* Offset 0x01: MAC (or PCS or Physical) Control Register */
 #define MV88E6XXX_PORT_MAC_CTL				0x01
-- 
2.21.0


^ permalink raw reply related

* Re: [PATCH v2] xfrm: policy: Fix possible user after free in __xfrm_policy_unlink
From: Herbert Xu @ 2019-02-28  6:41 UTC (permalink / raw)
  To: Yue Haibing; +Cc: steffen.klassert, davem, linux-kernel, netdev
In-Reply-To: <20190228063801.27200-1-yuehaibing@huawei.com>

On Thu, Feb 28, 2019 at 02:38:01PM +0800, Yue Haibing wrote:
>
> diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
> index a131f9f..aaa45c9 100644
> --- a/net/xfrm/xfrm_user.c
> +++ b/net/xfrm/xfrm_user.c
> @@ -1424,7 +1424,8 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
>  	ret = verify_policy_dir(p->dir);
>  	if (ret)
>  		return ret;
> -	if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
> +	if (p->index && (((p->index & XFRM_POLICY_MAX) != p->dir) ||
> +			 (xfrm_policy_id2dir(p->index) >= XFRM_POLICY_MAX)))

Please just check 

	xfrm_policy_id2dir(p->index) != p->dir

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCH v2] xfrm: policy: Fix possible user after free in __xfrm_policy_unlink
From: YueHaibing @ 2019-02-28  6:48 UTC (permalink / raw)
  To: Herbert Xu; +Cc: steffen.klassert, davem, linux-kernel, netdev
In-Reply-To: <20190228064106.v4fe5b2ij3gbodxk@gondor.apana.org.au>


On 2019/2/28 14:41, Herbert Xu wrote:
> On Thu, Feb 28, 2019 at 02:38:01PM +0800, Yue Haibing wrote:
>>
>> diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
>> index a131f9f..aaa45c9 100644
>> --- a/net/xfrm/xfrm_user.c
>> +++ b/net/xfrm/xfrm_user.c
>> @@ -1424,7 +1424,8 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
>>  	ret = verify_policy_dir(p->dir);
>>  	if (ret)
>>  		return ret;
>> -	if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
>> +	if (p->index && (((p->index & XFRM_POLICY_MAX) != p->dir) ||
>> +			 (xfrm_policy_id2dir(p->index) >= XFRM_POLICY_MAX)))
> 
> Please just check 
> 
> 	xfrm_policy_id2dir(p->index) != p->dir


Oh, it indeed can be merged, Thanks!

> 
> Thanks,
> 


^ permalink raw reply

* [PATCH v3] xfrm: policy: Fix possible user after free in __xfrm_policy_unlink
From: Yue Haibing @ 2019-02-28  6:56 UTC (permalink / raw)
  To: steffen.klassert, herbert, davem; +Cc: linux-kernel, netdev, YueHaibing

From: YueHaibing <yuehaibing@huawei.com>

UBSAN report this:

UBSAN: Undefined behaviour in net/xfrm/xfrm_policy.c:1289:24
index 6 is out of range for type 'unsigned int [6]'
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.4.162-514.55.6.9.x86_64+ #13
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
 0000000000000000 1466cf39b41b23c9 ffff8801f6b07a58 ffffffff81cb35f4
 0000000041b58ab3 ffffffff83230f9c ffffffff81cb34e0 ffff8801f6b07a80
 ffff8801f6b07a20 1466cf39b41b23c9 ffffffff851706e0 ffff8801f6b07ae8
Call Trace:
 <IRQ>  [<ffffffff81cb35f4>] __dump_stack lib/dump_stack.c:15 [inline]
 <IRQ>  [<ffffffff81cb35f4>] dump_stack+0x114/0x1a0 lib/dump_stack.c:51
 [<ffffffff81d94225>] ubsan_epilogue+0x12/0x8f lib/ubsan.c:164
 [<ffffffff81d954db>] __ubsan_handle_out_of_bounds+0x16e/0x1b2 lib/ubsan.c:382
 [<ffffffff82a25acd>] __xfrm_policy_unlink+0x3dd/0x5b0 net/xfrm/xfrm_policy.c:1289
 [<ffffffff82a2e572>] xfrm_policy_delete+0x52/0xb0 net/xfrm/xfrm_policy.c:1309
 [<ffffffff82a3319b>] xfrm_policy_timer+0x30b/0x590 net/xfrm/xfrm_policy.c:243
 [<ffffffff813d3927>] call_timer_fn+0x237/0x990 kernel/time/timer.c:1144
 [<ffffffff813d8e7e>] __run_timers kernel/time/timer.c:1218 [inline]
 [<ffffffff813d8e7e>] run_timer_softirq+0x6ce/0xb80 kernel/time/timer.c:1401
 [<ffffffff8120d6f9>] __do_softirq+0x299/0xe10 kernel/softirq.c:273
 [<ffffffff8120e676>] invoke_softirq kernel/softirq.c:350 [inline]
 [<ffffffff8120e676>] irq_exit+0x216/0x2c0 kernel/softirq.c:391
 [<ffffffff82c5edab>] exiting_irq arch/x86/include/asm/apic.h:652 [inline]
 [<ffffffff82c5edab>] smp_apic_timer_interrupt+0x8b/0xc0 arch/x86/kernel/apic/apic.c:926
 [<ffffffff82c5c985>] apic_timer_interrupt+0xa5/0xb0 arch/x86/entry/entry_64.S:735
 <EOI>  [<ffffffff81188096>] ? native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:52
 [<ffffffff810834d7>] arch_safe_halt arch/x86/include/asm/paravirt.h:111 [inline]
 [<ffffffff810834d7>] default_idle+0x27/0x430 arch/x86/kernel/process.c:446
 [<ffffffff81085f05>] arch_cpu_idle+0x15/0x20 arch/x86/kernel/process.c:437
 [<ffffffff8132abc3>] default_idle_call+0x53/0x90 kernel/sched/idle.c:92
 [<ffffffff8132b32d>] cpuidle_idle_call kernel/sched/idle.c:156 [inline]
 [<ffffffff8132b32d>] cpu_idle_loop kernel/sched/idle.c:251 [inline]
 [<ffffffff8132b32d>] cpu_startup_entry+0x60d/0x9a0 kernel/sched/idle.c:299
 [<ffffffff8113e119>] start_secondary+0x3c9/0x560 arch/x86/kernel/smpboot.c:245

The issue is triggered as this:

xfrm_add_policy
    -->verify_newpolicy_info  //check the index provided by user with XFRM_POLICY_MAX
			      //In my case, the index is 0x6E6BB6, so it pass the check.
    -->xfrm_policy_construct  //copy the user's policy and set xfrm_policy_timer
    -->xfrm_policy_insert
	--> __xfrm_policy_link //use the orgin dir, in my case is 2
	--> xfrm_gen_index   //generate policy index, there is 0x6E6BB6

then xfrm_policy_timer be fired

xfrm_policy_timer
   --> xfrm_policy_id2dir  //get dir from (policy index & 7), in my case is 6
   --> xfrm_policy_delete
      --> __xfrm_policy_unlink //access policy_count[dir], trigger out of range access

Add xfrm_policy_id2dir check in verify_newpolicy_info, make sure the computed dir is
valid, to fix the issue.

Reported-by: Hulk Robot <hulkci@huawei.com>
Fixes: e682adf021be ("xfrm: Try to honor policy index if it's supplied by user")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
v3: fold the check
v2: fix index check in verify_newpolicy_info
---
 net/xfrm/xfrm_user.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a131f9f..8d4d52f 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1424,7 +1424,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
 	ret = verify_policy_dir(p->dir);
 	if (ret)
 		return ret;
-	if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
+	if (p->index && (xfrm_policy_id2dir(p->index) != p->dir))
 		return -EINVAL;
 
 	return 0;
-- 
2.7.0



^ permalink raw reply related

* [PATCH 0/2] can: flexcan: add CANFD BRS and ISO FD support
From: Joakim Zhang @ 2019-02-28  6:57 UTC (permalink / raw)
  To: mkl@pengutronix.de, linux-can@vger.kernel.org
  Cc: dl-linux-imx, wg@grandegger.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Joakim Zhang

Hi Marc,

This patch set intends to enable CANFD bitrate switch and ISO FD mode
support.

You may need to firstly review the patch set([PATCH 0/3] can: flexcan:
add imx8qm support).

I noticed that you have been reviewing my patches recetnly, please feel
free to let me know if you want me to rebase the patch about CANFD and
that may easy your patch review.

Thanks a lot.

Joakim Zhang.

Dong Aisheng (1):
  can: flexcan: add CANFD BRS support and improve bittiming setting

Joakim Zhang (1):
  can: flexcan: add ISO CAN FD feature support

 drivers/net/can/flexcan.c | 116 ++++++++++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 22 deletions(-)

-- 
2.17.1


^ permalink raw reply

* [PATCH 2/2] can: flexcan: add ISO CAN FD feature support
From: Joakim Zhang @ 2019-02-28  6:57 UTC (permalink / raw)
  To: mkl@pengutronix.de, linux-can@vger.kernel.org
  Cc: dl-linux-imx, wg@grandegger.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Joakim Zhang
In-Reply-To: <20190228065506.3488-1-qiangqing.zhang@nxp.com>

ISO CAN FD is introduced to increase the failture detection capability
than non-ISO CAN FD. The non-ISO CAN FD is still supported by FlexCAN so
that it can be used mainly during an intermediate phase, for evaluation
and development purposes.

Therefore, it is strongly recommended to configure FlexCAN to the ISO
CAN FD protocol by setting the ISOCANFDEN field in the CTRL2 register.

Test Command:
ISO FD MODE:
ip link set can0 type can bitrate 1000000 dbitrate 4000000 fd on
fd-non-iso off

non-ISO FD MODE:
ip link set can0 type can bitrate 1000000 dbitrate 4000000 fd on
fd-non-iso on

NOTE: if you only set "fd on", driver will use ISO FD MODE by default.

Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
 drivers/net/can/flexcan.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 4ba35f9eb515..25e077a68db9 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -91,6 +91,7 @@
 #define FLEXCAN_CTRL2_MRP		BIT(18)
 #define FLEXCAN_CTRL2_RRS		BIT(17)
 #define FLEXCAN_CTRL2_EACEN		BIT(16)
+#define FLEXCAN_CTRL2_ISOCANFDEN	BIT(12)
 
 /* FLEXCAN memory error control register (MECR) bits */
 #define FLEXCAN_MECR_ECRWRDIS		BIT(31)
@@ -1227,6 +1228,12 @@ static int flexcan_chip_start(struct net_device *dev)
 		priv->write(reg_fdctrl, &regs->fdctrl);
 		reg_mcr = priv->read(&regs->mcr);
 		priv->write(reg_mcr | FLEXCAN_MCR_FDEN, &regs->mcr);
+
+		reg_ctrl2 = flexcan_read(&regs->ctrl2);
+		if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
+			flexcan_write(reg_ctrl2 | FLEXCAN_CTRL2_ISOCANFDEN, &regs->ctrl2);
+		else
+			flexcan_write(reg_ctrl2 & ~FLEXCAN_CTRL2_ISOCANFDEN, &regs->ctrl2);
 	}
 
 	if ((priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) &&
@@ -1729,7 +1736,7 @@ static int flexcan_probe(struct platform_device *pdev)
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
 		if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
 			priv->offload.is_canfd = true;
-			priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+			priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO;
 			priv->can.bittiming_const = &flexcan_fd_bittiming_const;
 			priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
 		} else {
-- 
2.17.1


^ permalink raw reply related

* [PATCH 1/2] can: flexcan: add CANFD BRS support and improve bittiming setting
From: Joakim Zhang @ 2019-02-28  6:57 UTC (permalink / raw)
  To: mkl@pengutronix.de, linux-can@vger.kernel.org
  Cc: dl-linux-imx, wg@grandegger.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Aisheng Dong, Joakim Zhang
In-Reply-To: <20190228065506.3488-1-qiangqing.zhang@nxp.com>

From: Dong Aisheng <aisheng.dong@nxp.com>

This patch intends to add CANFD BitRate Switch(BRS) support. Bit timing
must be set in CBT register other than CTRL1 register when CANFD
supports BRS, it will extend the range of all CAN bit timing variables
(PRESDIV, PROPSEG, PSEG1, PSEG2 and RJW), which will improve the bit
timing accuracy.

Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 drivers/net/can/flexcan.c | 107 ++++++++++++++++++++++++++++++--------
 1 file changed, 86 insertions(+), 21 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f997f07b6cf9..4ba35f9eb515 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -137,6 +137,14 @@
 	 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
 	 FLEXCAN_ESR_WAK_INT)
 
+/* FLEXCAN Bit Timing register (CBT) bits */
+#define FLEXCAN_CBT_BTF                 BIT(31)
+#define FLEXCAN_CBT_EPRESDIV(x)         (((x) & 0x3ff) << 21)
+#define FLEXCAN_CBT_ERJW(x)             (((x) & 0x1f) << 16)
+#define FLEXCAN_CBT_EPROPSEG(x)         (((x) & 0x3f) << 10)
+#define FLEXCAN_CBT_EPSEG1(x)           (((x) & 0x1f) << 5)
+#define FLEXCAN_CBT_EPSEG2(x)           ((x) & 0x1f)
+
 /* FLEXCAN FD control register (FDCTRL) bits */
 #define FLEXCAN_FDCTRL_MBDSR3(x)	(((x) & 0x3) << 25)
 #define FLEXCAN_FDCTRL_MBDSR2(x)	(((x) & 0x3) << 22)
@@ -243,7 +251,8 @@ struct flexcan_regs {
 	u32 crcr;		/* 0x44 */
 	u32 rxfgmask;		/* 0x48 */
 	u32 rxfir;		/* 0x4c */
-	u32 _reserved3[12];	/* 0x50 */
+	u32 cbt;                /* 0x50 */
+	u32 _reserved3[11];     /* 0x54 */
 	u8 mb[2][512];		/* 0x80 */
 	/* FIFO-mode:
 	 *			MB
@@ -363,6 +372,18 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
 	.brp_inc = 1,
 };
 
+static const struct can_bittiming_const flexcan_fd_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 2,
+	.tseg1_max = 64,
+	.tseg2_min = 1,
+	.tseg2_max = 32,
+	.sjw_max = 32,
+	.brp_min = 1,
+	.brp_max = 1024,
+	.brp_inc = 1,
+};
+
 static const struct can_bittiming_const flexcan_fd_data_bittiming_const = {
 	.name = DRV_NAME,
 	.tseg1_min = 1,
@@ -653,9 +674,13 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
 	if (cf->can_id & CAN_RTR_FLAG)
 		ctrl |= FLEXCAN_MB_CNT_RTR;
 
-	if (can_is_canfd_skb(skb))
+	if (can_is_canfd_skb(skb)) {
 		ctrl |= FLEXCAN_MB_CNT_EDL;
 
+		if (cf->flags & CANFD_BRS)
+			ctrl |= FLEXCAN_MB_CNT_BRS;
+	}
+
 	for (i = 0; i < cf->len; i += sizeof(u32)) {
 		data = be32_to_cpup((__be32 *)&cf->data[i]);
 		priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
@@ -834,6 +859,9 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
 
 	if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
 		cf->len = can_dlc2len((reg_ctrl >> 16) & 0x0F);
+
+		if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+			cf->flags |= CANFD_BRS;
 	} else {
 		cf->len = get_can_dlc((reg_ctrl >> 16) & 0x0F);
 
@@ -1013,21 +1041,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
 	u32 reg;
 
 	reg = priv->read(&regs->ctrl);
-	reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
-		 FLEXCAN_CTRL_RJW(0x3) |
-		 FLEXCAN_CTRL_PSEG1(0x7) |
-		 FLEXCAN_CTRL_PSEG2(0x7) |
-		 FLEXCAN_CTRL_PROPSEG(0x7) |
-		 FLEXCAN_CTRL_LPB |
-		 FLEXCAN_CTRL_SMP |
-		 FLEXCAN_CTRL_LOM);
-
-	reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
-		FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
-		FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
-		FLEXCAN_CTRL_RJW(bt->sjw - 1) |
-		FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
-
+	reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM);
 	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
 		reg |= FLEXCAN_CTRL_LPB;
 	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
@@ -1039,17 +1053,60 @@ static void flexcan_set_bittiming(struct net_device *dev)
 	priv->write(reg, &regs->ctrl);
 
 	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+		reg = FLEXCAN_CBT_EPRESDIV(bt->brp - 1) |
+			FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) |
+			FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1) |
+			FLEXCAN_CBT_ERJW(bt->sjw - 1) |
+			FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) |
+			FLEXCAN_CBT_BTF;
+		priv->write(reg, &regs->cbt);
+
+		netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+			   bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+			   bt->sjw - 1, bt->prop_seg - 1);
+
 		reg = FLEXCAN_FDCBT_FPRESDIV(dbt->brp - 1) |
 			FLEXCAN_FDCBT_FPSEG1(dbt->phase_seg1 - 1) |
 			FLEXCAN_FDCBT_FPSEG2(dbt->phase_seg2 - 1) |
 			FLEXCAN_FDCBT_FRJW(dbt->sjw - 1) |
 			FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg);
 		priv->write(reg, &regs->fdcbt);
-	}
 
-	/* print chip status */
-	netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
-		   priv->read(&regs->mcr), priv->read(&regs->ctrl));
+		if (bt->brp != dbt->brp)
+			netdev_warn(dev, "PRESDIV not the same, may risk transfer errors\n");
+
+		netdev_dbg(dev, "fdbt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+			   dbt->brp - 1, dbt->phase_seg1 - 1, dbt->phase_seg2 - 1,
+			   dbt->sjw - 1, dbt->prop_seg);
+
+		netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n",
+			   __func__, priv->read(&regs->mcr),
+			   priv->read(&regs->ctrl),
+			   priv->read(&regs->cbt),
+			   priv->read(&regs->fdcbt));
+	} else {
+		reg = priv->read(&regs->ctrl);
+		reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+			 FLEXCAN_CTRL_RJW(0x3) |
+			 FLEXCAN_CTRL_PSEG1(0x7) |
+			 FLEXCAN_CTRL_PSEG2(0x7) |
+			 FLEXCAN_CTRL_PROPSEG(0x7));
+
+		reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+			FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+			FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+			FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+			FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+		priv->write(reg, &regs->ctrl);
+
+		netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+			   bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+			   bt->sjw - 1, bt->prop_seg - 1);
+
+		/* print chip status */
+		netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+			   priv->read(&regs->mcr), priv->read(&regs->ctrl));
+	}
 }
 
 /* flexcan_chip_start
@@ -1172,6 +1229,13 @@ static int flexcan_chip_start(struct net_device *dev)
 		priv->write(reg_mcr | FLEXCAN_MCR_FDEN, &regs->mcr);
 	}
 
+	if ((priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) &&
+	    !(priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
+		netdev_err(dev, "fd mode must be enabled\n");
+		err = -EOPNOTSUPP;
+		goto out_chip_disable;
+	}
+
 	if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
 		reg_ctrl2 = priv->read(&regs->ctrl2);
 		reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS;
@@ -1666,6 +1730,7 @@ static int flexcan_probe(struct platform_device *pdev)
 		if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
 			priv->offload.is_canfd = true;
 			priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+			priv->can.bittiming_const = &flexcan_fd_bittiming_const;
 			priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
 		} else {
 			dev_err(&pdev->dev, "canfd mode can't work on fifo mode\n");
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 00/14] mlxsw: spectrum_acl: Split rehash work into chunks
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel

Jiri says:

When rehash happens on a vregion with many rules and they are being
migrated, it might take significant time to finish the job. During that
time vregion->lock is taken which prevents rules from being
added/deleted from the vregion.

Aim of this patchset is to allow to interrupt migration of rules during
rehash, reschedule and give chance for rules to be added/deleted. Then
continue migration in another execution of scheduled work.

Jiri Pirko (14):
  mlxsw: spectrum_acl: Push rehash dw struct into rehash sub-struct
  mlxsw: spectrum_acl: Don't migrate already migrated entry
  mlxsw: spectrum_acl: Introduce new rehash context struct and save
    hint_priv there
  mlxsw: spectrum_acl: Push rehash start/end code into separate
    functions
  mlxsw: spectrum_acl: Push code start/end from
    mlxsw_sp_acl_tcam_vregion_migrate()
  mlxsw: spectrum_acl: assign vregion->region by the newly created
    region
  mlxsw: spectrum_acl: assign vchunk->chunk by the newly created chunk
  mlxsw: spectrum_acl: Rename variables in
    mlxsw_sp_acl_tcam_ventry_migrate()
  mlxsw: spectrum_acl: Put this_is_rollback to rehash context struct
  mlxsw: spectrum_acl: Put vchunk migrate start/end code into separate
    functions
  mlxsw: spectrum_acl: Do rollback as another call to
    mlxsw_sp_acl_tcam_vchunk_migrate_all()
  mlxsw: spectrum_acl: Allow to interrupt/continue rehash work
  mlxsw: spectrum_acl: Remember where to continue rehash migration
  mlxsw: spectrum_acl: Make mlxsw_sp_acl_tcam_vregion_rehash() return
    void

 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 411 ++++++++++++------
 1 file changed, 286 insertions(+), 125 deletions(-)

-- 
2.20.1


^ permalink raw reply

* Re: [PATCH] tools/libbpf: signedness bug in btf_dedup_ref_type()
From: Yonghong Song @ 2019-02-28  6:58 UTC (permalink / raw)
  To: Dan Carpenter, Alexei Starovoitov, Andrii Nakryiko
  Cc: Daniel Borkmann, Martin Lau, Song Liu, netdev@vger.kernel.org,
	kernel-janitors@vger.kernel.org
In-Reply-To: <20190228054627.GC3253@kadam>



On 2/27/19 9:46 PM, Dan Carpenter wrote:
> The "ref_type_id" variable needs to be signed for the error handling
> to work.
> 
> Fixes: d5caef5b5655 ("btf: add BTF types deduplication algorithm")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> This goes through the BPF tree probably, although it does apply to
> net-next.
> 
>   tools/lib/bpf/btf.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index 68b50e9bbde1..8faed5386124 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -2326,7 +2326,8 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
>   	struct btf_type *t, *cand;
>   	/* if we don't find equivalent type, then we are representative type */
>   	__u32 new_id = type_id;
> -	__u32 h, ref_type_id;
> +	__u32 h; > +	int ref_type_id;

nit. Maybe you can change to
	int ref_type_id;
	__u32 h;
to maintain kernel declaration reverse christmas tree convention?

>   
>   	if (d->map[type_id] == BTF_IN_PROGRESS_ID)
>   		return -ELOOP;
> 

^ permalink raw reply

* [PATCH net-next 02/14] mlxsw: spectrum_acl: Don't migrate already migrated entry
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Check if the entry is already in a chunk where we want it to be. In that
case, skip migration. This is preparation for "per parts" migration
where this situation may occur.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index e2699373dfa7..30131ea2e324 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1174,6 +1174,10 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp,
 {
 	struct mlxsw_sp_acl_tcam_entry *entry2;
 
+	/* First check if the entry is not already where we want it to be. */
+	if (ventry->entry->chunk == chunk2)
+		return 0;
+
 	entry2 = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk2);
 	if (IS_ERR(entry2))
 		return PTR_ERR(entry2);
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 01/14] mlxsw: spectrum_acl: Push rehash dw struct into rehash sub-struct
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

More rehash related fields are going to come. Push "dw" into sub-struct
that will accommodate the others as well.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c  | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index c9d9cded1724..e2699373dfa7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -192,7 +192,9 @@ struct mlxsw_sp_acl_tcam_vregion {
 	struct mlxsw_afk_key_info *key_info;
 	struct mlxsw_sp_acl_tcam *tcam;
 	struct mlxsw_sp_acl_tcam_vgroup *vgroup;
-	struct delayed_work rehash_dw;
+	struct {
+		struct delayed_work dw;
+	} rehash;
 	struct mlxsw_sp *mlxsw_sp;
 	bool failed_rollback; /* Indicates failed rollback during migration */
 	unsigned int ref_count;
@@ -718,7 +720,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion
 
 	if (!interval)
 		return;
-	mlxsw_core_schedule_dw(&vregion->rehash_dw,
+	mlxsw_core_schedule_dw(&vregion->rehash.dw,
 			       msecs_to_jiffies(interval));
 }
 
@@ -730,7 +732,7 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
 {
 	struct mlxsw_sp_acl_tcam_vregion *vregion =
 		container_of(work, struct mlxsw_sp_acl_tcam_vregion,
-			     rehash_dw.work);
+			     rehash.dw.work);
 
 	mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion);
 	mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
@@ -778,7 +780,7 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp,
 
 	if (vgroup->vregion_rehash_enabled && ops->region_rehash_hints_get) {
 		/* Create the delayed work for vregion periodic rehash */
-		INIT_DELAYED_WORK(&vregion->rehash_dw,
+		INIT_DELAYED_WORK(&vregion->rehash.dw,
 				  mlxsw_sp_acl_tcam_vregion_rehash_work);
 		mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
 		mutex_lock(&tcam->lock);
@@ -809,7 +811,7 @@ mlxsw_sp_acl_tcam_vregion_destroy(struct mlxsw_sp *mlxsw_sp,
 		mutex_lock(&tcam->lock);
 		list_del(&vregion->tlist);
 		mutex_unlock(&tcam->lock);
-		cancel_delayed_work_sync(&vregion->rehash_dw);
+		cancel_delayed_work_sync(&vregion->rehash.dw);
 	}
 	mlxsw_sp_acl_tcam_vgroup_vregion_detach(mlxsw_sp, vregion);
 	if (vregion->region2)
@@ -847,9 +849,9 @@ int mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp,
 	mutex_lock(&tcam->lock);
 	list_for_each_entry(vregion, &tcam->vregion_list, tlist) {
 		if (val)
-			mlxsw_core_schedule_dw(&vregion->rehash_dw, 0);
+			mlxsw_core_schedule_dw(&vregion->rehash.dw, 0);
 		else
-			cancel_delayed_work_sync(&vregion->rehash_dw);
+			cancel_delayed_work_sync(&vregion->rehash.dw);
 	}
 	mutex_unlock(&tcam->lock);
 	return 0;
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 04/14] mlxsw: spectrum_acl: Push rehash start/end code into separate functions
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

In preparations for interrupt/continue of rehash work, put the code at
the beginning/end of the rehash function into separate functions.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 41 +++++++++++++++----
 1 file changed, 32 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index ae1101c17f2c..fa204003bc84 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1334,26 +1334,50 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 }
 
 static int
-mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
-				 struct mlxsw_sp_acl_tcam_vregion *vregion)
+mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
+				       struct mlxsw_sp_acl_tcam_vregion *vregion,
+				       struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
-	struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
 	void *hints_priv;
-	int err;
 
 	trace_mlxsw_sp_acl_tcam_vregion_rehash(mlxsw_sp, vregion);
 	if (vregion->failed_rollback)
 		return -EBUSY;
 
 	hints_priv = ops->region_rehash_hints_get(vregion->region->priv);
-	if (IS_ERR(hints_priv)) {
-		err = PTR_ERR(hints_priv);
+	if (IS_ERR(hints_priv))
+		return PTR_ERR(hints_priv);
+
+	ctx->hints_priv = hints_priv;
+
+	return 0;
+}
+
+static void
+mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp,
+				     struct mlxsw_sp_acl_tcam_vregion *vregion,
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+{
+	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
+
+	ops->region_rehash_hints_put(ctx->hints_priv);
+	ctx->hints_priv = NULL;
+}
+
+static int
+mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
+				 struct mlxsw_sp_acl_tcam_vregion *vregion)
+{
+	struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
+	int err;
+
+	err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp, vregion, ctx);
+	if (err) {
 		if (err != -EAGAIN)
 			dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n");
 		return err;
 	}
-	ctx->hints_priv = hints_priv;
 
 	err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx);
 	if (err) {
@@ -1365,8 +1389,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 		}
 	}
 
-	ops->region_rehash_hints_put(ctx->hints_priv);
-	ctx->hints_priv = NULL;
+	mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx);
 	return err;
 }
 
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 08/14] mlxsw: spectrum_acl: Rename variables in mlxsw_sp_acl_tcam_ventry_migrate()
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Remove some of variables in function mlxsw_sp_acl_tcam_ventry_migrate()
so the names are aligned with the rest of the code.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c    | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 6a50266b6809..0bc04016c6d0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1175,19 +1175,19 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp,
 static int
 mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_ventry *ventry,
-				 struct mlxsw_sp_acl_tcam_chunk *chunk2)
+				 struct mlxsw_sp_acl_tcam_chunk *chunk)
 {
-	struct mlxsw_sp_acl_tcam_entry *entry2;
+	struct mlxsw_sp_acl_tcam_entry *new_entry;
 
 	/* First check if the entry is not already where we want it to be. */
-	if (ventry->entry->chunk == chunk2)
+	if (ventry->entry->chunk == chunk)
 		return 0;
 
-	entry2 = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk2);
-	if (IS_ERR(entry2))
-		return PTR_ERR(entry2);
+	new_entry = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk);
+	if (IS_ERR(new_entry))
+		return PTR_ERR(new_entry);
 	mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry);
-	ventry->entry = entry2;
+	ventry->entry = new_entry;
 	return 0;
 }
 
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 05/14] mlxsw: spectrum_acl: Push code start/end from mlxsw_sp_acl_tcam_vregion_migrate()
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Push code from the beginning and end of function
mlxsw_sp_acl_tcam_vregion_migrate() into rehash_start()/end() functions.
Then all the things needed to be done before and after the actual
migration process will be grouped together.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 74 +++++++++----------
 1 file changed, 35 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index fa204003bc84..cf901a1504c4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1277,59 +1277,24 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 				  struct mlxsw_sp_acl_tcam_vregion *vregion,
 				  struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
-	unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion);
-	struct mlxsw_sp_acl_tcam_region *region2, *unused_region;
 	int err;
 
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
-
-	region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam,
-						  vregion, ctx->hints_priv);
-	if (IS_ERR(region2)) {
-		err = PTR_ERR(region2);
-		goto out;
-	}
-
-	vregion->region2 = region2;
-	err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp,
-						    vregion->region->group,
-						    region2, priority,
-						    vregion->region);
-	if (err)
-		goto err_group_region_attach;
-
 	mutex_lock(&vregion->lock);
 
 	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion);
 	if (!vregion->failed_rollback) {
 		if (!err) {
 			/* In case of successful migration, region2 is used and
-			 * the original is unused.
-			 */
-			unused_region = vregion->region;
-			vregion->region = vregion->region2;
-		} else {
-			/* In case of failure during migration, the original
-			 * region is still used.
+			 * the original is unused. So swap them.
 			 */
-			unused_region = vregion->region2;
+			swap(vregion->region, vregion->region2);
 		}
-		mutex_unlock(&vregion->lock);
-		vregion->region2 = NULL;
-		mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, unused_region);
-		mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, unused_region);
-	} else {
-		mutex_unlock(&vregion->lock);
+		/* vregion->region2 contains pointer to unused region now. */
 	}
 
-	goto out;
-
-err_group_region_attach:
-	vregion->region2 = NULL;
-	mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2);
-out:
+	mutex_unlock(&vregion->lock);
 	trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
-
 	return err;
 }
 
@@ -1339,7 +1304,10 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
+	unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion);
+	struct mlxsw_sp_acl_tcam_region *region2;
 	void *hints_priv;
+	int err;
 
 	trace_mlxsw_sp_acl_tcam_vregion_rehash(mlxsw_sp, vregion);
 	if (vregion->failed_rollback)
@@ -1349,9 +1317,31 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 	if (IS_ERR(hints_priv))
 		return PTR_ERR(hints_priv);
 
+	region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam,
+						  vregion, hints_priv);
+	if (IS_ERR(region2)) {
+		err = PTR_ERR(region2);
+		goto err_region_create;
+	}
+
+	vregion->region2 = region2;
+	err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp,
+						    vregion->region->group,
+						    region2, priority,
+						    vregion->region);
+	if (err)
+		goto err_group_region_attach;
+
 	ctx->hints_priv = hints_priv;
 
 	return 0;
+
+err_group_region_attach:
+	vregion->region2 = NULL;
+	mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2);
+err_region_create:
+	ops->region_rehash_hints_put(hints_priv);
+	return err;
 }
 
 static void
@@ -1359,8 +1349,14 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp,
 				     struct mlxsw_sp_acl_tcam_vregion *vregion,
 				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
+	struct mlxsw_sp_acl_tcam_region *unused_region = vregion->region2;
 	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
 
+	if (!vregion->failed_rollback) {
+		vregion->region2 = NULL;
+		mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, unused_region);
+		mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, unused_region);
+	}
 	ops->region_rehash_hints_put(ctx->hints_priv);
 	ctx->hints_priv = NULL;
 }
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 09/14] mlxsw: spectrum_acl: Put this_is_rollback to rehash context struct
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Put the this_is_rollback flag into rehash context struct in preparations
for interrupt/continue of rehash work.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 0bc04016c6d0..db80b20e4a13 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -182,6 +182,7 @@ struct mlxsw_sp_acl_tcam_vgroup {
 
 struct mlxsw_sp_acl_tcam_rehash_ctx {
 	void *hints_priv;
+	bool this_is_rollback;
 };
 
 struct mlxsw_sp_acl_tcam_vregion {
@@ -1195,7 +1196,7 @@ static int
 mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 				     struct mlxsw_sp_acl_tcam_vchunk *vchunk,
 				     struct mlxsw_sp_acl_tcam_region *region,
-				     bool this_is_rollback)
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	struct mlxsw_sp_acl_tcam_chunk *new_chunk;
 	struct mlxsw_sp_acl_tcam_ventry *ventry;
@@ -1204,7 +1205,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 
 	new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
 	if (IS_ERR(new_chunk)) {
-		if (this_is_rollback)
+		if (ctx->this_is_rollback)
 			vchunk->vregion->failed_rollback = true;
 		return PTR_ERR(new_chunk);
 	}
@@ -1215,7 +1216,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
 						       vchunk->chunk);
 		if (err) {
-			if (this_is_rollback) {
+			if (ctx->this_is_rollback) {
 				vchunk->vregion->failed_rollback = true;
 				return err;
 			}
@@ -1251,7 +1252,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 
 static int
 mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
-				     struct mlxsw_sp_acl_tcam_vregion *vregion)
+				     struct mlxsw_sp_acl_tcam_vregion *vregion,
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	struct mlxsw_sp_acl_tcam_vchunk *vchunk;
 	int err;
@@ -1259,7 +1261,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 	list_for_each_entry(vchunk, &vregion->vchunk_list, list) {
 		err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
 							   vregion->region,
-							   false);
+							   ctx);
 		if (err)
 			goto rollback;
 	}
@@ -1270,10 +1272,12 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 	 * so the original region pointer is assigned again to vregion->region.
 	 */
 	swap(vregion->region, vregion->region2);
+	ctx->this_is_rollback = true;
 	list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list,
 					     list) {
 		mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
-						     vregion->region, true);
+						     vregion->region,
+						     ctx);
 	}
 	return err;
 }
@@ -1287,7 +1291,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
 	mutex_lock(&vregion->lock);
-	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion);
+	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx);
 	mutex_unlock(&vregion->lock);
 	trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
 	return err;
@@ -1332,6 +1336,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 		goto err_group_region_attach;
 
 	ctx->hints_priv = hints_priv;
+	ctx->this_is_rollback = false;
 
 	return 0;
 
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 06/14] mlxsw: spectrum_acl: assign vregion->region by the newly created region
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Make the vregion->region contain pointer of a new region we migrate to.
In case of a rollback, it contains the original region.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 42 +++++++++----------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index cf901a1504c4..72734ee60a1e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1256,7 +1256,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 
 	list_for_each_entry(vchunk, &vregion->vchunk_list, list) {
 		err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
-							   vregion->region2,
+							   vregion->region,
 							   false);
 		if (err)
 			goto rollback;
@@ -1264,6 +1264,10 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 	return 0;
 
 rollback:
+	/* In case migration was not successful, we need to swap
+	 * so the original region pointer is assigned again to vregion->region.
+	 */
+	swap(vregion->region, vregion->region2);
 	list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list,
 					     list) {
 		mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
@@ -1281,18 +1285,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
 	mutex_lock(&vregion->lock);
-
 	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion);
-	if (!vregion->failed_rollback) {
-		if (!err) {
-			/* In case of successful migration, region2 is used and
-			 * the original is unused. So swap them.
-			 */
-			swap(vregion->region, vregion->region2);
-		}
-		/* vregion->region2 contains pointer to unused region now. */
-	}
-
 	mutex_unlock(&vregion->lock);
 	trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
 	return err;
@@ -1305,7 +1298,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 {
 	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
 	unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion);
-	struct mlxsw_sp_acl_tcam_region *region2;
+	struct mlxsw_sp_acl_tcam_region *new_region;
 	void *hints_priv;
 	int err;
 
@@ -1317,18 +1310,22 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 	if (IS_ERR(hints_priv))
 		return PTR_ERR(hints_priv);
 
-	region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam,
-						  vregion, hints_priv);
-	if (IS_ERR(region2)) {
-		err = PTR_ERR(region2);
+	new_region = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam,
+						     vregion, hints_priv);
+	if (IS_ERR(new_region)) {
+		err = PTR_ERR(new_region);
 		goto err_region_create;
 	}
 
-	vregion->region2 = region2;
+	/* vregion->region contains the pointer to the new region
+	 * we are going to migrate to.
+	 */
+	vregion->region2 = vregion->region;
+	vregion->region = new_region;
 	err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp,
-						    vregion->region->group,
-						    region2, priority,
-						    vregion->region);
+						    vregion->region2->group,
+						    new_region, priority,
+						    vregion->region2);
 	if (err)
 		goto err_group_region_attach;
 
@@ -1337,8 +1334,9 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 	return 0;
 
 err_group_region_attach:
+	vregion->region = vregion->region2;
 	vregion->region2 = NULL;
-	mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2);
+	mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, new_region);
 err_region_create:
 	ops->region_rehash_hints_put(hints_priv);
 	return err;
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 10/14] mlxsw: spectrum_acl: Put vchunk migrate start/end code into separate functions
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

In preparations of interrupt/continue of rehash work, put the code that
is done at the beginning/end of vchunk migrate function into separate
functions.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 43 ++++++++++++++-----
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index db80b20e4a13..1f308ad4b635 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1193,15 +1193,12 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp,
 }
 
 static int
-mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
-				     struct mlxsw_sp_acl_tcam_vchunk *vchunk,
-				     struct mlxsw_sp_acl_tcam_region *region,
-				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp,
+				       struct mlxsw_sp_acl_tcam_vchunk *vchunk,
+				       struct mlxsw_sp_acl_tcam_region *region,
+				       struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	struct mlxsw_sp_acl_tcam_chunk *new_chunk;
-	struct mlxsw_sp_acl_tcam_ventry *ventry;
-	int err;
-	int err2;
 
 	new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
 	if (IS_ERR(new_chunk)) {
@@ -1211,6 +1208,31 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 	}
 	vchunk->chunk2 = vchunk->chunk;
 	vchunk->chunk = new_chunk;
+	return 0;
+}
+
+static void
+mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp,
+				     struct mlxsw_sp_acl_tcam_vchunk *vchunk)
+{
+	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
+	vchunk->chunk2 = NULL;
+}
+
+static int
+mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
+				     struct mlxsw_sp_acl_tcam_vchunk *vchunk,
+				     struct mlxsw_sp_acl_tcam_region *region,
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+{
+	struct mlxsw_sp_acl_tcam_ventry *ventry;
+	int err;
+	int err2;
+
+	err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk,
+						     region, ctx);
+	if (err)
+		return err;
 
 	list_for_each_entry(ventry, &vchunk->ventry_list, list) {
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
@@ -1223,8 +1245,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 			goto rollback;
 		}
 	}
-	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
-	vchunk->chunk2 = NULL;
+
+	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk);
 	return 0;
 
 rollback:
@@ -1243,8 +1265,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 		}
 	}
 
-	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
-	vchunk->chunk2 = NULL;
+	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk);
 
 err_rollback:
 	return err;
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 07/14] mlxsw: spectrum_acl: assign vchunk->chunk by the newly created chunk
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Make the vchunk->chunk contain pointer of a new chunk we migrate to.
In case of a rollback, it contains the original chunk.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c         | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 72734ee60a1e..6a50266b6809 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1197,21 +1197,23 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 				     struct mlxsw_sp_acl_tcam_region *region,
 				     bool this_is_rollback)
 {
+	struct mlxsw_sp_acl_tcam_chunk *new_chunk;
 	struct mlxsw_sp_acl_tcam_ventry *ventry;
-	struct mlxsw_sp_acl_tcam_chunk *chunk2;
 	int err;
 	int err2;
 
-	chunk2 = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
-	if (IS_ERR(chunk2)) {
+	new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
+	if (IS_ERR(new_chunk)) {
 		if (this_is_rollback)
 			vchunk->vregion->failed_rollback = true;
-		return PTR_ERR(chunk2);
+		return PTR_ERR(new_chunk);
 	}
-	vchunk->chunk2 = chunk2;
+	vchunk->chunk2 = vchunk->chunk;
+	vchunk->chunk = new_chunk;
+
 	list_for_each_entry(ventry, &vchunk->ventry_list, list) {
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
-						       vchunk->chunk2);
+						       vchunk->chunk);
 		if (err) {
 			if (this_is_rollback) {
 				vchunk->vregion->failed_rollback = true;
@@ -1220,8 +1222,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 			goto rollback;
 		}
 	}
-	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk);
-	vchunk->chunk = chunk2;
+	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
 	vchunk->chunk2 = NULL;
 	return 0;
 
@@ -1230,6 +1231,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 	 * migration fails, there's no good way how to proceed. Set the
 	 * vregion with "failed_rollback" flag.
 	 */
+	swap(vchunk->chunk, vchunk->chunk2);
 	list_for_each_entry_continue_reverse(ventry, &vchunk->ventry_list,
 					     list) {
 		err2 = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 11/14] mlxsw: spectrum_acl: Do rollback as another call to mlxsw_sp_acl_tcam_vchunk_migrate_all()
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

In order to simplify the code and to prepare it for
interrupted/continued migration process, do the rollback in case of
migration error as another call to mlxsw_sp_acl_tcam_vchunk_migrate_all().
It can be understood as "migrate all back".

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 75 +++++++------------
 1 file changed, 29 insertions(+), 46 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 1f308ad4b635..9dc83815644e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -1227,48 +1227,34 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 {
 	struct mlxsw_sp_acl_tcam_ventry *ventry;
 	int err;
-	int err2;
 
-	err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk,
-						     region, ctx);
-	if (err)
-		return err;
+	if (vchunk->chunk->region != region) {
+		err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk,
+							     region, ctx);
+		if (err)
+			return err;
+	} else if (!vchunk->chunk2) {
+		/* The chunk is already as it should be, nothing to do. */
+		return 0;
+	}
 
 	list_for_each_entry(ventry, &vchunk->ventry_list, list) {
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
 						       vchunk->chunk);
 		if (err) {
-			if (ctx->this_is_rollback) {
-				vchunk->vregion->failed_rollback = true;
+			if (ctx->this_is_rollback)
 				return err;
-			}
-			goto rollback;
+			/* Swap the chunk and chunk2 pointers so the follow-up
+			 * rollback call will see the original chunk pointer
+			 * in vchunk->chunk.
+			 */
+			swap(vchunk->chunk, vchunk->chunk2);
+			return err;
 		}
 	}
 
 	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk);
 	return 0;
-
-rollback:
-	/* Migrate the entries back to the original chunk. If some entry
-	 * migration fails, there's no good way how to proceed. Set the
-	 * vregion with "failed_rollback" flag.
-	 */
-	swap(vchunk->chunk, vchunk->chunk2);
-	list_for_each_entry_continue_reverse(ventry, &vchunk->ventry_list,
-					     list) {
-		err2 = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
-							vchunk->chunk);
-		if (err2) {
-			vchunk->vregion->failed_rollback = true;
-			goto err_rollback;
-		}
-	}
-
-	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk);
-
-err_rollback:
-	return err;
 }
 
 static int
@@ -1284,23 +1270,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 							   vregion->region,
 							   ctx);
 		if (err)
-			goto rollback;
+			return err;
 	}
 	return 0;
-
-rollback:
-	/* In case migration was not successful, we need to swap
-	 * so the original region pointer is assigned again to vregion->region.
-	 */
-	swap(vregion->region, vregion->region2);
-	ctx->this_is_rollback = true;
-	list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list,
-					     list) {
-		mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
-						     vregion->region,
-						     ctx);
-	}
-	return err;
 }
 
 static int
@@ -1308,11 +1280,22 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 				  struct mlxsw_sp_acl_tcam_vregion *vregion,
 				  struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
-	int err;
+	int err, err2;
 
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
 	mutex_lock(&vregion->lock);
 	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx);
+	if (err) {
+		/* In case migration was not successful, we need to swap
+		 * so the original region pointer is assigned again
+		 * to vregion->region.
+		 */
+		swap(vregion->region, vregion->region2);
+		ctx->this_is_rollback = true;
+		err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx);
+		if (err2)
+			vregion->failed_rollback = true;
+	}
 	mutex_unlock(&vregion->lock);
 	trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
 	return err;
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 12/14] mlxsw: spectrum_acl: Allow to interrupt/continue rehash work
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Currently, migration of vregions with many entries may take long time
during which insertions and removals of the rules are blocked
due to wait to acquire vregion->lock.

To overcome this, allow to interrupt and continue rehash work according
to the set credits - number of rules to migrate.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 82 ++++++++++++++-----
 1 file changed, 62 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 9dc83815644e..cfd05af3f0f6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -27,6 +27,7 @@ size_t mlxsw_sp_acl_tcam_priv_size(struct mlxsw_sp *mlxsw_sp)
 
 #define MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_DFLT 5000 /* ms */
 #define MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_MIN 3000 /* ms */
+#define MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS 100 /* number of entries */
 
 int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
 			   struct mlxsw_sp_acl_tcam *tcam)
@@ -732,16 +733,26 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion
 
 static int
 mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
-				 struct mlxsw_sp_acl_tcam_vregion *vregion);
+				 struct mlxsw_sp_acl_tcam_vregion *vregion,
+				 int *credits);
 
 static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
 {
 	struct mlxsw_sp_acl_tcam_vregion *vregion =
 		container_of(work, struct mlxsw_sp_acl_tcam_vregion,
 			     rehash.dw.work);
+	int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
+	int err;
 
-	mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion);
-	mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
+	err = mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp,
+					       vregion, &credits);
+	if (credits < 0)
+		/* Rehash gone out of credits so it was interrupted.
+		 * Schedule the work as soon as possible to continue.
+		 */
+		mlxsw_core_schedule_dw(&vregion->rehash.dw, 0);
+	else
+		mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
 }
 
 static struct mlxsw_sp_acl_tcam_vregion *
@@ -1176,7 +1187,8 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp,
 static int
 mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_ventry *ventry,
-				 struct mlxsw_sp_acl_tcam_chunk *chunk)
+				 struct mlxsw_sp_acl_tcam_chunk *chunk,
+				 int *credits)
 {
 	struct mlxsw_sp_acl_tcam_entry *new_entry;
 
@@ -1184,6 +1196,9 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp,
 	if (ventry->entry->chunk == chunk)
 		return 0;
 
+	if (--(*credits) < 0)
+		return 0;
+
 	new_entry = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk);
 	if (IS_ERR(new_entry))
 		return PTR_ERR(new_entry);
@@ -1223,7 +1238,8 @@ static int
 mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 				     struct mlxsw_sp_acl_tcam_vchunk *vchunk,
 				     struct mlxsw_sp_acl_tcam_region *region,
-				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx,
+				     int *credits)
 {
 	struct mlxsw_sp_acl_tcam_ventry *ventry;
 	int err;
@@ -1240,7 +1256,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 
 	list_for_each_entry(ventry, &vchunk->ventry_list, list) {
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
-						       vchunk->chunk);
+						       vchunk->chunk, credits);
 		if (err) {
 			if (ctx->this_is_rollback)
 				return err;
@@ -1250,6 +1266,11 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 			 */
 			swap(vchunk->chunk, vchunk->chunk2);
 			return err;
+		} else if (*credits < 0) {
+			/* We are out of credits, the rest of the ventries
+			 * will be migrated later.
+			 */
+			return 0;
 		}
 	}
 
@@ -1260,7 +1281,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 static int
 mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 				     struct mlxsw_sp_acl_tcam_vregion *vregion,
-				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx,
+				     int *credits)
 {
 	struct mlxsw_sp_acl_tcam_vchunk *vchunk;
 	int err;
@@ -1268,8 +1290,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 	list_for_each_entry(vchunk, &vregion->vchunk_list, list) {
 		err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
 							   vregion->region,
-							   ctx);
-		if (err)
+							   ctx, credits);
+		if (err || *credits < 0)
 			return err;
 	}
 	return 0;
@@ -1278,13 +1300,15 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 static int
 mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 				  struct mlxsw_sp_acl_tcam_vregion *vregion,
-				  struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+				  struct mlxsw_sp_acl_tcam_rehash_ctx *ctx,
+				  int *credits)
 {
 	int err, err2;
 
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
 	mutex_lock(&vregion->lock);
-	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx);
+	err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
+						   ctx, credits);
 	if (err) {
 		/* In case migration was not successful, we need to swap
 		 * so the original region pointer is assigned again
@@ -1292,7 +1316,8 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 		 */
 		swap(vregion->region, vregion->region2);
 		ctx->this_is_rollback = true;
-		err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx);
+		err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
+							    ctx, credits);
 		if (err2)
 			vregion->failed_rollback = true;
 	}
@@ -1301,6 +1326,12 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 	return err;
 }
 
+static bool
+mlxsw_sp_acl_tcam_vregion_rehash_in_progress(const struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
+{
+	return ctx->hints_priv;
+}
+
 static int
 mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_tcam_vregion *vregion,
@@ -1372,19 +1403,28 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp,
 
 static int
 mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
-				 struct mlxsw_sp_acl_tcam_vregion *vregion)
+				 struct mlxsw_sp_acl_tcam_vregion *vregion,
+				 int *credits)
 {
 	struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
 	int err;
 
-	err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp, vregion, ctx);
-	if (err) {
-		if (err != -EAGAIN)
-			dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n");
-		return err;
+	/* Check if the previous rehash work was interrupted
+	 * which means we have to continue it now.
+	 * If not, start a new rehash.
+	 */
+	if (!mlxsw_sp_acl_tcam_vregion_rehash_in_progress(ctx)) {
+		err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp,
+							     vregion, ctx);
+		if (err) {
+			if (err != -EAGAIN)
+				dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n");
+			return err;
+		}
 	}
 
-	err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx);
+	err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion,
+						ctx, credits);
 	if (err) {
 		dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
 		if (vregion->failed_rollback) {
@@ -1394,7 +1434,9 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 		}
 	}
 
-	mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx);
+	if (*credits >= 0)
+		mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx);
+
 	return err;
 }
 
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 03/14] mlxsw: spectrum_acl: Introduce new rehash context struct and save hint_priv there
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Prepare for continued migration. Introduce a new structure to track
rehash context and save hint_priv into it.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c  | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index 30131ea2e324..ae1101c17f2c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -180,6 +180,10 @@ struct mlxsw_sp_acl_tcam_vgroup {
 	bool vregion_rehash_enabled;
 };
 
+struct mlxsw_sp_acl_tcam_rehash_ctx {
+	void *hints_priv;
+};
+
 struct mlxsw_sp_acl_tcam_vregion {
 	struct mutex lock; /* Protects consistency of region, region2 pointers
 			    * and vchunk_list.
@@ -194,6 +198,7 @@ struct mlxsw_sp_acl_tcam_vregion {
 	struct mlxsw_sp_acl_tcam_vgroup *vgroup;
 	struct {
 		struct delayed_work dw;
+		struct mlxsw_sp_acl_tcam_rehash_ctx ctx;
 	} rehash;
 	struct mlxsw_sp *mlxsw_sp;
 	bool failed_rollback; /* Indicates failed rollback during migration */
@@ -1270,7 +1275,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 static int
 mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 				  struct mlxsw_sp_acl_tcam_vregion *vregion,
-				  void *hints_priv)
+				  struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion);
 	struct mlxsw_sp_acl_tcam_region *region2, *unused_region;
@@ -1279,7 +1284,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 	trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
 
 	region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam,
-						  vregion, hints_priv);
+						  vregion, ctx->hints_priv);
 	if (IS_ERR(region2)) {
 		err = PTR_ERR(region2);
 		goto out;
@@ -1333,6 +1338,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_vregion *vregion)
 {
 	const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
+	struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
 	void *hints_priv;
 	int err;
 
@@ -1347,8 +1353,9 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 			dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n");
 		return err;
 	}
+	ctx->hints_priv = hints_priv;
 
-	err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, hints_priv);
+	err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx);
 	if (err) {
 		dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
 		if (vregion->failed_rollback) {
@@ -1358,7 +1365,8 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 		}
 	}
 
-	ops->region_rehash_hints_put(hints_priv);
+	ops->region_rehash_hints_put(ctx->hints_priv);
+	ctx->hints_priv = NULL;
 	return err;
 }
 
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 13/14] mlxsw: spectrum_acl: Remember where to continue rehash migration
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

Store pointer to vchunk where the migration was interrupted, as well as
ventry pointer to start from and to stop at (during rollback). This
saved pointers need to be forgotten in case of ventries list or vchunk
list changes, which is done by couple of "changed" helpers.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../mellanox/mlxsw/spectrum_acl_tcam.c        | 91 ++++++++++++++++++-
 1 file changed, 86 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index cfd05af3f0f6..dc118ed714b2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -184,6 +184,19 @@ struct mlxsw_sp_acl_tcam_vgroup {
 struct mlxsw_sp_acl_tcam_rehash_ctx {
 	void *hints_priv;
 	bool this_is_rollback;
+	struct mlxsw_sp_acl_tcam_vchunk *current_vchunk; /* vchunk being
+							  * currently migrated.
+							  */
+	struct mlxsw_sp_acl_tcam_ventry *start_ventry; /* ventry to start
+							* migration from in
+							* a vchunk being
+							* currently migrated.
+							*/
+	struct mlxsw_sp_acl_tcam_ventry *stop_ventry; /* ventry to stop
+						       * migration at
+						       * a vchunk being
+						       * currently migrated.
+						       */
 };
 
 struct mlxsw_sp_acl_tcam_vregion {
@@ -755,6 +768,31 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
 		mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
 }
 
+static void
+mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(struct mlxsw_sp_acl_tcam_vchunk *vchunk)
+{
+	struct mlxsw_sp_acl_tcam_vregion *vregion = vchunk->vregion;
+
+	/* If a rule was added or deleted from vchunk which is currently
+	 * under rehash migration, we have to reset the ventry pointers
+	 * to make sure all rules are properly migrated.
+	 */
+	if (vregion->rehash.ctx.current_vchunk == vchunk) {
+		vregion->rehash.ctx.start_ventry = NULL;
+		vregion->rehash.ctx.stop_ventry = NULL;
+	}
+}
+
+static void
+mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(struct mlxsw_sp_acl_tcam_vregion *vregion)
+{
+	/* If a chunk was added or deleted from vregion we have to reset
+	 * the current chunk pointer to make sure all chunks
+	 * are properly migrated.
+	 */
+	vregion->rehash.ctx.current_vchunk = NULL;
+}
+
 static struct mlxsw_sp_acl_tcam_vregion *
 mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_vgroup *vgroup,
@@ -989,6 +1027,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp,
 		goto err_chunk_create;
 	}
 
+	mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(vregion);
 	list_add_tail(&vchunk->list, &vregion->vchunk_list);
 	mutex_unlock(&vregion->lock);
 
@@ -1012,6 +1051,7 @@ mlxsw_sp_acl_tcam_vchunk_destroy(struct mlxsw_sp *mlxsw_sp,
 	struct mlxsw_sp_acl_tcam_vgroup *vgroup = vchunk->vgroup;
 
 	mutex_lock(&vregion->lock);
+	mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(vregion);
 	list_del(&vchunk->list);
 	if (vchunk->chunk2)
 		mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
@@ -1141,6 +1181,7 @@ static int mlxsw_sp_acl_tcam_ventry_add(struct mlxsw_sp *mlxsw_sp,
 	}
 
 	list_add_tail(&ventry->list, &vchunk->ventry_list);
+	mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(vchunk);
 	mutex_unlock(&vregion->lock);
 
 	return 0;
@@ -1157,6 +1198,7 @@ static void mlxsw_sp_acl_tcam_ventry_del(struct mlxsw_sp *mlxsw_sp,
 	struct mlxsw_sp_acl_tcam_vregion *vregion = vchunk->vregion;
 
 	mutex_lock(&vregion->lock);
+	mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(vchunk);
 	list_del(&ventry->list);
 	mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry);
 	mutex_unlock(&vregion->lock);
@@ -1223,15 +1265,20 @@ mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp,
 	}
 	vchunk->chunk2 = vchunk->chunk;
 	vchunk->chunk = new_chunk;
+	ctx->current_vchunk = vchunk;
+	ctx->start_ventry = NULL;
+	ctx->stop_ventry = NULL;
 	return 0;
 }
 
 static void
 mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp,
-				     struct mlxsw_sp_acl_tcam_vchunk *vchunk)
+				     struct mlxsw_sp_acl_tcam_vchunk *vchunk,
+				     struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
 {
 	mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
 	vchunk->chunk2 = NULL;
+	ctx->current_vchunk = NULL;
 }
 
 static int
@@ -1254,7 +1301,22 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 		return 0;
 	}
 
-	list_for_each_entry(ventry, &vchunk->ventry_list, list) {
+	/* If the migration got interrupted, we have the ventry to start from
+	 * stored in context.
+	 */
+	if (ctx->start_ventry)
+		ventry = ctx->start_ventry;
+	else
+		ventry = list_first_entry(&vchunk->ventry_list,
+					  typeof(*ventry), list);
+
+	list_for_each_entry_from(ventry, &vchunk->ventry_list, list) {
+		/* During rollback, once we reach the ventry that failed
+		 * to migrate, we are done.
+		 */
+		if (ventry == ctx->stop_ventry)
+			break;
+
 		err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry,
 						       vchunk->chunk, credits);
 		if (err) {
@@ -1265,16 +1327,25 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
 			 * in vchunk->chunk.
 			 */
 			swap(vchunk->chunk, vchunk->chunk2);
+			/* The rollback has to be done from beginning of the
+			 * chunk, that is why we have to null the start_ventry.
+			 * However, we know where to stop the rollback,
+			 * at the current ventry.
+			 */
+			ctx->start_ventry = NULL;
+			ctx->stop_ventry = ventry;
 			return err;
 		} else if (*credits < 0) {
 			/* We are out of credits, the rest of the ventries
-			 * will be migrated later.
+			 * will be migrated later. Save the ventry
+			 * which we ended with.
 			 */
+			ctx->start_ventry = ventry;
 			return 0;
 		}
 	}
 
-	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk);
+	mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk, ctx);
 	return 0;
 }
 
@@ -1287,7 +1358,16 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
 	struct mlxsw_sp_acl_tcam_vchunk *vchunk;
 	int err;
 
-	list_for_each_entry(vchunk, &vregion->vchunk_list, list) {
+	/* If the migration got interrupted, we have the vchunk
+	 * we are working on stored in context.
+	 */
+	if (ctx->current_vchunk)
+		vchunk = ctx->current_vchunk;
+	else
+		vchunk = list_first_entry(&vregion->vchunk_list,
+					  typeof(*vchunk), list);
+
+	list_for_each_entry_from(vchunk, &vregion->vchunk_list, list) {
 		err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk,
 							   vregion->region,
 							   ctx, credits);
@@ -1315,6 +1395,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
 		 * to vregion->region.
 		 */
 		swap(vregion->region, vregion->region2);
+		ctx->current_vchunk = NULL;
 		ctx->this_is_rollback = true;
 		err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
 							    ctx, credits);
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next 14/14] mlxsw: spectrum_acl: Make mlxsw_sp_acl_tcam_vregion_rehash() return void
From: Ido Schimmel @ 2019-02-28  6:59 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, mlxsw, Ido Schimmel
In-Reply-To: <20190228065850.7471-1-idosch@mellanox.com>

From: Jiri Pirko <jiri@mellanox.com>

The return value is ignored anyway, so just return void.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c  | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index dc118ed714b2..8811f6513e36 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -744,7 +744,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion
 			       msecs_to_jiffies(interval));
 }
 
-static int
+static void
 mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_vregion *vregion,
 				 int *credits);
@@ -755,10 +755,8 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
 		container_of(work, struct mlxsw_sp_acl_tcam_vregion,
 			     rehash.dw.work);
 	int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
-	int err;
 
-	err = mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp,
-					       vregion, &credits);
+	mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
 	if (credits < 0)
 		/* Rehash gone out of credits so it was interrupted.
 		 * Schedule the work as soon as possible to continue.
@@ -1482,7 +1480,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp,
 	ctx->hints_priv = NULL;
 }
 
-static int
+static void
 mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 				 struct mlxsw_sp_acl_tcam_vregion *vregion,
 				 int *credits)
@@ -1500,7 +1498,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 		if (err) {
 			if (err != -EAGAIN)
 				dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n");
-			return err;
+			return;
 		}
 	}
 
@@ -1517,8 +1515,6 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
 
 	if (*credits >= 0)
 		mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx);
-
-	return err;
 }
 
 static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = {
-- 
2.20.1


^ permalink raw reply related

* Re: linux-next: manual merge of the staging tree with the net-next tree
From: Greg KH @ 2019-02-28  7:04 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: David Miller, Networking, Linux Next Mailing List,
	Linux Kernel Mailing List, Florian Fainelli
In-Reply-To: <20190228155201.329a1fad@canb.auug.org.au>

On Thu, Feb 28, 2019 at 03:52:01PM +1100, Stephen Rothwell wrote:
> Hi all,
> 
> Today's linux-next merge of the staging tree got a conflict in:
> 
>   drivers/staging/fsl-dpaa2/ethsw/ethsw.c
> 
> between commit:
> 
>   570b68c8ddde ("staging: fsl-dpaa2: ethsw: Handle SWITCHDEV_PORT_ATTR_SET")
> 
> from the net-next tree and commit:
> 
>   11f27765f611 ("staging: fsl-dpaa2: ethsw: Add missing netdevice check")
> 
> from the staging tree.
> 
> I fixed it up (the former is a superset of the latter) and can carry the
> fix as necessary. This is now fixed as far as linux-next is concerned,
> but any non trivial conflicts should be mentioned to your upstream
> maintainer when your tree is submitted for merging.  You may also want
> to consider cooperating with the maintainer of the conflicting tree to
> minimise any particularly complex conflicts.

Looks good to me, thanks!

greg k-h

^ permalink raw reply

* Re: [PATCH net-next] switchdev: Remove unused transaction item queue
From: Jiri Pirko @ 2019-02-28  7:02 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: netdev, David S. Miller, Ido Schimmel, open list,
	open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
	andrew, vivien.didelot
In-Reply-To: <20190228002916.24904-1-f.fainelli@gmail.com>

Thu, Feb 28, 2019 at 01:29:16AM CET, f.fainelli@gmail.com wrote:
>There are no more in tree users of the
>switchdev_trans_item_{dequeue,enqueue} or switchdev_trans_item structure
>in the kernel since commit 00fc0c51e35b ("rocker: Change world_ops API
>and implementation to be switchdev independant").
>
>Remove this unused code and update the documentation accordingly since.
>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox