2024-01-17 06:23:45

by Jenishkumar Patel [C]

[permalink] [raw]
Subject: [net v2 PATCH 1/1] net: mvpp2: clear BM pool before initialization

Register value persist after booting the kernel using
kexec which results in kernel panic. Thus clear the
BM pool registers before initialisation to fix the issue.

Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit")
Signed-off-by: Jenishkumar Maheshbhai Patel <[email protected]>
---
v1-v2:
-Move comments outside the loop
-remove unrequired brances.

.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 820b1fabe297..49d9960f9ce8 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -614,12 +614,37 @@ static void mvpp23_bm_set_8pool_mode(struct mvpp2 *priv)
mvpp2_write(priv, MVPP22_BM_POOL_BASE_ADDR_HIGH_REG, val);
}

+/* Cleanup pool before actual initialization in the OS */
+static void mvpp2_bm_pool_cleanup(struct mvpp2 *priv, int pool_id)
+{
+ u32 val;
+ int i;
+ /* Drain the BM from all possible residues left by firmware */
+ for (i = 0; i < MVPP2_BM_POOL_SIZE_MAX; i++)
+ mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(pool_id));
+ /* Stop the BM pool */
+ val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(pool_id));
+ val |= MVPP2_BM_STOP_MASK;
+ mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(pool_id), val);
+ /* Mask BM all interrupts */
+ mvpp2_write(priv, MVPP2_BM_INTR_MASK_REG(pool_id), 0);
+ /* Clear BM cause register */
+ mvpp2_write(priv, MVPP2_BM_INTR_CAUSE_REG(pool_id), 0);
+}
+
static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv)
{
enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
int i, err, poolnum = MVPP2_BM_POOLS_NUM;
struct mvpp2_port *port;

+ if (priv->percpu_pools)
+ poolnum = mvpp2_get_nrxqs(priv) * 2;
+
+ /* Clean up the pool state in case it contains stale state */
+ for (i = 0; i < poolnum; i++)
+ mvpp2_bm_pool_cleanup(priv, i);
+
if (priv->percpu_pools) {
for (i = 0; i < priv->port_count; i++) {
port = priv->port_list[i];
--
2.25.1



2024-01-17 09:26:39

by Antoine Tenart

[permalink] [raw]
Subject: Re: [net v2 PATCH 1/1] net: mvpp2: clear BM pool before initialization

Hello,

Quoting Jenishkumar Maheshbhai Patel (2024-01-17 07:23:10)
> +/* Cleanup pool before actual initialization in the OS */
> +static void mvpp2_bm_pool_cleanup(struct mvpp2 *priv, int pool_id)
> +{
> + u32 val;
> + int i;

Please add an empty line here. (You might as well add some below to
improve readability).

> + /* Drain the BM from all possible residues left by firmware */
> + for (i = 0; i < MVPP2_BM_POOL_SIZE_MAX; i++)
> + mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(pool_id));

Not sure about the above, but I don't have the datasheet. Looks like
MVPP2_BM_PHY_ALLOC_REG contains the buffer dma addr, and is read
multiple times in a loop. Also the driver's comments says:

"""
- global registers that must be accessed through a specific thread
window, because they are related to an access to a per-thread
register

MVPP2_BM_PHY_ALLOC_REG (related to MVPP2_BM_VIRT_ALLOC_REG)
"""

If that's intended, maybe add a comment about what this does and why
mvpp2_thread_read isn't used?

> + /* Stop the BM pool */
> + val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(pool_id));
> + val |= MVPP2_BM_STOP_MASK;
> + mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(pool_id), val);
> + /* Mask BM all interrupts */
> + mvpp2_write(priv, MVPP2_BM_INTR_MASK_REG(pool_id), 0);
> + /* Clear BM cause register */
> + mvpp2_write(priv, MVPP2_BM_INTR_CAUSE_REG(pool_id), 0);
> +}
> +
> static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv)
> {
> enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
> int i, err, poolnum = MVPP2_BM_POOLS_NUM;
> struct mvpp2_port *port;
>
> + if (priv->percpu_pools)
> + poolnum = mvpp2_get_nrxqs(priv) * 2;

Since poolnum is now set here, you can remove the one below in the same
function (not shown in the context).

> +
> + /* Clean up the pool state in case it contains stale state */
> + for (i = 0; i < poolnum; i++)
> + mvpp2_bm_pool_cleanup(priv, i);
> +
> if (priv->percpu_pools) {
> for (i = 0; i < priv->port_count; i++) {
> port = priv->port_list[i];

Thanks.

2024-01-18 08:13:23

by Jenishkumar Patel [C]

[permalink] [raw]
Subject: RE: [EXT] Re: [net v2 PATCH 1/1] net: mvpp2: clear BM pool before initialization



-----Original Message-----
From: Antoine Tenart <[email protected]>
Sent: Wednesday, January 17, 2024 2:56 PM
To: Jenishkumar Patel [C] <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Cc: Jenishkumar Patel [C] <[email protected]>
Subject: [EXT] Re: [net v2 PATCH 1/1] net: mvpp2: clear BM pool before initialization

External Email

----------------------------------------------------------------------
Hello,

Quoting Jenishkumar Maheshbhai Patel (2024-01-17 07:23:10)
> +/* Cleanup pool before actual initialization in the OS */ static void
> +mvpp2_bm_pool_cleanup(struct mvpp2 *priv, int pool_id) {
> + u32 val;
> + int i;

Please add an empty line here. (You might as well add some below to improve readability).

I will address the comments in v3

> + /* Drain the BM from all possible residues left by firmware */
> + for (i = 0; i < MVPP2_BM_POOL_SIZE_MAX; i++)
> + mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(pool_id));

Not sure about the above, but I don't have the datasheet. Looks like MVPP2_BM_PHY_ALLOC_REG contains the buffer dma addr, and is read multiple times in a loop. Also the driver's comments says:

"""
- global registers that must be accessed through a specific thread
window, because they are related to an access to a per-thread
register

MVPP2_BM_PHY_ALLOC_REG (related to MVPP2_BM_VIRT_ALLOC_REG)
"""

If that's intended, maybe add a comment about what this does and why mvpp2_thread_read isn't used?

I will address the comments in v3 and correct the API accordingly

> + /* Stop the BM pool */
> + val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(pool_id));
> + val |= MVPP2_BM_STOP_MASK;
> + mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(pool_id), val);
> + /* Mask BM all interrupts */
> + mvpp2_write(priv, MVPP2_BM_INTR_MASK_REG(pool_id), 0);
> + /* Clear BM cause register */
> + mvpp2_write(priv, MVPP2_BM_INTR_CAUSE_REG(pool_id), 0); }
> +
> static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv) {
> enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
> int i, err, poolnum = MVPP2_BM_POOLS_NUM;
> struct mvpp2_port *port;
>
> + if (priv->percpu_pools)
> + poolnum = mvpp2_get_nrxqs(priv) * 2;

Since poolnum is now set here, you can remove the one below in the same function (not shown in the context).

I will address the comments in v3
> +
> + /* Clean up the pool state in case it contains stale state */
> + for (i = 0; i < poolnum; i++)
> + mvpp2_bm_pool_cleanup(priv, i);
> +
> if (priv->percpu_pools) {
> for (i = 0; i < priv->port_count; i++) {
> port = priv->port_list[i];

Thanks.