kernel: 5.10: backport qca8k stability improvements
This is a backport of Ansuel Smith's "Multiple improvement to qca8k stability" series. The QCA8337 switch is available on multiple platforms including ipq806x, ath79 and bcm53xx. Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
This commit is contained in:
parent
6a1284cfa8
commit
e3c47ff90d
26 changed files with 2660 additions and 5 deletions
|
@ -0,0 +1,35 @@
|
|||
From 5d9e068402dcf7354cc8ee66c2152845306d2ccb Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:51 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: change simple print to dev variant
|
||||
|
||||
Change pr_err and pr_warn to dev variant.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -701,7 +701,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
|
||||
/* Make sure that port 0 is the cpu port */
|
||||
if (!dsa_is_cpu_port(ds, 0)) {
|
||||
- pr_err("port 0 is not the CPU port\n");
|
||||
+ dev_err(priv->dev, "port 0 is not the CPU port");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -711,7 +711,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
priv->regmap = devm_regmap_init(ds->dev, NULL, priv,
|
||||
&qca8k_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
- pr_warn("regmap initialization failed");
|
||||
+ dev_warn(priv->dev, "regmap initialization failed");
|
||||
|
||||
ret = qca8k_setup_mdio_bus(priv);
|
||||
if (ret)
|
|
@ -0,0 +1,61 @@
|
|||
From 2ad255f2faaffb3af786031fba2e7955454b558a Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:52 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: use iopoll macro for qca8k_busy_wait
|
||||
|
||||
Use iopoll macro instead of while loop.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 23 +++++++++++------------
|
||||
drivers/net/dsa/qca8k.h | 2 ++
|
||||
2 files changed, 13 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -262,21 +262,20 @@ static struct regmap_config qca8k_regmap
|
||||
static int
|
||||
qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
- unsigned long timeout;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
|
||||
- timeout = jiffies + msecs_to_jiffies(20);
|
||||
+ ret = read_poll_timeout(qca8k_read, val, !(val & mask),
|
||||
+ 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
|
||||
+ priv, reg);
|
||||
|
||||
- /* loop until the busy flag has cleared */
|
||||
- do {
|
||||
- u32 val = qca8k_read(priv, reg);
|
||||
- int busy = val & mask;
|
||||
+ /* Check if qca8k_read has failed for a different reason
|
||||
+ * before returning -ETIMEDOUT
|
||||
+ */
|
||||
+ if (ret < 0 && val < 0)
|
||||
+ return val;
|
||||
|
||||
- if (!busy)
|
||||
- break;
|
||||
- cond_resched();
|
||||
- } while (!time_after_eq(jiffies, timeout));
|
||||
-
|
||||
- return time_after_eq(jiffies, timeout);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -18,6 +18,8 @@
|
||||
#define PHY_ID_QCA8337 0x004dd036
|
||||
#define QCA8K_ID_QCA8337 0x13
|
||||
|
||||
+#define QCA8K_BUSY_WAIT_TIMEOUT 20
|
||||
+
|
||||
#define QCA8K_NUM_FDB_RECORDS 2048
|
||||
|
||||
#define QCA8K_CPU_PORT 0
|
|
@ -0,0 +1,86 @@
|
|||
From 504bf65931824eda83494e5b5d75686e27ace03e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:53 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: improve qca8k read/write/rmw bus access
|
||||
|
||||
Put bus in local variable to improve faster access to the mdio bus.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 29 ++++++++++++++++-------------
|
||||
1 file changed, 16 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -142,17 +142,18 @@ qca8k_set_page(struct mii_bus *bus, u16
|
||||
static u32
|
||||
qca8k_read(struct qca8k_priv *priv, u32 reg)
|
||||
{
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(priv->bus, page);
|
||||
- val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
|
||||
+ qca8k_set_page(bus, page);
|
||||
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
+ mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -160,35 +161,37 @@ qca8k_read(struct qca8k_priv *priv, u32
|
||||
static void
|
||||
qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
{
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(priv->bus, page);
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_set_page(bus, page);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
+ mutex_unlock(&bus->mdio_lock);
|
||||
}
|
||||
|
||||
static u32
|
||||
qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 val)
|
||||
{
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 ret;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(priv->bus, page);
|
||||
- ret = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
|
||||
+ qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
ret &= ~mask;
|
||||
ret |= val;
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, ret);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, ret);
|
||||
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
+ mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
From ba5707ec58cfb6853dff41c2aae72deb6a03d389 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:54 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: handle qca8k_set_page errors
|
||||
|
||||
With a remote possibility, the set_page function can fail. Since this is
|
||||
a critical part of the write/read qca8k regs, propagate the error and
|
||||
terminate any read/write operation.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 33 ++++++++++++++++++++++++++-------
|
||||
1 file changed, 26 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -127,16 +127,23 @@ qca8k_mii_write32(struct mii_bus *bus, i
|
||||
"failed to write qca8k 32bit register\n");
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_set_page(struct mii_bus *bus, u16 page)
|
||||
{
|
||||
+ int ret;
|
||||
+
|
||||
if (page == qca8k_current_page)
|
||||
- return;
|
||||
+ return 0;
|
||||
|
||||
- if (bus->write(bus, 0x18, 0, page) < 0)
|
||||
+ ret = bus->write(bus, 0x18, 0, page);
|
||||
+ if (ret < 0) {
|
||||
dev_err_ratelimited(&bus->dev,
|
||||
"failed to set qca8k page\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
qca8k_current_page = page;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
@@ -150,11 +157,14 @@ qca8k_read(struct qca8k_priv *priv, u32
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(bus, page);
|
||||
+ val = qca8k_set_page(bus, page);
|
||||
+ if (val < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
val = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
|
||||
+exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
-
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -163,14 +173,19 @@ qca8k_write(struct qca8k_priv *priv, u32
|
||||
{
|
||||
struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
+ int ret;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(bus, page);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
|
||||
+exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
}
|
||||
|
||||
@@ -185,12 +200,16 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(bus, page);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
ret = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
ret &= ~mask;
|
||||
ret |= val;
|
||||
qca8k_mii_write32(bus, 0x10 | r2, r1, ret);
|
||||
|
||||
+exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return ret;
|
|
@ -0,0 +1,207 @@
|
|||
From 028f5f8ef44fcf87a456772cbb9f0d90a0a22884 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:55 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: handle error with qca8k_read operation
|
||||
|
||||
qca8k_read can fail. Rework any user to handle error values and
|
||||
correctly return.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 73 ++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 58 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -231,8 +231,13 @@ static int
|
||||
qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_read(priv, reg);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
|
||||
- *val = qca8k_read(priv, reg);
|
||||
+ *val = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -300,15 +305,20 @@ qca8k_busy_wait(struct qca8k_priv *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
|
||||
{
|
||||
- u32 reg[4];
|
||||
+ u32 reg[4], val;
|
||||
int i;
|
||||
|
||||
/* load the ARL table into an array */
|
||||
- for (i = 0; i < 4; i++)
|
||||
- reg[i] = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4));
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ val = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4));
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ reg[i] = val;
|
||||
+ }
|
||||
|
||||
/* vid - 83:72 */
|
||||
fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M;
|
||||
@@ -323,6 +333,8 @@ qca8k_fdb_read(struct qca8k_priv *priv,
|
||||
fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff;
|
||||
fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff;
|
||||
fdb->mac[5] = reg[0] & 0xff;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -374,6 +386,8 @@ qca8k_fdb_access(struct qca8k_priv *priv
|
||||
/* Check for table full violation when adding an entry */
|
||||
if (cmd == QCA8K_FDB_LOAD) {
|
||||
reg = qca8k_read(priv, QCA8K_REG_ATU_FUNC);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
if (reg & QCA8K_ATU_FUNC_FULL)
|
||||
return -1;
|
||||
}
|
||||
@@ -388,10 +402,10 @@ qca8k_fdb_next(struct qca8k_priv *priv,
|
||||
|
||||
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
|
||||
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
|
||||
- if (ret >= 0)
|
||||
- qca8k_fdb_read(priv, fdb);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
|
||||
- return ret;
|
||||
+ return qca8k_fdb_read(priv, fdb);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -449,6 +463,8 @@ qca8k_vlan_access(struct qca8k_priv *pri
|
||||
/* Check for table full violation when adding an entry */
|
||||
if (cmd == QCA8K_VLAN_LOAD) {
|
||||
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC1);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
if (reg & QCA8K_VTU_FUNC1_FULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -475,6 +491,8 @@ qca8k_vlan_add(struct qca8k_priv *priv,
|
||||
goto out;
|
||||
|
||||
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
|
||||
reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port));
|
||||
if (untagged)
|
||||
@@ -506,6 +524,8 @@ qca8k_vlan_del(struct qca8k_priv *priv,
|
||||
goto out;
|
||||
|
||||
reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port));
|
||||
reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT <<
|
||||
QCA8K_VTU_FUNC0_EG_MODE_S(port);
|
||||
@@ -621,8 +641,11 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
QCA8K_MDIO_MASTER_BUSY))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
- val = (qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL) &
|
||||
- QCA8K_MDIO_MASTER_DATA_MASK);
|
||||
+ val = qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -978,6 +1001,8 @@ qca8k_phylink_mac_link_state(struct dsa_
|
||||
u32 reg;
|
||||
|
||||
reg = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port));
|
||||
+ if (reg < 0)
|
||||
+ return reg;
|
||||
|
||||
state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP);
|
||||
state->an_complete = state->link;
|
||||
@@ -1078,18 +1103,26 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
const struct qca8k_mib_desc *mib;
|
||||
- u32 reg, i;
|
||||
+ u32 reg, i, val;
|
||||
u64 hi;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) {
|
||||
mib = &ar8327_mib[i];
|
||||
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
|
||||
|
||||
- data[i] = qca8k_read(priv, reg);
|
||||
+ val = qca8k_read(priv, reg);
|
||||
+ if (val < 0)
|
||||
+ continue;
|
||||
+
|
||||
if (mib->size == 2) {
|
||||
hi = qca8k_read(priv, reg + 4);
|
||||
- data[i] |= hi << 32;
|
||||
+ if (hi < 0)
|
||||
+ continue;
|
||||
}
|
||||
+
|
||||
+ data[i] = val;
|
||||
+ if (mib->size == 2)
|
||||
+ data[i] |= hi << 32;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1107,18 +1140,25 @@ qca8k_set_mac_eee(struct dsa_switch *ds,
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
|
||||
+ int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
reg = qca8k_read(priv, QCA8K_REG_EEE_CTRL);
|
||||
+ if (reg < 0) {
|
||||
+ ret = reg;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
if (eee->eee_enabled)
|
||||
reg |= lpi_en;
|
||||
else
|
||||
reg &= ~lpi_en;
|
||||
qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
|
||||
- mutex_unlock(&priv->reg_mutex);
|
||||
|
||||
- return 0;
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1456,6 +1496,9 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
|
||||
/* read the switches ID register */
|
||||
id = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
|
||||
+ if (id < 0)
|
||||
+ return id;
|
||||
+
|
||||
id >>= QCA8K_MASK_CTRL_ID_S;
|
||||
id &= QCA8K_MASK_CTRL_ID_M;
|
||||
if (id != QCA8K_ID_QCA8337)
|
|
@ -0,0 +1,263 @@
|
|||
From d7805757c75c76e9518fc1023a29f0c4eed5b581 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:56 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: handle error with qca8k_write operation
|
||||
|
||||
qca8k_write can fail. Rework any user to handle error values and
|
||||
correctly return.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 102 ++++++++++++++++++++++++++--------------
|
||||
1 file changed, 67 insertions(+), 35 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -168,7 +168,7 @@ exit:
|
||||
return val;
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
{
|
||||
struct mii_bus *bus = priv->bus;
|
||||
@@ -187,6 +187,7 @@ qca8k_write(struct qca8k_priv *priv, u32
|
||||
|
||||
exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static u32
|
||||
@@ -247,9 +248,7 @@ qca8k_regmap_write(void *ctx, uint32_t r
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
|
||||
- qca8k_write(priv, reg, val);
|
||||
-
|
||||
- return 0;
|
||||
+ return qca8k_write(priv, reg, val);
|
||||
}
|
||||
|
||||
static const struct regmap_range qca8k_readable_ranges[] = {
|
||||
@@ -367,6 +366,7 @@ static int
|
||||
qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
|
||||
{
|
||||
u32 reg;
|
||||
+ int ret;
|
||||
|
||||
/* Set the command and FDB index */
|
||||
reg = QCA8K_ATU_FUNC_BUSY;
|
||||
@@ -377,7 +377,9 @@ qca8k_fdb_access(struct qca8k_priv *priv
|
||||
}
|
||||
|
||||
/* Write the function register triggering the table access */
|
||||
- qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* wait for completion */
|
||||
if (qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY))
|
||||
@@ -447,6 +449,7 @@ static int
|
||||
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
|
||||
{
|
||||
u32 reg;
|
||||
+ int ret;
|
||||
|
||||
/* Set the command and VLAN index */
|
||||
reg = QCA8K_VTU_FUNC1_BUSY;
|
||||
@@ -454,7 +457,9 @@ qca8k_vlan_access(struct qca8k_priv *pri
|
||||
reg |= vid << QCA8K_VTU_FUNC1_VID_S;
|
||||
|
||||
/* Write the function register triggering the table access */
|
||||
- qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* wait for completion */
|
||||
if (qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY))
|
||||
@@ -502,7 +507,9 @@ qca8k_vlan_add(struct qca8k_priv *priv,
|
||||
reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG <<
|
||||
QCA8K_VTU_FUNC0_EG_MODE_S(port);
|
||||
|
||||
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
|
||||
out:
|
||||
@@ -545,7 +552,9 @@ qca8k_vlan_del(struct qca8k_priv *priv,
|
||||
if (del) {
|
||||
ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
|
||||
} else {
|
||||
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
|
||||
}
|
||||
|
||||
@@ -555,15 +564,20 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_mib_init(struct qca8k_priv *priv)
|
||||
{
|
||||
+ int ret;
|
||||
+
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
- qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
|
||||
+
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
|
||||
+
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -600,6 +614,7 @@ static int
|
||||
qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
|
||||
{
|
||||
u32 phy, val;
|
||||
+ int ret;
|
||||
|
||||
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
|
||||
return -EINVAL;
|
||||
@@ -613,7 +628,9 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
|
||||
QCA8K_MDIO_MASTER_DATA(data);
|
||||
|
||||
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
+ ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
@@ -623,6 +640,7 @@ static int
|
||||
qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
|
||||
{
|
||||
u32 phy, val;
|
||||
+ int ret;
|
||||
|
||||
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
|
||||
return -EINVAL;
|
||||
@@ -635,7 +653,9 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum);
|
||||
|
||||
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
+ ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY))
|
||||
@@ -766,12 +786,18 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
|
||||
/* Enable MIB counters */
|
||||
- qca8k_mib_init(priv);
|
||||
+ ret = qca8k_mib_init(priv);
|
||||
+ if (ret)
|
||||
+ dev_warn(priv->dev, "mib init failed");
|
||||
|
||||
/* Enable QCA header mode on the cpu port */
|
||||
- qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
|
||||
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->dev, "failed enabling QCA header mode");
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
/* Disable forwarding by default on all ports */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
@@ -783,11 +809,13 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
qca8k_port_set_status(priv, i, 0);
|
||||
|
||||
/* Forward all unknown frames to CPU port for Linux processing */
|
||||
- qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
|
||||
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
|
||||
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* Setup connection between CPU port & user ports */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
@@ -815,16 +843,20 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
|
||||
0xfff << shift,
|
||||
QCA8K_PORT_VID_DEF << shift);
|
||||
- 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));
|
||||
+ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup our port MTUs to match power on defaults */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
|
||||
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
|
||||
+ if (ret)
|
||||
+ dev_warn(priv->dev, "failed setting MTU settings");
|
||||
|
||||
/* Flush the FDB table */
|
||||
qca8k_fdb_flush(priv);
|
||||
@@ -1140,8 +1172,8 @@ qca8k_set_mac_eee(struct dsa_switch *ds,
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
|
||||
- int ret = 0;
|
||||
u32 reg;
|
||||
+ int ret;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
reg = qca8k_read(priv, QCA8K_REG_EEE_CTRL);
|
||||
@@ -1154,7 +1186,7 @@ qca8k_set_mac_eee(struct dsa_switch *ds,
|
||||
reg |= lpi_en;
|
||||
else
|
||||
reg &= ~lpi_en;
|
||||
- qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
@@ -1284,9 +1316,7 @@ qca8k_port_change_mtu(struct dsa_switch
|
||||
mtu = priv->port_mtu[i];
|
||||
|
||||
/* Include L2 header / FCS length */
|
||||
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
-
|
||||
- return 0;
|
||||
+ return qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
}
|
||||
|
||||
static int
|
|
@ -0,0 +1,226 @@
|
|||
From aaf421425cbdec4eb6fd75a29e65c2867b0b7bbd Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:57 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: handle error with qca8k_rmw operation
|
||||
|
||||
qca8k_rmw can fail. Rework any user to handle error values and
|
||||
correctly return. Change qca8k_rmw to return the error code or 0 instead
|
||||
of the reg value. The reg returned by qca8k_rmw wasn't used anywhere,
|
||||
so this doesn't cause any functional change.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 133 +++++++++++++++++++++++++---------------
|
||||
1 file changed, 83 insertions(+), 50 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -190,12 +190,13 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static u32
|
||||
-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 val)
|
||||
+static int
|
||||
+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
{
|
||||
struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
- u32 ret;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
@@ -205,10 +206,15 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
- ret = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
- ret &= ~mask;
|
||||
- ret |= val;
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, ret);
|
||||
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
+ if (val < 0) {
|
||||
+ ret = val;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ val &= ~mask;
|
||||
+ val |= write_val;
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
@@ -216,16 +222,16 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
{
|
||||
- qca8k_rmw(priv, reg, 0, val);
|
||||
+ return qca8k_rmw(priv, reg, 0, val);
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
{
|
||||
- qca8k_rmw(priv, reg, val, 0);
|
||||
+ return qca8k_rmw(priv, reg, val, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -570,12 +576,19 @@ qca8k_mib_init(struct qca8k_priv *priv)
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
+
|
||||
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
|
||||
ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
|
||||
|
||||
+exit:
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
return ret;
|
||||
}
|
||||
@@ -747,9 +760,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
* a dt-overlay and driver reload changed the configuration
|
||||
*/
|
||||
|
||||
- qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_EN);
|
||||
- return 0;
|
||||
+ return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_EN);
|
||||
}
|
||||
|
||||
priv->ops.phy_read = qca8k_phy_read;
|
||||
@@ -782,8 +794,12 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
return ret;
|
||||
|
||||
/* Enable CPU Port */
|
||||
- qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
+ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->dev, "failed enabling CPU port");
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
/* Enable MIB counters */
|
||||
ret = qca8k_mib_init(priv);
|
||||
@@ -800,9 +816,12 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
}
|
||||
|
||||
/* Disable forwarding by default on all ports */
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, 0);
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER, 0);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
/* Disable MAC by default on all ports */
|
||||
for (i = 1; i < QCA8K_NUM_PORTS; i++)
|
||||
@@ -821,28 +840,37 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
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)) {
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
|
||||
+ 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)) {
|
||||
int shift = 16 * (i % 2);
|
||||
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER,
|
||||
- BIT(QCA8K_CPU_PORT));
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER,
|
||||
+ BIT(QCA8K_CPU_PORT));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* Enable ARP Auto-learning by default */
|
||||
- qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- QCA8K_PORT_LOOKUP_LEARN);
|
||||
+ ret = qca8k_reg_set(priv, 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
|
||||
*/
|
||||
- qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
|
||||
- 0xfff << shift,
|
||||
- QCA8K_PORT_VID_DEF << shift);
|
||||
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
|
||||
+ 0xfff << shift,
|
||||
+ QCA8K_PORT_VID_DEF << shift);
|
||||
+ 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));
|
||||
@@ -1234,7 +1262,7 @@ qca8k_port_bridge_join(struct dsa_switch
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
int port_mask = BIT(QCA8K_CPU_PORT);
|
||||
- int i;
|
||||
+ int i, ret;
|
||||
|
||||
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
|
||||
if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
@@ -1242,17 +1270,20 @@ qca8k_port_bridge_join(struct dsa_switch
|
||||
/* Add this port to the portvlan mask of the other ports
|
||||
* in the bridge
|
||||
*/
|
||||
- qca8k_reg_set(priv,
|
||||
- QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- BIT(port));
|
||||
+ ret = qca8k_reg_set(priv,
|
||||
+ QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ BIT(port));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
if (i != port)
|
||||
port_mask |= BIT(i);
|
||||
}
|
||||
+
|
||||
/* Add all other ports to this ports portvlan mask */
|
||||
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
|
||||
|
||||
- return 0;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void
|
|
@ -0,0 +1,66 @@
|
|||
From b7c818d194927bdc60ed15db55bb8654496a36b7 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:58 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: handle error from qca8k_busy_wait
|
||||
|
||||
Propagate errors from qca8k_busy_wait instead of hardcoding return
|
||||
value.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 21 +++++++++++++--------
|
||||
1 file changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -388,8 +388,9 @@ qca8k_fdb_access(struct qca8k_priv *priv
|
||||
return ret;
|
||||
|
||||
/* wait for completion */
|
||||
- if (qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY))
|
||||
- return -1;
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* Check for table full violation when adding an entry */
|
||||
if (cmd == QCA8K_FDB_LOAD) {
|
||||
@@ -468,8 +469,9 @@ qca8k_vlan_access(struct qca8k_priv *pri
|
||||
return ret;
|
||||
|
||||
/* wait for completion */
|
||||
- if (qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY))
|
||||
- return -ETIMEDOUT;
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
/* Check for table full violation when adding an entry */
|
||||
if (cmd == QCA8K_VLAN_LOAD) {
|
||||
@@ -580,7 +582,9 @@ qca8k_mib_init(struct qca8k_priv *priv)
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
|
||||
ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
if (ret)
|
||||
@@ -670,9 +674,10 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_BUSY))
|
||||
- return -ETIMEDOUT;
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_BUSY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
val = qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL);
|
||||
if (val < 0)
|
|
@ -0,0 +1,96 @@
|
|||
From 6e82a457e06252b59102486767539cc9c2aba60b Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 22:59:59 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add support for qca8327 switch
|
||||
|
||||
qca8327 switch is a low tier version of the more recent qca8337.
|
||||
It does share the same regs used by the qca8k driver and can be
|
||||
supported with minimal change.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 23 ++++++++++++++++++++---
|
||||
drivers/net/dsa/qca8k.h | 6 ++++++
|
||||
2 files changed, 26 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1533,6 +1533,7 @@ static const struct dsa_switch_ops qca8k
|
||||
static int
|
||||
qca8k_sw_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
+ const struct qca8k_match_data *data;
|
||||
struct qca8k_priv *priv;
|
||||
u32 id;
|
||||
|
||||
@@ -1560,6 +1561,11 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
gpiod_set_value_cansleep(priv->reset_gpio, 0);
|
||||
}
|
||||
|
||||
+ /* get the switches ID from the compatible */
|
||||
+ data = of_device_get_match_data(&mdiodev->dev);
|
||||
+ if (!data)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
/* read the switches ID register */
|
||||
id = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
|
||||
if (id < 0)
|
||||
@@ -1567,8 +1573,10 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
|
||||
id >>= QCA8K_MASK_CTRL_ID_S;
|
||||
id &= QCA8K_MASK_CTRL_ID_M;
|
||||
- if (id != QCA8K_ID_QCA8337)
|
||||
+ if (id != data->id) {
|
||||
+ dev_err(&mdiodev->dev, "Switch id detected %x but expected %x", id, data->id);
|
||||
return -ENODEV;
|
||||
+ }
|
||||
|
||||
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
|
||||
if (!priv->ds)
|
||||
@@ -1634,9 +1642,18 @@ static int qca8k_resume(struct device *d
|
||||
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||
qca8k_suspend, qca8k_resume);
|
||||
|
||||
+static const struct qca8k_match_data qca832x = {
|
||||
+ .id = QCA8K_ID_QCA8327,
|
||||
+};
|
||||
+
|
||||
+static const struct qca8k_match_data qca833x = {
|
||||
+ .id = QCA8K_ID_QCA8337,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id qca8k_of_match[] = {
|
||||
- { .compatible = "qca,qca8334" },
|
||||
- { .compatible = "qca,qca8337" },
|
||||
+ { .compatible = "qca,qca8327", .data = &qca832x },
|
||||
+ { .compatible = "qca,qca8334", .data = &qca833x },
|
||||
+ { .compatible = "qca,qca8337", .data = &qca833x },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -15,6 +15,8 @@
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
#define QCA8K_MAX_MTU 9000
|
||||
|
||||
+#define PHY_ID_QCA8327 0x004dd034
|
||||
+#define QCA8K_ID_QCA8327 0x12
|
||||
#define PHY_ID_QCA8337 0x004dd036
|
||||
#define QCA8K_ID_QCA8337 0x13
|
||||
|
||||
@@ -213,6 +215,10 @@ struct ar8xxx_port_status {
|
||||
int enabled;
|
||||
};
|
||||
|
||||
+struct qca8k_match_data {
|
||||
+ u8 id;
|
||||
+};
|
||||
+
|
||||
struct qca8k_priv {
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
|
@ -0,0 +1,26 @@
|
|||
From 227a9ffc1bc77037339530607fe129af3824620e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:00 +0200
|
||||
Subject: [PATCH] devicetree: net: dsa: qca8k: Document new compatible qca8327
|
||||
|
||||
Add support for qca8327 in the compatible list.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -3,6 +3,7 @@
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of:
|
||||
+ "qca,qca8327"
|
||||
"qca,qca8334"
|
||||
"qca,qca8337"
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
From 83a3ceb39b2495171aabe9446271b94c678354f3 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:01 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add priority tweak to qca8337 switch
|
||||
|
||||
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.
|
||||
The packet priority tweak is only needed for the qca8337 switch and
|
||||
other qca8k switch are not affected.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 47 +++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 25 ++++++++++++++++++++++
|
||||
2 files changed, 72 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -779,6 +779,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
int ret, i;
|
||||
+ u32 mask;
|
||||
|
||||
/* Make sure that port 0 is the cpu port */
|
||||
if (!dsa_is_cpu_port(ds, 0)) {
|
||||
@@ -884,6 +885,51 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* 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) {
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ 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 |
|
||||
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||
+ QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||
+ mask);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Setup our port MTUs to match power on defaults */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
@@ -1578,6 +1624,7 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
+ priv->switch_id = id;
|
||||
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
|
||||
if (!priv->ds)
|
||||
return -ENOMEM;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -168,6 +168,30 @@
|
||||
#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
|
||||
+#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24)
|
||||
+
|
||||
+#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
|
||||
+
|
||||
/* Pkt edit registers */
|
||||
#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2)))
|
||||
|
||||
@@ -220,6 +244,7 @@ struct qca8k_match_data {
|
||||
};
|
||||
|
||||
struct qca8k_priv {
|
||||
+ u8 switch_id;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
|
@ -0,0 +1,31 @@
|
|||
From 5bf9ff3b9fb5ecb67a1a3517b26db3a00f2a2f11 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:02 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: limit port5 delay to qca8337
|
||||
|
||||
Limit port5 rx delay to qca8337. This is taken from the legacy QSDK code
|
||||
that limits the rx delay on port5 to only this particular switch version,
|
||||
on other switch only the tx and rx delay for port0 are needed.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1003,8 +1003,10 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
QCA8K_PORT_PAD_RGMII_EN |
|
||||
QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
|
||||
QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
|
||||
- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||||
- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||||
+ /* QCA8337 requires to set rgmii rx delay */
|
||||
+ if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||
+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
|
@ -0,0 +1,48 @@
|
|||
From 0fc57e4b5e39461fc0a54aae0afe4241363a7267 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:03 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add GLOBAL_FC settings needed for qca8327
|
||||
|
||||
Switch qca8327 needs special settings for the GLOBAL_FC_THRES regs.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 10 ++++++++++
|
||||
drivers/net/dsa/qca8k.h | 6 ++++++
|
||||
2 files changed, 16 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -930,6 +930,16 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* 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) |
|
||||
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);
|
||||
+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH,
|
||||
+ QCA8K_GLOBAL_FC_GOL_XON_THRES_S |
|
||||
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S,
|
||||
+ mask);
|
||||
+ }
|
||||
+
|
||||
/* Setup our port MTUs to match power on defaults */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -168,6 +168,12 @@
|
||||
#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
|
||||
+#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0)
|
||||
+
|
||||
#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8)
|
||||
#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0)
|
||||
#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0)
|
|
@ -0,0 +1,114 @@
|
|||
From 95ffeaf18b3bb90eeef52cbf7d79ccc9d0345ff5 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:04 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add support for switch rev
|
||||
|
||||
qca8k internal phy driver require some special debug value to be set
|
||||
based on the switch revision. Rework the switch id read function to
|
||||
also read the chip revision.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 53 ++++++++++++++++++++++++++---------------
|
||||
drivers/net/dsa/qca8k.h | 7 ++++--
|
||||
2 files changed, 39 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1588,12 +1588,40 @@ static const struct dsa_switch_ops qca8k
|
||||
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
|
||||
};
|
||||
|
||||
+static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ const struct qca8k_match_data *data;
|
||||
+ u32 val;
|
||||
+ u8 id;
|
||||
+
|
||||
+ /* get the switches ID from the compatible */
|
||||
+ data = of_device_get_match_data(priv->dev);
|
||||
+ if (!data)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ val = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
|
||||
+ if (val < 0)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK);
|
||||
+ if (id != data->id) {
|
||||
+ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ priv->switch_id = id;
|
||||
+
|
||||
+ /* Save revision to communicate to the internal PHY driver */
|
||||
+ priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_sw_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
- const struct qca8k_match_data *data;
|
||||
struct qca8k_priv *priv;
|
||||
- u32 id;
|
||||
+ int ret;
|
||||
|
||||
/* allocate the private data struct so that we can probe the switches
|
||||
* ID register
|
||||
@@ -1619,24 +1647,11 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
gpiod_set_value_cansleep(priv->reset_gpio, 0);
|
||||
}
|
||||
|
||||
- /* get the switches ID from the compatible */
|
||||
- data = of_device_get_match_data(&mdiodev->dev);
|
||||
- if (!data)
|
||||
- return -ENODEV;
|
||||
+ /* Check the detected switch id */
|
||||
+ ret = qca8k_read_switch_id(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
- /* read the switches ID register */
|
||||
- id = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
|
||||
- if (id < 0)
|
||||
- return id;
|
||||
-
|
||||
- id >>= QCA8K_MASK_CTRL_ID_S;
|
||||
- id &= QCA8K_MASK_CTRL_ID_M;
|
||||
- if (id != data->id) {
|
||||
- dev_err(&mdiodev->dev, "Switch id detected %x but expected %x", id, data->id);
|
||||
- return -ENODEV;
|
||||
- }
|
||||
-
|
||||
- priv->switch_id = id;
|
||||
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
|
||||
if (!priv->ds)
|
||||
return -ENOMEM;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -30,8 +30,10 @@
|
||||
|
||||
/* Global control registers */
|
||||
#define QCA8K_REG_MASK_CTRL 0x000
|
||||
-#define QCA8K_MASK_CTRL_ID_M 0xff
|
||||
-#define QCA8K_MASK_CTRL_ID_S 8
|
||||
+#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0)
|
||||
+#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0)
|
||||
+#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
|
||||
+#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
|
||||
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
@@ -251,6 +253,7 @@ struct qca8k_match_data {
|
||||
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
+ u8 switch_revision;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
|
@ -0,0 +1,28 @@
|
|||
From 1ee0591a1093c2448642c33433483e9260275f7b Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:05 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add ethernet-ports fallback to
|
||||
setup_mdio_bus
|
||||
|
||||
Dsa now also supports ethernet-ports. Add this new binding as a fallback
|
||||
if the ports node can't be found.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -719,6 +719,9 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
|
||||
ports = of_get_child_by_name(priv->dev->of_node, "ports");
|
||||
if (!ports)
|
||||
+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports");
|
||||
+
|
||||
+ if (!ports)
|
||||
return -EINVAL;
|
||||
|
||||
for_each_available_child_of_node(ports, port) {
|
|
@ -0,0 +1,188 @@
|
|||
From e4b9977cee1583da38a6e9118078bb728aaccf7b Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:06 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: make rgmii delay configurable
|
||||
|
||||
The legacy qsdk code used a different delay instead of the max value.
|
||||
Qsdk use 1 ns for rx and 2 ns for tx. Make these values configurable
|
||||
using the standard rx/tx-internal-delay-ps ethernet binding and apply
|
||||
qsdk values by default. The connected gmac doesn't add any delay so no
|
||||
additional delay is added to tx/rx.
|
||||
On this switch the delay is actually in ns so value should be in the
|
||||
1000 order. Any value converted from ps to ns by dividing it by 1000
|
||||
as the switch max value for delay is 3ns.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 82 ++++++++++++++++++++++++++++++++++++++++-
|
||||
drivers/net/dsa/qca8k.h | 11 +++---
|
||||
2 files changed, 86 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -778,6 +778,68 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ struct device_node *port_dn;
|
||||
+ phy_interface_t mode;
|
||||
+ struct dsa_port *dp;
|
||||
+ u32 val;
|
||||
+
|
||||
+ /* CPU port is already checked */
|
||||
+ dp = dsa_to_port(priv->ds, 0);
|
||||
+
|
||||
+ port_dn = dp->dn;
|
||||
+
|
||||
+ /* Check if port 0 is set to the correct type */
|
||||
+ of_get_phy_mode(port_dn, &mode);
|
||||
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
+ mode != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
+ mode != PHY_INTERFACE_MODE_RGMII_TXID) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ switch (mode) {
|
||||
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
+ if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
|
||||
+ val = 2;
|
||||
+ else
|
||||
+ /* Switch regs accept value in ns, convert ps to ns */
|
||||
+ val = val / 1000;
|
||||
+
|
||||
+ if (val > QCA8K_MAX_DELAY) {
|
||||
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||||
+ val = 3;
|
||||
+ }
|
||||
+
|
||||
+ priv->rgmii_rx_delay = val;
|
||||
+ /* Stop here if we need to check only for rx delay */
|
||||
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID)
|
||||
+ break;
|
||||
+
|
||||
+ fallthrough;
|
||||
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
+ if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
|
||||
+ val = 1;
|
||||
+ else
|
||||
+ /* Switch regs accept value in ns, convert ps to ns */
|
||||
+ val = val / 1000;
|
||||
+
|
||||
+ if (val > QCA8K_MAX_DELAY) {
|
||||
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||||
+ val = 3;
|
||||
+ }
|
||||
+
|
||||
+ priv->rgmii_tx_delay = val;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
@@ -802,6 +864,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = qca8k_setup_of_rgmii_delay(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
/* Enable CPU Port */
|
||||
ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
@@ -970,6 +1036,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
case 0: /* 1st CPU port */
|
||||
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
state->interface != PHY_INTERFACE_MODE_SGMII)
|
||||
return;
|
||||
|
||||
@@ -985,6 +1053,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
case 6: /* 2nd CPU port / external PHY */
|
||||
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
state->interface != PHY_INTERFACE_MODE_SGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_1000BASEX)
|
||||
return;
|
||||
@@ -1008,14 +1078,18 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
/* RGMII_ID needs internal delay. This is enabled through
|
||||
* PORT5_PAD_CTRL for all ports, rather than individual port
|
||||
* registers
|
||||
*/
|
||||
qca8k_write(priv, reg,
|
||||
QCA8K_PORT_PAD_RGMII_EN |
|
||||
- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
|
||||
- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||||
/* QCA8337 requires to set rgmii rx delay */
|
||||
if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||
qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||||
@@ -1073,6 +1147,8 @@ qca8k_phylink_validate(struct dsa_switch
|
||||
if (state->interface != PHY_INTERFACE_MODE_NA &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
state->interface != PHY_INTERFACE_MODE_SGMII)
|
||||
goto unsupported;
|
||||
break;
|
||||
@@ -1090,6 +1166,8 @@ qca8k_phylink_validate(struct dsa_switch
|
||||
if (state->interface != PHY_INTERFACE_MODE_NA &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
state->interface != PHY_INTERFACE_MODE_SGMII &&
|
||||
state->interface != PHY_INTERFACE_MODE_1000BASEX)
|
||||
goto unsupported;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -38,12 +38,11 @@
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||||
-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) \
|
||||
- ((0x8 + (x & 0x3)) << 22)
|
||||
-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \
|
||||
- ((0x10 + (x & 0x3)) << 20)
|
||||
-#define QCA8K_MAX_DELAY 3
|
||||
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
|
||||
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
|
||||
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
|
||||
+#define QCA8K_MAX_DELAY 3
|
||||
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
|
||||
#define QCA8K_REG_PWS 0x010
|
||||
#define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
|
||||
@@ -254,6 +253,8 @@ struct qca8k_match_data {
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
+ u8 rgmii_tx_delay;
|
||||
+ u8 rgmii_rx_delay;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
|
@ -0,0 +1,50 @@
|
|||
From 63c33bbfeb6842a956a0eb12901e28eb335bdb18 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:07 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: clear MASTER_EN after phy read/write
|
||||
|
||||
Clear MDIO_MASTER_EN bit from MDIO_MASTER_CTRL after read/write
|
||||
operation. The MDIO_MASTER_EN bit is not reset after read/write
|
||||
operation and the next operation can be wrongly interpreted by the
|
||||
switch as a mdio operation. This cause a production of wrong/garbage
|
||||
data from the switch and underfined bheavior. (random port drop,
|
||||
unplugged port flagged with link up, wrong port speed)
|
||||
Also on driver remove the MASTER_CTRL can be left set and cause the
|
||||
malfunction of any next driver using the mdio device.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -649,8 +649,14 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_BUSY);
|
||||
+ ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_BUSY);
|
||||
+
|
||||
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
+ qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_EN);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -685,6 +691,10 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
|
||||
val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
|
||||
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
+ qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_EN);
|
||||
+
|
||||
return val;
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
From 60df02b6ea4581d72eb7a3ab7204504a54059b72 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:08 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: dsa: qca8k: protect MASTER busy_wait with
|
||||
mdio mutex
|
||||
|
||||
MDIO_MASTER operation have a dedicated busy wait that is not protected
|
||||
by the mdio mutex. This can cause situation where the MASTER operation
|
||||
is done and a normal operation is executed between the MASTER read/write
|
||||
and the MASTER busy_wait. Rework the qca8k_mdio_read/write function to
|
||||
address this issue by binding the lock for the whole MASTER operation
|
||||
and not only the mdio read/write common operation.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 68 +++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 55 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -628,8 +628,31 @@ qca8k_port_to_phy(int port)
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_mdio_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
+{
|
||||
+ u16 r1, r2, page;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
+
|
||||
+ ret = read_poll_timeout(qca8k_mii_read32, val, !(val & mask), 0,
|
||||
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
|
||||
+ priv->bus, 0x10 | r2, r1);
|
||||
+
|
||||
+ /* Check if qca8k_read has failed for a different reason
|
||||
+ * before returnting -ETIMEDOUT
|
||||
+ */
|
||||
+ if (ret < 0 && val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
|
||||
{
|
||||
+ u16 r1, r2, page;
|
||||
u32 phy, val;
|
||||
int ret;
|
||||
|
||||
@@ -645,12 +668,21 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
|
||||
QCA8K_MDIO_MASTER_DATA(data);
|
||||
|
||||
- ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
|
||||
+
|
||||
+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+
|
||||
+ ret = qca8k_set_page(priv->bus, page);
|
||||
if (ret)
|
||||
- return ret;
|
||||
+ goto exit;
|
||||
+
|
||||
+ qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
|
||||
- ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_BUSY);
|
||||
+ ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_BUSY);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->bus->mdio_lock);
|
||||
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
@@ -662,6 +694,7 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
static int
|
||||
qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
|
||||
{
|
||||
+ u16 r1, r2, page;
|
||||
u32 phy, val;
|
||||
int ret;
|
||||
|
||||
@@ -676,21 +709,30 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum);
|
||||
|
||||
- ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
|
||||
+
|
||||
+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_BUSY);
|
||||
+ ret = qca8k_set_page(priv->bus, page);
|
||||
if (ret)
|
||||
- return ret;
|
||||
+ goto exit;
|
||||
|
||||
- val = qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL);
|
||||
- if (val < 0)
|
||||
- return val;
|
||||
+ qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
+
|
||||
+ ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_BUSY);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
|
||||
+ val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
|
||||
val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->bus->mdio_lock);
|
||||
+
|
||||
+ if (val >= 0)
|
||||
+ val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
+
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_EN);
|
|
@ -0,0 +1,39 @@
|
|||
From 617960d72e93de0f3fa52407e2d39e8c43e73b0a Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:09 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: enlarge mdio delay and timeout
|
||||
|
||||
The witch require some extra delay after setting page or the next
|
||||
read/write can use still use the old page. Add a delay after the
|
||||
set_page function to address this as it's done in QSDK legacy driver.
|
||||
Some timeouts were notice with VLAN and phy function, enlarge the
|
||||
mdio busy wait timeout to fix these problems.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 1 +
|
||||
drivers/net/dsa/qca8k.h | 2 +-
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -143,6 +143,7 @@ qca8k_set_page(struct mii_bus *bus, u16
|
||||
}
|
||||
|
||||
qca8k_current_page = page;
|
||||
+ usleep_range(1000, 2000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -20,7 +20,7 @@
|
||||
#define PHY_ID_QCA8337 0x004dd036
|
||||
#define QCA8K_ID_QCA8337 0x13
|
||||
|
||||
-#define QCA8K_BUSY_WAIT_TIMEOUT 20
|
||||
+#define QCA8K_BUSY_WAIT_TIMEOUT 2000
|
||||
|
||||
#define QCA8K_NUM_FDB_RECORDS 2048
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
From 759bafb8a3226326ca357613bc90acf738f80c32 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:10 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: add support for internal phy and internal
|
||||
mdio
|
||||
|
||||
Add support to setup_mdio_bus for internal phy declaration. Introduce a
|
||||
flag to use the legacy port phy mapping by default and use the direct
|
||||
mapping if a mdio node is detected in the switch node. Register a
|
||||
dedicated mdio internal mdio bus to address the different mapping
|
||||
between port and phy if the mdio node is detected.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 112 +++++++++++++++++++++++++++++-----------
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 83 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/dsa.h>
|
||||
#include <linux/of_net.h>
|
||||
+#include <linux/of_mdio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/mdio.h>
|
||||
@@ -629,7 +630,7 @@ qca8k_port_to_phy(int port)
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)
|
||||
{
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
@@ -639,7 +640,7 @@ qca8k_mdio_busy_wait(struct qca8k_priv *
|
||||
|
||||
ret = read_poll_timeout(qca8k_mii_read32, val, !(val & mask), 0,
|
||||
QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
|
||||
- priv->bus, 0x10 | r2, r1);
|
||||
+ bus, 0x10 | r2, r1);
|
||||
|
||||
/* Check if qca8k_read has failed for a different reason
|
||||
* before returnting -ETIMEDOUT
|
||||
@@ -651,19 +652,16 @@ qca8k_mdio_busy_wait(struct qca8k_priv *
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
|
||||
+qca8k_mdio_write(struct mii_bus *salve_bus, int phy, int regnum, u16 data)
|
||||
{
|
||||
+ struct qca8k_priv *priv = salve_bus->priv;
|
||||
u16 r1, r2, page;
|
||||
- u32 phy, val;
|
||||
+ u32 val;
|
||||
int ret;
|
||||
|
||||
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
|
||||
return -EINVAL;
|
||||
|
||||
- /* callee is responsible for not passing bad ports,
|
||||
- * but we still would like to make spills impossible.
|
||||
- */
|
||||
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
|
||||
QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
|
||||
@@ -679,33 +677,29 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
|
||||
qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
|
||||
- ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ ret = qca8k_mdio_busy_wait(priv->bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
|
||||
exit:
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
-
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_EN);
|
||||
+ qca8k_mii_write32(priv->bus, 0x10 | r2, r1, 0);
|
||||
+
|
||||
+ mutex_unlock(&priv->bus->mdio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
|
||||
+qca8k_mdio_read(struct mii_bus *salve_bus, int phy, int regnum)
|
||||
{
|
||||
+ struct qca8k_priv *priv = salve_bus->priv;
|
||||
u16 r1, r2, page;
|
||||
- u32 phy, val;
|
||||
+ u32 val;
|
||||
int ret;
|
||||
|
||||
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
|
||||
return -EINVAL;
|
||||
|
||||
- /* callee is responsible for not passing bad ports,
|
||||
- * but we still would like to make spills impossible.
|
||||
- */
|
||||
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
|
||||
QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
|
||||
QCA8K_MDIO_MASTER_REG_ADDR(regnum);
|
||||
@@ -720,24 +714,22 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
|
||||
qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
|
||||
- ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ ret = qca8k_mdio_busy_wait(priv->bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
|
||||
- val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
|
||||
exit:
|
||||
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
+ qca8k_mii_write32(priv->bus, 0x10 | r2, r1, 0);
|
||||
+
|
||||
mutex_unlock(&priv->bus->mdio_lock);
|
||||
|
||||
if (val >= 0)
|
||||
val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
|
||||
- /* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_EN);
|
||||
-
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -746,7 +738,14 @@ qca8k_phy_write(struct dsa_switch *ds, i
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
|
||||
- return qca8k_mdio_write(priv, port, regnum, data);
|
||||
+ /* Check if the legacy mapping should be used and the
|
||||
+ * port is not correctly mapped to the right PHY in the
|
||||
+ * devicetree
|
||||
+ */
|
||||
+ if (priv->legacy_phy_port_mapping)
|
||||
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
+
|
||||
+ return qca8k_mdio_write(priv->bus, port, regnum, data);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -755,7 +754,14 @@ qca8k_phy_read(struct dsa_switch *ds, in
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
int ret;
|
||||
|
||||
- ret = qca8k_mdio_read(priv, port, regnum);
|
||||
+ /* Check if the legacy mapping should be used and the
|
||||
+ * port is not correctly mapped to the right PHY in the
|
||||
+ * devicetree
|
||||
+ */
|
||||
+ if (priv->legacy_phy_port_mapping)
|
||||
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
+
|
||||
+ ret = qca8k_mdio_read(priv->bus, port, regnum);
|
||||
|
||||
if (ret < 0)
|
||||
return 0xffff;
|
||||
@@ -764,10 +770,37 @@ qca8k_phy_read(struct dsa_switch *ds, in
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio)
|
||||
+{
|
||||
+ struct dsa_switch *ds = priv->ds;
|
||||
+ struct mii_bus *bus;
|
||||
+
|
||||
+ bus = devm_mdiobus_alloc(ds->dev);
|
||||
+
|
||||
+ if (!bus)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ bus->priv = (void *)priv;
|
||||
+ bus->name = "qca8k slave mii";
|
||||
+ bus->read = qca8k_mdio_read;
|
||||
+ bus->write = qca8k_mdio_write;
|
||||
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d",
|
||||
+ ds->index);
|
||||
+
|
||||
+ bus->parent = ds->dev;
|
||||
+ bus->phy_mask = ~ds->phys_mii_mask;
|
||||
+
|
||||
+ ds->slave_mii_bus = bus;
|
||||
+
|
||||
+ return devm_of_mdiobus_register(priv->dev, bus, mdio);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_setup_mdio_bus(struct qca8k_priv *priv)
|
||||
{
|
||||
u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg;
|
||||
- struct device_node *ports, *port;
|
||||
+ struct device_node *ports, *port, *mdio;
|
||||
+ phy_interface_t mode;
|
||||
int err;
|
||||
|
||||
ports = of_get_child_by_name(priv->dev->of_node, "ports");
|
||||
@@ -788,7 +821,10 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
if (!dsa_is_user_port(priv->ds, reg))
|
||||
continue;
|
||||
|
||||
- if (of_property_read_bool(port, "phy-handle"))
|
||||
+ of_get_phy_mode(port, &mode);
|
||||
+
|
||||
+ if (of_property_read_bool(port, "phy-handle") &&
|
||||
+ mode != PHY_INTERFACE_MODE_INTERNAL)
|
||||
external_mdio_mask |= BIT(reg);
|
||||
else
|
||||
internal_mdio_mask |= BIT(reg);
|
||||
@@ -825,8 +861,23 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
QCA8K_MDIO_MASTER_EN);
|
||||
}
|
||||
|
||||
+ /* Check if the devicetree declare the port:phy mapping */
|
||||
+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
|
||||
+ if (of_device_is_available(mdio)) {
|
||||
+ err = qca8k_mdio_register(priv, mdio);
|
||||
+ if (err)
|
||||
+ of_node_put(mdio);
|
||||
+
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ /* If a mapping can't be found the legacy mapping is used,
|
||||
+ * using the qca8k_port_to_phy function
|
||||
+ */
|
||||
+ priv->legacy_phy_port_mapping = true;
|
||||
priv->ops.phy_read = qca8k_phy_read;
|
||||
priv->ops.phy_write = qca8k_phy_write;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1212,7 +1263,8 @@ qca8k_phylink_validate(struct dsa_switch
|
||||
case 5:
|
||||
/* Internal PHY */
|
||||
if (state->interface != PHY_INTERFACE_MODE_NA &&
|
||||
- state->interface != PHY_INTERFACE_MODE_GMII)
|
||||
+ state->interface != PHY_INTERFACE_MODE_GMII &&
|
||||
+ state->interface != PHY_INTERFACE_MODE_INTERNAL)
|
||||
goto unsupported;
|
||||
break;
|
||||
case 6: /* 2nd CPU port / external PHY */
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -255,6 +255,7 @@ struct qca8k_priv {
|
||||
u8 switch_revision;
|
||||
u8 rgmii_tx_delay;
|
||||
u8 rgmii_rx_delay;
|
||||
+ bool legacy_phy_port_mapping;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
|
@ -0,0 +1,93 @@
|
|||
From 0c994a28e7518f098c84a3049cb2915780db873a Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:11 +0200
|
||||
Subject: [PATCH] devicetree: bindings: dsa: qca8k: Document internal mdio
|
||||
definition
|
||||
|
||||
Document new way of declare mapping of internal PHY to port.
|
||||
The new implementation directly declare the PHY connected to the port
|
||||
by adding a node in the switch node. The driver detect this and register
|
||||
an internal mdiobus using the mapping defined in the mdio node.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
.../devicetree/bindings/net/dsa/qca8k.txt | 39 +++++++++++++++++++
|
||||
1 file changed, 39 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -21,6 +21,10 @@ described in dsa/dsa.txt. If the QCA8K s
|
||||
mdio-bus each subnode describing a port needs to have a valid phandle
|
||||
referencing the internal PHY it is connected to. This is because there's no
|
||||
N:N mapping of port and PHY id.
|
||||
+To declare the internal mdio-bus configuration, declare a mdio node in the
|
||||
+switch node and declare the phandle for the port referencing the internal
|
||||
+PHY is connected to. In this config a internal mdio-bus is registered and
|
||||
+the mdio MASTER is used as communication.
|
||||
|
||||
Don't use mixed external and internal mdio-bus configurations, as this is
|
||||
not supported by the hardware.
|
||||
@@ -150,26 +154,61 @@ for the internal master mdio-bus configu
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&phy_port1>;
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&phy_port2>;
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&phy_port3>;
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "lan4";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&phy_port4>;
|
||||
};
|
||||
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "wan";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&phy_port5>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ mdio {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ phy_port1: phy@0 {
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+
|
||||
+ phy_port2: phy@1 {
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+
|
||||
+ phy_port3: phy@2 {
|
||||
+ reg = <2>;
|
||||
+ };
|
||||
+
|
||||
+ phy_port4: phy@3 {
|
||||
+ reg = <3>;
|
||||
+ };
|
||||
+
|
||||
+ phy_port5: phy@4 {
|
||||
+ reg = <4>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
From b7ebac354d54f1657bb89b7a7ca149db50203e6a Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:12 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: improve internal mdio read/write bus access
|
||||
|
||||
Improve the internal mdio read/write bus access by caching the value
|
||||
without accessing it for every read/write.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 28 +++++++++++++++-------------
|
||||
1 file changed, 15 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -655,6 +655,7 @@ static int
|
||||
qca8k_mdio_write(struct mii_bus *salve_bus, int phy, int regnum, u16 data)
|
||||
{
|
||||
struct qca8k_priv *priv = salve_bus->priv;
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -669,22 +670,22 @@ qca8k_mdio_write(struct mii_bus *salve_b
|
||||
|
||||
qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
|
||||
|
||||
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(priv->bus, page);
|
||||
+ ret = qca8k_set_page(bus, page);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
|
||||
- ret = qca8k_mdio_busy_wait(priv->bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
|
||||
exit:
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, 0);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
|
||||
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
+ mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -693,6 +694,7 @@ static int
|
||||
qca8k_mdio_read(struct mii_bus *salve_bus, int phy, int regnum)
|
||||
{
|
||||
struct qca8k_priv *priv = salve_bus->priv;
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -706,26 +708,26 @@ qca8k_mdio_read(struct mii_bus *salve_bu
|
||||
|
||||
qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
|
||||
|
||||
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(priv->bus, page);
|
||||
+ ret = qca8k_set_page(bus, page);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
|
||||
- ret = qca8k_mdio_busy_wait(priv->bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
|
||||
+ val = qca8k_mii_read32(bus, 0x10 | r2, r1);
|
||||
|
||||
exit:
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, 0);
|
||||
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
|
||||
|
||||
- mutex_unlock(&priv->bus->mdio_lock);
|
||||
+ mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
if (val >= 0)
|
||||
val &= QCA8K_MDIO_MASTER_DATA_MASK;
|
|
@ -0,0 +1,48 @@
|
|||
From a46aec02bc06ac2c33f326339e4ef88c735dc30d Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:13 +0200
|
||||
Subject: [PATCH] net: dsa: qca8k: pass switch_revision info to phy dev_flags
|
||||
|
||||
Define get_phy_flags to pass switch_Revision needed to tweak the
|
||||
internal PHY with debug values based on the revision.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1740,6 +1740,22 @@ qca8k_port_vlan_del(struct dsa_switch *d
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ /* Communicate to the phy internal driver the switch revision.
|
||||
+ * Based on the switch revision different values needs to be
|
||||
+ * set to the dbg and mmd reg on the phy.
|
||||
+ * The first 2 bit are used to communicate the switch revision
|
||||
+ * to the phy driver.
|
||||
+ */
|
||||
+ if (port > 0 && port < 6)
|
||||
+ return priv->switch_revision;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static enum dsa_tag_protocol
|
||||
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
|
||||
enum dsa_tag_protocol mp)
|
||||
@@ -1774,6 +1790,7 @@ static const struct dsa_switch_ops qca8k
|
||||
.phylink_mac_config = qca8k_phylink_mac_config,
|
||||
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
|
||||
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
|
||||
+ .get_phy_flags = qca8k_get_phy_flags,
|
||||
};
|
||||
|
||||
static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
|
@ -0,0 +1,229 @@
|
|||
From 272833b9b3b3969be7a91839121d86662c8c4253 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 14 May 2021 23:00:15 +0200
|
||||
Subject: [PATCH] net: phy: add support for qca8k switch internal PHY in at803x
|
||||
|
||||
Since the at803x share the same regs, it's assumed they are based on the
|
||||
same implementation. Make it part of the at803x PHY driver to skip
|
||||
having redudant code.
|
||||
Add initial support for qca8k internal PHYs. The internal PHYs requires
|
||||
special mmd and debug values to be set based on the switch revision
|
||||
passwd using the dev_flags. Supports output of idle, receive and eee_wake
|
||||
errors stats.
|
||||
Some debug values sets can't be translated as the documentation lacks any
|
||||
reference about them.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 5 +-
|
||||
drivers/net/phy/at803x.c | 132 ++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 134 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -235,10 +235,11 @@ config NXP_TJA11XX_PHY
|
||||
Currently supports the NXP TJA1100 and TJA1101 PHY.
|
||||
|
||||
config AT803X_PHY
|
||||
- tristate "Qualcomm Atheros AR803X PHYs"
|
||||
+ tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
|
||||
depends on REGULATOR
|
||||
help
|
||||
- Currently supports the AR8030, AR8031, AR8033 and AR8035 model
|
||||
+ Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
|
||||
+ QCA8337(Internal qca8k PHY) model
|
||||
|
||||
config QSEMI_PHY
|
||||
tristate "Quality Semiconductor PHYs"
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -92,10 +92,16 @@
|
||||
#define AT803X_DEBUG_REG_5 0x05
|
||||
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
|
||||
|
||||
+#define AT803X_DEBUG_REG_3C 0x3C
|
||||
+
|
||||
+#define AT803X_DEBUG_REG_3D 0x3D
|
||||
+
|
||||
#define AT803X_DEBUG_REG_1F 0x1F
|
||||
#define AT803X_DEBUG_PLL_ON BIT(2)
|
||||
#define AT803X_DEBUG_RGMII_1V8 BIT(3)
|
||||
|
||||
+#define MDIO_AZ_DEBUG 0x800D
|
||||
+
|
||||
/* AT803x supports either the XTAL input pad, an internal PLL or the
|
||||
* DSP as clock reference for the clock output pad. The XTAL reference
|
||||
* is only used for 25 MHz output, all other frequencies need the PLL.
|
||||
@@ -142,10 +148,34 @@
|
||||
#define AT803X_PAGE_FIBER 0
|
||||
#define AT803X_PAGE_COPPER 1
|
||||
|
||||
+#define QCA8327_PHY_ID 0x004dd034
|
||||
+#define QCA8337_PHY_ID 0x004dd036
|
||||
+#define QCA8K_PHY_ID_MASK 0xffffffff
|
||||
+
|
||||
+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
|
||||
+
|
||||
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
|
||||
MODULE_AUTHOR("Matus Ujhelyi");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+enum stat_access_type {
|
||||
+ PHY,
|
||||
+ MMD
|
||||
+};
|
||||
+
|
||||
+struct at803x_hw_stat {
|
||||
+ const char *string;
|
||||
+ u8 reg;
|
||||
+ u32 mask;
|
||||
+ enum stat_access_type access_type;
|
||||
+};
|
||||
+
|
||||
+static struct at803x_hw_stat at803x_hw_stats[] = {
|
||||
+ { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
|
||||
+ { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
|
||||
+ { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
|
||||
+};
|
||||
+
|
||||
struct at803x_priv {
|
||||
int flags;
|
||||
#define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */
|
||||
@@ -154,6 +184,7 @@ struct at803x_priv {
|
||||
struct regulator_dev *vddio_rdev;
|
||||
struct regulator_dev *vddh_rdev;
|
||||
struct regulator *vddio;
|
||||
+ u64 stats[ARRAY_SIZE(at803x_hw_stats)];
|
||||
};
|
||||
|
||||
struct at803x_context {
|
||||
@@ -165,6 +196,17 @@ struct at803x_context {
|
||||
u16 led_control;
|
||||
};
|
||||
|
||||
+static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return phy_write(phydev, AT803X_DEBUG_DATA, data);
|
||||
+}
|
||||
+
|
||||
static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
|
||||
{
|
||||
int ret;
|
||||
@@ -327,6 +369,53 @@ static void at803x_get_wol(struct phy_de
|
||||
wol->wolopts |= WAKE_MAGIC;
|
||||
}
|
||||
|
||||
+static int at803x_get_sset_count(struct phy_device *phydev)
|
||||
+{
|
||||
+ return ARRAY_SIZE(at803x_hw_stats);
|
||||
+}
|
||||
+
|
||||
+static void at803x_get_strings(struct phy_device *phydev, u8 *data)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
|
||||
+ strscpy(data + i * ETH_GSTRING_LEN,
|
||||
+ at803x_hw_stats[i].string, ETH_GSTRING_LEN);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static u64 at803x_get_stat(struct phy_device *phydev, int i)
|
||||
+{
|
||||
+ struct at803x_hw_stat stat = at803x_hw_stats[i];
|
||||
+ struct at803x_priv *priv = phydev->priv;
|
||||
+ int val;
|
||||
+ u64 ret;
|
||||
+
|
||||
+ if (stat.access_type == MMD)
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
|
||||
+ else
|
||||
+ val = phy_read(phydev, stat.reg);
|
||||
+
|
||||
+ if (val < 0) {
|
||||
+ ret = U64_MAX;
|
||||
+ } else {
|
||||
+ val = val & stat.mask;
|
||||
+ priv->stats[i] += val;
|
||||
+ ret = priv->stats[i];
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void at803x_get_stats(struct phy_device *phydev,
|
||||
+ struct ethtool_stats *stats, u64 *data)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
|
||||
+ data[i] = at803x_get_stat(phydev, i);
|
||||
+}
|
||||
+
|
||||
static int at803x_suspend(struct phy_device *phydev)
|
||||
{
|
||||
int value;
|
||||
@@ -1102,6 +1191,34 @@ static int at803x_cable_test_start(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int qca83xx_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ u8 switch_revision;
|
||||
+
|
||||
+ switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
|
||||
+
|
||||
+ switch (switch_revision) {
|
||||
+ case 1:
|
||||
+ /* For 100M waveform */
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
|
||||
+ /* Turn on Gigabit clock */
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
|
||||
+ break;
|
||||
+
|
||||
+ case 2:
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
|
||||
+ fallthrough;
|
||||
+ case 4:
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static struct phy_driver at803x_driver[] = {
|
||||
{
|
||||
/* Qualcomm Atheros AR8035 */
|
||||
@@ -1198,7 +1315,20 @@ static struct phy_driver at803x_driver[]
|
||||
.read_status = at803x_read_status,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
.config_aneg = at803x_config_aneg,
|
||||
-} };
|
||||
+}, {
|
||||
+ /* QCA8337 */
|
||||
+ .phy_id = QCA8337_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "QCA PHY 8337",
|
||||
+ /* PHY_GBIT_FEATURES */
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
+}, };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
|
|
@ -20,7 +20,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
|||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -935,6 +935,34 @@ static int at803x_set_tunable(struct phy
|
||||
@@ -1024,6 +1024,34 @@ static int at803x_set_tunable(struct phy
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
|||
static int at803x_cable_test_result_trans(u16 status)
|
||||
{
|
||||
switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
|
||||
@@ -1156,7 +1184,7 @@ static struct phy_driver at803x_driver[]
|
||||
@@ -1273,7 +1301,7 @@ static struct phy_driver at803x_driver[]
|
||||
.resume = at803x_resume,
|
||||
.read_page = at803x_read_page,
|
||||
.write_page = at803x_write_page,
|
||||
|
|
|
@ -25,9 +25,9 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
|
|||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -314,6 +314,12 @@ config AT803X_PHY
|
||||
help
|
||||
Currently supports the AR8030, AR8031, AR8033 and AR8035 model
|
||||
@@ -315,6 +315,12 @@ config AT803X_PHY
|
||||
Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
|
||||
QCA8337(Internal qca8k PHY) model
|
||||
|
||||
+config QCA807X_PHY
|
||||
+ tristate "Qualcomm QCA807X PHYs"
|
||||
|
|
Loading…
Reference in a new issue