generic: 6.1: backport various qca8k fixes patch
Backport various QCA8K fixes patch merged upstream. Refresh any changed patches due to backports. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
f166c9e617
commit
a62b1544d1
@ -0,0 +1,63 @@
|
|||||||
|
From e03cea60c3db8c6b011cc36ecef9281dff8377f3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Jan 2023 21:35:16 +0100
|
||||||
|
Subject: [PATCH] net: dsa: qca8k: add QCA8K_ATU_TABLE_SIZE define for fdb
|
||||||
|
access
|
||||||
|
|
||||||
|
Add and use QCA8K_ATU_TABLE_SIZE instead of hardcoding the ATU size with
|
||||||
|
a pure number and using sizeof on the array.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-common.c | 10 ++++++----
|
||||||
|
drivers/net/dsa/qca/qca8k.h | 2 ++
|
||||||
|
2 files changed, 8 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
@@ -150,11 +150,12 @@ static int qca8k_busy_wait(struct qca8k_
|
||||||
|
|
||||||
|
static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
|
||||||
|
{
|
||||||
|
- u32 reg[3];
|
||||||
|
+ u32 reg[QCA8K_ATU_TABLE_SIZE];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* load the ARL table into an array */
|
||||||
|
- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||||
|
+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
+ QCA8K_ATU_TABLE_SIZE * sizeof(u32));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
@@ -178,7 +179,7 @@ static int qca8k_fdb_read(struct qca8k_p
|
||||||
|
static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask,
|
||||||
|
const u8 *mac, u8 aging)
|
||||||
|
{
|
||||||
|
- u32 reg[3] = { 0 };
|
||||||
|
+ u32 reg[QCA8K_ATU_TABLE_SIZE] = { 0 };
|
||||||
|
|
||||||
|
/* vid - 83:72 */
|
||||||
|
reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
|
||||||
|
@@ -195,7 +196,8 @@ static void qca8k_fdb_write(struct qca8k
|
||||||
|
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
|
||||||
|
|
||||||
|
/* load the array into the ARL table */
|
||||||
|
- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
|
||||||
|
+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
+ QCA8K_ATU_TABLE_SIZE * sizeof(u32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd,
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k.h
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||||
|
@@ -148,6 +148,8 @@
|
||||||
|
#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474
|
||||||
|
|
||||||
|
/* Lookup registers */
|
||||||
|
+#define QCA8K_ATU_TABLE_SIZE 3 /* 12 bytes wide table / sizeof(u32) */
|
||||||
|
+
|
||||||
|
#define QCA8K_REG_ATU_DATA0 0x600
|
||||||
|
#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24)
|
||||||
|
#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16)
|
@ -0,0 +1,261 @@
|
|||||||
|
From c766e077d927e1775902c18827205ea2ade3a35d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Jan 2023 21:35:17 +0100
|
||||||
|
Subject: [PATCH] net: dsa: qca8k: convert to regmap read/write API
|
||||||
|
|
||||||
|
Convert qca8k to regmap read/write bulk API. The mgmt eth can write up
|
||||||
|
to 32 bytes of data at times. Currently we use a custom function to do
|
||||||
|
it but regmap now supports declaration of read/write bulk even without a
|
||||||
|
bus.
|
||||||
|
|
||||||
|
Drop the custom function and rework the regmap function to this new
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Rework the qca8k_fdb_read/write function to use the new
|
||||||
|
regmap_bulk_read/write as the old qca8k_bulk_read/write are now dropped.
|
||||||
|
|
||||||
|
Cc: Mark Brown <broonie@kernel.org>
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 92 ++++++++++++++++++++++++------
|
||||||
|
drivers/net/dsa/qca/qca8k-common.c | 47 ++-------------
|
||||||
|
drivers/net/dsa/qca/qca8k.h | 3 -
|
||||||
|
3 files changed, 77 insertions(+), 65 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -425,16 +425,12 @@ qca8k_regmap_update_bits_eth(struct qca8
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
-qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||||
|
+qca8k_read_mii(struct qca8k_priv *priv, uint32_t reg, uint32_t *val)
|
||||||
|
{
|
||||||
|
- struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||||
|
struct mii_bus *bus = priv->bus;
|
||||||
|
u16 r1, r2, page;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (!qca8k_read_eth(priv, reg, val, sizeof(*val)))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||||
|
|
||||||
|
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||||
|
@@ -451,16 +447,12 @@ exit:
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
-qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
|
||||||
|
+qca8k_write_mii(struct qca8k_priv *priv, uint32_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
- struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||||
|
struct mii_bus *bus = priv->bus;
|
||||||
|
u16 r1, r2, page;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (!qca8k_write_eth(priv, reg, &val, sizeof(val)))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||||
|
|
||||||
|
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||||
|
@@ -477,17 +469,14 @@ exit:
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
-qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val)
|
||||||
|
+qca8k_regmap_update_bits_mii(struct qca8k_priv *priv, uint32_t reg,
|
||||||
|
+ uint32_t mask, uint32_t write_val)
|
||||||
|
{
|
||||||
|
- struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||||
|
struct mii_bus *bus = priv->bus;
|
||||||
|
u16 r1, r2, page;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||||
|
|
||||||
|
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||||
|
@@ -510,17 +499,84 @@ exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+qca8k_bulk_read(void *ctx, const void *reg_buf, size_t reg_len,
|
||||||
|
+ void *val_buf, size_t val_len)
|
||||||
|
+{
|
||||||
|
+ int i, count = val_len / sizeof(u32), ret;
|
||||||
|
+ u32 reg = *(u32 *)reg_buf & U16_MAX;
|
||||||
|
+ struct qca8k_priv *priv = ctx;
|
||||||
|
+
|
||||||
|
+ if (priv->mgmt_master &&
|
||||||
|
+ !qca8k_read_eth(priv, reg, val_buf, val_len))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* loop count times and increment reg of 4 */
|
||||||
|
+ for (i = 0; i < count; i++, reg += sizeof(u32)) {
|
||||||
|
+ ret = qca8k_read_mii(priv, reg, val_buf + i);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+qca8k_bulk_gather_write(void *ctx, const void *reg_buf, size_t reg_len,
|
||||||
|
+ const void *val_buf, size_t val_len)
|
||||||
|
+{
|
||||||
|
+ int i, count = val_len / sizeof(u32), ret;
|
||||||
|
+ u32 reg = *(u32 *)reg_buf & U16_MAX;
|
||||||
|
+ struct qca8k_priv *priv = ctx;
|
||||||
|
+ u32 *val = (u32 *)val_buf;
|
||||||
|
+
|
||||||
|
+ if (priv->mgmt_master &&
|
||||||
|
+ !qca8k_write_eth(priv, reg, val, val_len))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* loop count times, increment reg of 4 and increment val ptr to
|
||||||
|
+ * the next value
|
||||||
|
+ */
|
||||||
|
+ for (i = 0; i < count; i++, reg += sizeof(u32), val++) {
|
||||||
|
+ ret = qca8k_write_mii(priv, reg, *val);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+qca8k_bulk_write(void *ctx, const void *data, size_t bytes)
|
||||||
|
+{
|
||||||
|
+ return qca8k_bulk_gather_write(ctx, data, sizeof(u16), data + sizeof(u16),
|
||||||
|
+ bytes - sizeof(u16));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val)
|
||||||
|
+{
|
||||||
|
+ struct qca8k_priv *priv = ctx;
|
||||||
|
+
|
||||||
|
+ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ return qca8k_regmap_update_bits_mii(priv, reg, mask, write_val);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct regmap_config qca8k_regmap_config = {
|
||||||
|
.reg_bits = 16,
|
||||||
|
.val_bits = 32,
|
||||||
|
.reg_stride = 4,
|
||||||
|
.max_register = 0x16ac, /* end MIB - Port6 range */
|
||||||
|
- .reg_read = qca8k_regmap_read,
|
||||||
|
- .reg_write = qca8k_regmap_write,
|
||||||
|
+ .read = qca8k_bulk_read,
|
||||||
|
+ .write = qca8k_bulk_write,
|
||||||
|
.reg_update_bits = qca8k_regmap_update_bits,
|
||||||
|
.rd_table = &qca8k_readable_table,
|
||||||
|
.disable_locking = true, /* Locking is handled by qca8k read/write */
|
||||||
|
.cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */
|
||||||
|
+ .max_raw_read = 32, /* mgmt eth can read/write up to 8 registers at time */
|
||||||
|
+ .max_raw_write = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
@@ -2091,8 +2147,6 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||||
|
|
||||||
|
static const struct qca8k_info_ops qca8xxx_ops = {
|
||||||
|
.autocast_mib = qca8k_get_ethtool_stats_eth,
|
||||||
|
- .read_eth = qca8k_read_eth,
|
||||||
|
- .write_eth = qca8k_write_eth,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qca8k_match_data qca8327 = {
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
@@ -101,45 +101,6 @@ const struct regmap_access_table qca8k_r
|
||||||
|
.n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges),
|
||||||
|
};
|
||||||
|
|
||||||
|
-/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||||
|
-static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||||
|
-{
|
||||||
|
- int i, count = len / sizeof(u32), ret;
|
||||||
|
-
|
||||||
|
- if (priv->mgmt_master && priv->info->ops->read_eth &&
|
||||||
|
- !priv->info->ops->read_eth(priv, reg, val, len))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- for (i = 0; i < count; i++) {
|
||||||
|
- ret = regmap_read(priv->regmap, reg + (i * 4), val + i);
|
||||||
|
- if (ret < 0)
|
||||||
|
- return ret;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||||
|
-static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||||
|
-{
|
||||||
|
- int i, count = len / sizeof(u32), ret;
|
||||||
|
- u32 tmp;
|
||||||
|
-
|
||||||
|
- if (priv->mgmt_master && priv->info->ops->write_eth &&
|
||||||
|
- !priv->info->ops->write_eth(priv, reg, val, len))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- for (i = 0; i < count; i++) {
|
||||||
|
- tmp = val[i];
|
||||||
|
-
|
||||||
|
- ret = regmap_write(priv->regmap, reg + (i * 4), tmp);
|
||||||
|
- if (ret < 0)
|
||||||
|
- return ret;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
@@ -154,8 +115,8 @@ static int qca8k_fdb_read(struct qca8k_p
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* load the ARL table into an array */
|
||||||
|
- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
- QCA8K_ATU_TABLE_SIZE * sizeof(u32));
|
||||||
|
+ ret = regmap_bulk_read(priv->regmap, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
+ QCA8K_ATU_TABLE_SIZE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
@@ -196,8 +157,8 @@ static void qca8k_fdb_write(struct qca8k
|
||||||
|
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
|
||||||
|
|
||||||
|
/* load the array into the ARL table */
|
||||||
|
- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
- QCA8K_ATU_TABLE_SIZE * sizeof(u32));
|
||||||
|
+ regmap_bulk_write(priv->regmap, QCA8K_REG_ATU_DATA0, reg,
|
||||||
|
+ QCA8K_ATU_TABLE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd,
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k.h
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||||
|
@@ -330,9 +330,6 @@ struct qca8k_priv;
|
||||||
|
|
||||||
|
struct qca8k_info_ops {
|
||||||
|
int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data);
|
||||||
|
- /* TODO: remove these extra ops when we can support regmap bulk read/write */
|
||||||
|
- int (*read_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||||
|
- int (*write_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qca8k_match_data {
|
@ -0,0 +1,78 @@
|
|||||||
|
From 2c39dd025da489cf87d26469d9f5ff19715324a0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Mon, 24 Jul 2023 05:25:28 +0200
|
||||||
|
Subject: [PATCH 1/4] net: dsa: qca8k: enable use_single_write for qca8xxx
|
||||||
|
|
||||||
|
The qca8xxx switch supports 2 way to write reg values, a slow way using
|
||||||
|
mdio and a fast way by sending specially crafted mgmt packet to
|
||||||
|
read/write reg.
|
||||||
|
|
||||||
|
The fast way can support up to 32 bytes of data as eth packet are used
|
||||||
|
to send/receive.
|
||||||
|
|
||||||
|
This correctly works for almost the entire regmap of the switch but with
|
||||||
|
the use of some kernel selftests for dsa drivers it was found a funny
|
||||||
|
and interesting hw defect/limitation.
|
||||||
|
|
||||||
|
For some specific reg, bulk write won't work and will result in writing
|
||||||
|
only part of the requested regs resulting in half data written. This was
|
||||||
|
especially hard to track and discover due to the total strangeness of
|
||||||
|
the problem and also by the specific regs where this occurs.
|
||||||
|
|
||||||
|
This occurs in the specific regs of the ATU table, where multiple entry
|
||||||
|
needs to be written to compose the entire entry.
|
||||||
|
It was discovered that with a bulk write of 12 bytes on
|
||||||
|
QCA8K_REG_ATU_DATA0 only QCA8K_REG_ATU_DATA0 and QCA8K_REG_ATU_DATA2
|
||||||
|
were written, but QCA8K_REG_ATU_DATA1 was always zero.
|
||||||
|
Tcpdump was used to make sure the specially crafted packet was correct
|
||||||
|
and this was confirmed.
|
||||||
|
|
||||||
|
The problem was hard to track as the lack of QCA8K_REG_ATU_DATA1
|
||||||
|
resulted in an entry somehow possible as the first bytes of the mac
|
||||||
|
address are set in QCA8K_REG_ATU_DATA0 and the entry type is set in
|
||||||
|
QCA8K_REG_ATU_DATA2.
|
||||||
|
|
||||||
|
Funlly enough writing QCA8K_REG_ATU_DATA1 results in the same problem
|
||||||
|
with QCA8K_REG_ATU_DATA2 empty and QCA8K_REG_ATU_DATA1 and
|
||||||
|
QCA8K_REG_ATU_FUNC correctly written.
|
||||||
|
A speculation on the problem might be that there are some kind of
|
||||||
|
indirection internally when accessing these regs and they can't be
|
||||||
|
accessed all together, due to the fact that it's really a table mapped
|
||||||
|
somewhere in the switch SRAM.
|
||||||
|
|
||||||
|
Even more funny is the fact that every other reg was tested with all
|
||||||
|
kind of combination and they are not affected by this problem. Read
|
||||||
|
operation was also tested and always worked so it's not affected by this
|
||||||
|
problem.
|
||||||
|
|
||||||
|
The problem is not present if we limit writing a single reg at times.
|
||||||
|
|
||||||
|
To handle this hardware defect, enable use_single_write so that bulk
|
||||||
|
api can correctly split the write in multiple different operation
|
||||||
|
effectively reverting to a non-bulk write.
|
||||||
|
|
||||||
|
Cc: Mark Brown <broonie@kernel.org>
|
||||||
|
Fixes: c766e077d927 ("net: dsa: qca8k: convert to regmap read/write API")
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Cc: stable@vger.kernel.org
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 7 +++++--
|
||||||
|
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -575,8 +575,11 @@ static struct regmap_config qca8k_regmap
|
||||||
|
.rd_table = &qca8k_readable_table,
|
||||||
|
.disable_locking = true, /* Locking is handled by qca8k read/write */
|
||||||
|
.cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */
|
||||||
|
- .max_raw_read = 32, /* mgmt eth can read/write up to 8 registers at time */
|
||||||
|
- .max_raw_write = 32,
|
||||||
|
+ .max_raw_read = 32, /* mgmt eth can read up to 8 registers at time */
|
||||||
|
+ /* ATU regs suffer from a bug where some data are not correctly
|
||||||
|
+ * written. Disable bulk write to correctly write ATU entry.
|
||||||
|
+ */
|
||||||
|
+ .use_single_write = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
@ -0,0 +1,146 @@
|
|||||||
|
From 23cfc7172e5297d0bee49ac6f6f8248d1cf0820d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Sun, 30 Jul 2023 09:41:10 +0200
|
||||||
|
Subject: [PATCH 1/4] net: dsa: qca8k: make learning configurable and keep off
|
||||||
|
if standalone
|
||||||
|
|
||||||
|
Address learning should initially be turned off by the driver for port
|
||||||
|
operation in standalone mode, then the DSA core handles changes to it
|
||||||
|
via ds->ops->port_bridge_flags().
|
||||||
|
|
||||||
|
Currently this is not the case for qca8k where learning is enabled
|
||||||
|
unconditionally in qca8k_setup for every user port.
|
||||||
|
|
||||||
|
Handle ports configured in standalone mode by making the learning
|
||||||
|
configurable and not enabling it by default.
|
||||||
|
|
||||||
|
Implement .port_pre_bridge_flags and .port_bridge_flags dsa ops to
|
||||||
|
enable learning for bridge that request it and tweak
|
||||||
|
.port_stp_state_set to correctly disable learning when port is
|
||||||
|
configured in standalone mode.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||||
|
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230730074113.21889-2-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 7 +++--
|
||||||
|
drivers/net/dsa/qca/qca8k-common.c | 48 ++++++++++++++++++++++++++++++
|
||||||
|
drivers/net/dsa/qca/qca8k.h | 6 ++++
|
||||||
|
3 files changed, 58 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -1883,9 +1883,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- /* Enable ARP Auto-learning by default */
|
||||||
|
- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
- QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
+ ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
+ QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
@@ -1991,6 +1990,8 @@ static const struct dsa_switch_ops qca8k
|
||||||
|
.port_change_mtu = qca8k_port_change_mtu,
|
||||||
|
.port_max_mtu = qca8k_port_max_mtu,
|
||||||
|
.port_stp_state_set = qca8k_port_stp_state_set,
|
||||||
|
+ .port_pre_bridge_flags = qca8k_port_pre_bridge_flags,
|
||||||
|
+ .port_bridge_flags = qca8k_port_bridge_flags,
|
||||||
|
.port_bridge_join = qca8k_port_bridge_join,
|
||||||
|
.port_bridge_leave = qca8k_port_bridge_leave,
|
||||||
|
.port_fast_age = qca8k_port_fast_age,
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-common.c
|
||||||
|
@@ -565,9 +565,26 @@ int qca8k_get_mac_eee(struct dsa_switch
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int qca8k_port_configure_learning(struct dsa_switch *ds, int port,
|
||||||
|
+ bool learning)
|
||||||
|
+{
|
||||||
|
+ struct qca8k_priv *priv = ds->priv;
|
||||||
|
+
|
||||||
|
+ if (learning)
|
||||||
|
+ return regmap_set_bits(priv->regmap,
|
||||||
|
+ QCA8K_PORT_LOOKUP_CTRL(port),
|
||||||
|
+ QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
+ else
|
||||||
|
+ return regmap_clear_bits(priv->regmap,
|
||||||
|
+ QCA8K_PORT_LOOKUP_CTRL(port),
|
||||||
|
+ QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||||
|
{
|
||||||
|
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||||
|
struct qca8k_priv *priv = ds->priv;
|
||||||
|
+ bool learning = false;
|
||||||
|
u32 stp_state;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
@@ -582,8 +599,11 @@ void qca8k_port_stp_state_set(struct dsa
|
||||||
|
break;
|
||||||
|
case BR_STATE_LEARNING:
|
||||||
|
stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
|
||||||
|
+ learning = dp->learning;
|
||||||
|
break;
|
||||||
|
case BR_STATE_FORWARDING:
|
||||||
|
+ learning = dp->learning;
|
||||||
|
+ fallthrough;
|
||||||
|
default:
|
||||||
|
stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
|
||||||
|
break;
|
||||||
|
@@ -591,6 +611,34 @@ void qca8k_port_stp_state_set(struct dsa
|
||||||
|
|
||||||
|
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||||
|
QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
|
||||||
|
+
|
||||||
|
+ qca8k_port_configure_learning(ds, port, learning);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
|
||||||
|
+ struct switchdev_brport_flags flags,
|
||||||
|
+ struct netlink_ext_ack *extack)
|
||||||
|
+{
|
||||||
|
+ if (flags.mask & ~BR_LEARNING)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
|
||||||
|
+ struct switchdev_brport_flags flags,
|
||||||
|
+ struct netlink_ext_ack *extack)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (flags.mask & BR_LEARNING) {
|
||||||
|
+ ret = qca8k_port_configure_learning(ds, port,
|
||||||
|
+ flags.val & BR_LEARNING);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k.h
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||||
|
@@ -448,6 +448,12 @@ int qca8k_get_mac_eee(struct dsa_switch
|
||||||
|
|
||||||
|
/* Common bridge function */
|
||||||
|
void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
|
||||||
|
+int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
|
||||||
|
+ struct switchdev_brport_flags flags,
|
||||||
|
+ struct netlink_ext_ack *extack);
|
||||||
|
+int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
|
||||||
|
+ struct switchdev_brport_flags flags,
|
||||||
|
+ struct netlink_ext_ack *extack);
|
||||||
|
int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
|
||||||
|
struct dsa_bridge bridge,
|
||||||
|
bool *tx_fwd_offload,
|
@ -0,0 +1,53 @@
|
|||||||
|
From 18e8feae4a807994e4906d659116d249bfecd4c5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Sun, 30 Jul 2023 09:41:11 +0200
|
||||||
|
Subject: [PATCH 2/4] net: dsa: qca8k: limit user ports access to the first CPU
|
||||||
|
port on setup
|
||||||
|
|
||||||
|
In preparation for multi-CPU support, set CPU port LOOKUP MEMBER outside
|
||||||
|
the port loop and setup the LOOKUP MEMBER mask for user ports only to
|
||||||
|
the first CPU port.
|
||||||
|
|
||||||
|
This is to handle flooding condition where every CPU port is set as
|
||||||
|
target and prevent packet duplication for unknown frames from user ports.
|
||||||
|
|
||||||
|
Secondary CPU port LOOKUP MEMBER mask will be setup later when
|
||||||
|
port_change_master will be implemented.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Simon Horman <simon.horman@corigine.com>
|
||||||
|
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230730074113.21889-3-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 14 ++++++--------
|
||||||
|
1 file changed, 6 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -1863,18 +1863,16 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
+ /* CPU port gets connected to all user ports of the switch */
|
||||||
|
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
|
||||||
|
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
/* Setup connection between CPU port & user ports
|
||||||
|
* Configure specific switch configuration for ports
|
||||||
|
*/
|
||||||
|
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||||
|
- /* CPU port gets connected to all user ports of the switch */
|
||||||
|
- if (dsa_is_cpu_port(ds, i)) {
|
||||||
|
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
/* Individual user ports get connected to CPU port only */
|
||||||
|
if (dsa_is_user_port(ds, i)) {
|
||||||
|
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
@ -0,0 +1,111 @@
|
|||||||
|
From a9108b0712bf018dc69020864b21485b71b17dfc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Sun, 30 Jul 2023 09:41:12 +0200
|
||||||
|
Subject: [PATCH 3/4] net: dsa: qca8k: move qca8xxx hol fixup to separate
|
||||||
|
function
|
||||||
|
|
||||||
|
Move qca8xxx hol fixup to separate function to tidy things up and to
|
||||||
|
permit using a more efficent loop in future patch.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230730074113.21889-4-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 78 +++++++++++++++++---------------
|
||||||
|
1 file changed, 42 insertions(+), 36 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -1773,6 +1773,46 @@ static int qca8k_connect_tag_protocol(st
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void qca8k_setup_hol_fixup(struct qca8k_priv *priv, int port)
|
||||||
|
+{
|
||||||
|
+ u32 mask;
|
||||||
|
+
|
||||||
|
+ switch (port) {
|
||||||
|
+ /* The 2 CPU port and port 5 requires some different
|
||||||
|
+ * priority than any other ports.
|
||||||
|
+ */
|
||||||
|
+ case 0:
|
||||||
|
+ case 5:
|
||||||
|
+ case 6:
|
||||||
|
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
|
||||||
|
+ }
|
||||||
|
+ regmap_write(priv->regmap, QCA8K_REG_PORT_HOL_CTRL0(port), mask);
|
||||||
|
+
|
||||||
|
+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_WRED_EN;
|
||||||
|
+ regmap_update_bits(priv->regmap, QCA8K_REG_PORT_HOL_CTRL1(port),
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||||
|
+ QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||||
|
+ mask);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int
|
||||||
|
qca8k_setup(struct dsa_switch *ds)
|
||||||
|
{
|
||||||
|
@@ -1908,42 +1948,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
|
* missing settings to improve switch stability under load condition.
|
||||||
|
* This problem is limited to qca8337 and other qca8k switch are not affected.
|
||||||
|
*/
|
||||||
|
- if (priv->switch_id == QCA8K_ID_QCA8337) {
|
||||||
|
- switch (i) {
|
||||||
|
- /* The 2 CPU port and port 5 requires some different
|
||||||
|
- * priority than any other ports.
|
||||||
|
- */
|
||||||
|
- case 0:
|
||||||
|
- case 5:
|
||||||
|
- case 6:
|
||||||
|
- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
|
||||||
|
- break;
|
||||||
|
- default:
|
||||||
|
- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
|
||||||
|
- }
|
||||||
|
- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask);
|
||||||
|
-
|
||||||
|
- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_WRED_EN;
|
||||||
|
- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i),
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||||
|
- QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||||
|
- mask);
|
||||||
|
- }
|
||||||
|
+ if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||||
|
+ qca8k_setup_hol_fixup(priv, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
|
@ -0,0 +1,158 @@
|
|||||||
|
From 01e6f8ad8d26ced14b0cf288c42e55d03a7c5070 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Sun, 30 Jul 2023 09:41:13 +0200
|
||||||
|
Subject: [PATCH 4/4] net: dsa: qca8k: use dsa_for_each macro instead of for
|
||||||
|
loop
|
||||||
|
|
||||||
|
Convert for loop to dsa_for_each macro to save some redundant write on
|
||||||
|
unconnected/unused port and tidy things up.
|
||||||
|
|
||||||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||||
|
Link: https://lore.kernel.org/r/20230730074113.21889-5-ansuelsmth@gmail.com
|
||||||
|
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 107 ++++++++++++++++---------------
|
||||||
|
1 file changed, 54 insertions(+), 53 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -1817,7 +1817,8 @@ static int
|
||||||
|
qca8k_setup(struct dsa_switch *ds)
|
||||||
|
{
|
||||||
|
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||||
|
- int cpu_port, ret, i;
|
||||||
|
+ struct dsa_port *dp;
|
||||||
|
+ int cpu_port, ret;
|
||||||
|
u32 mask;
|
||||||
|
|
||||||
|
cpu_port = qca8k_find_cpu_port(ds);
|
||||||
|
@@ -1868,27 +1869,27 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
|
dev_warn(priv->dev, "mib init failed");
|
||||||
|
|
||||||
|
/* Initial setup of all ports */
|
||||||
|
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||||
|
+ dsa_switch_for_each_port(dp, ds) {
|
||||||
|
/* Disable forwarding by default on all ports */
|
||||||
|
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(dp->index),
|
||||||
|
QCA8K_PORT_LOOKUP_MEMBER, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- /* Enable QCA header mode on all cpu ports */
|
||||||
|
- if (dsa_is_cpu_port(ds, i)) {
|
||||||
|
- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i),
|
||||||
|
- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
|
||||||
|
- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
|
||||||
|
- if (ret) {
|
||||||
|
- dev_err(priv->dev, "failed enabling QCA header mode");
|
||||||
|
- return ret;
|
||||||
|
- }
|
||||||
|
+ /* Disable MAC by default on all user ports */
|
||||||
|
+ dsa_switch_for_each_user_port(dp, ds)
|
||||||
|
+ qca8k_port_set_status(priv, dp->index, 0);
|
||||||
|
+
|
||||||
|
+ /* Enable QCA header mode on all cpu ports */
|
||||||
|
+ dsa_switch_for_each_cpu_port(dp, ds) {
|
||||||
|
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(dp->index),
|
||||||
|
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
|
||||||
|
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
|
||||||
|
+ if (ret) {
|
||||||
|
+ dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index);
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- /* Disable MAC by default on all user ports */
|
||||||
|
- if (dsa_is_user_port(ds, i))
|
||||||
|
- qca8k_port_set_status(priv, i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward all unknown frames to CPU port for Linux processing
|
||||||
|
@@ -1910,48 +1911,48 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Setup connection between CPU port & user ports
|
||||||
|
- * Configure specific switch configuration for ports
|
||||||
|
+ * Individual user ports get connected to CPU port only
|
||||||
|
*/
|
||||||
|
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||||
|
- /* Individual user ports get connected to CPU port only */
|
||||||
|
- if (dsa_is_user_port(ds, i)) {
|
||||||
|
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
- QCA8K_PORT_LOOKUP_MEMBER,
|
||||||
|
- BIT(cpu_port));
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||||
|
- QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- /* For port based vlans to work we need to set the
|
||||||
|
- * default egress vid
|
||||||
|
- */
|
||||||
|
- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
|
||||||
|
- QCA8K_EGREES_VLAN_PORT_MASK(i),
|
||||||
|
- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF));
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
|
||||||
|
- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
|
||||||
|
- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
- }
|
||||||
|
+ dsa_switch_for_each_user_port(dp, ds) {
|
||||||
|
+ u8 port = dp->index;
|
||||||
|
|
||||||
|
- /* The port 5 of the qca8337 have some problem in flood condition. The
|
||||||
|
- * original legacy driver had some specific buffer and priority settings
|
||||||
|
- * for the different port suggested by the QCA switch team. Add this
|
||||||
|
- * missing settings to improve switch stability under load condition.
|
||||||
|
- * This problem is limited to qca8337 and other qca8k switch are not affected.
|
||||||
|
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||||
|
+ QCA8K_PORT_LOOKUP_MEMBER,
|
||||||
|
+ BIT(cpu_port));
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||||
|
+ QCA8K_PORT_LOOKUP_LEARN);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ /* For port based vlans to work we need to set the
|
||||||
|
+ * default egress vid
|
||||||
|
*/
|
||||||
|
- if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||||
|
- qca8k_setup_hol_fixup(priv, i);
|
||||||
|
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
|
||||||
|
+ QCA8K_EGREES_VLAN_PORT_MASK(port),
|
||||||
|
+ QCA8K_EGREES_VLAN_PORT(port, QCA8K_PORT_VID_DEF));
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
|
||||||
|
+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
|
||||||
|
+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* The port 5 of the qca8337 have some problem in flood condition. The
|
||||||
|
+ * original legacy driver had some specific buffer and priority settings
|
||||||
|
+ * for the different port suggested by the QCA switch team. Add this
|
||||||
|
+ * missing settings to improve switch stability under load condition.
|
||||||
|
+ * This problem is limited to qca8337 and other qca8k switch are not affected.
|
||||||
|
+ */
|
||||||
|
+ if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||||
|
+ dsa_switch_for_each_available_port(dp, ds)
|
||||||
|
+ qca8k_setup_hol_fixup(priv, dp->index);
|
||||||
|
+
|
||||||
|
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
|
||||||
|
if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||||
|
mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
|
@ -20,7 +20,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
@@ -719,21 +719,6 @@ err_clear_skb:
|
@@ -778,21 +778,6 @@ err_clear_skb:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
{
|
{
|
||||||
--- a/drivers/net/dsa/qca/qca8k.h
|
--- a/drivers/net/dsa/qca/qca8k.h
|
||||||
+++ b/drivers/net/dsa/qca/qca8k.h
|
+++ b/drivers/net/dsa/qca/qca8k.h
|
||||||
@@ -422,6 +422,20 @@ struct qca8k_fdb {
|
@@ -421,6 +421,20 @@ struct qca8k_fdb {
|
||||||
u8 mac[6];
|
u8 mac[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
||||||
@@ -1729,6 +1730,10 @@ qca8k_setup(struct dsa_switch *ds)
|
@@ -1829,6 +1830,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -386,7 +386,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
#define QCA8K_GOL_MAC_ADDR0 0x60
|
#define QCA8K_GOL_MAC_ADDR0 0x60
|
||||||
#define QCA8K_GOL_MAC_ADDR1 0x64
|
#define QCA8K_GOL_MAC_ADDR1 0x64
|
||||||
#define QCA8K_MAX_FRAME_SIZE 0x78
|
#define QCA8K_MAX_FRAME_SIZE 0x78
|
||||||
@@ -383,6 +429,19 @@ struct qca8k_pcs {
|
@@ -382,6 +428,19 @@ struct qca8k_pcs {
|
||||||
int port;
|
int port;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
struct qca8k_priv {
|
struct qca8k_priv {
|
||||||
u8 switch_id;
|
u8 switch_id;
|
||||||
u8 switch_revision;
|
u8 switch_revision;
|
||||||
@@ -407,6 +466,7 @@ struct qca8k_priv {
|
@@ -406,6 +465,7 @@ struct qca8k_priv {
|
||||||
struct qca8k_pcs pcs_port_0;
|
struct qca8k_pcs pcs_port_0;
|
||||||
struct qca8k_pcs pcs_port_6;
|
struct qca8k_pcs pcs_port_6;
|
||||||
const struct qca8k_match_data *info;
|
const struct qca8k_match_data *info;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user