kernel: Bump to 6.6.22 + kkit-linux-6.6.y

This commit is contained in:
Tobias Waldekranz
2024-03-20 14:41:25 +01:00
parent 3a740ff049
commit 2bd3b508ee
35 changed files with 1115 additions and 1216 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
+1 -1
View File
@@ -25,7 +25,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
+1 -1
View File
@@ -27,7 +27,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image
BR2_ROOTFS_POST_SCRIPT_ARGS="-c $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/genimage.cfg"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
BR2_LINUX_KERNEL_PATCH="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/rk3328-nanopi-r2s-dts.patch"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/linux_defconfig"
+1 -1
View File
@@ -22,7 +22,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
+1 -1
View File
@@ -24,7 +24,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.5.11"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.22"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -1,41 +0,0 @@
From e1011848d2c9476e20e6a4053b8ab46ce2a1506f Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 5 Oct 2023 16:09:25 +0200
Subject: [PATCH 01/20] eth: fwnode: Fall back to NVMEM provided MAC address
from OF
Organization: Addiva Elektronik
In the cases where the fwnode is an OF node, make use of any NVMEM
source of the interface's MAC address that might have been specified
in the device tree.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
net/ethernet/eth.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 2edc8b796a4e..04900a41fab3 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -609,11 +609,17 @@ static int fwnode_get_mac_addr(struct fwnode_handle *fwnode,
*/
int fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr)
{
+ struct device_node *np;
+
if (!fwnode_get_mac_addr(fwnode, "mac-address", addr) ||
!fwnode_get_mac_addr(fwnode, "local-mac-address", addr) ||
!fwnode_get_mac_addr(fwnode, "address", addr))
return 0;
+ np = to_of_node(fwnode);
+ if (np)
+ return of_get_mac_address_nvmem(np, addr);
+
return -ENOENT;
}
EXPORT_SYMBOL(fwnode_get_mac_address);
--
2.34.1
@@ -0,0 +1,107 @@
From 79abf7872e35080ca5b519bb4ad2acc1fbd96e8c Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Thu, 25 Jan 2024 21:36:59 +0100
Subject: [PATCH 01/19] net: phy: add support for PHY LEDs polarity modes
Organization: Addiva Elektronik
Add support for PHY LEDs polarity modes. Some PHY require LED to be set
to active low to be turned ON. Adds support for this by declaring
active-low property in DT.
PHY driver needs to declare .led_polarity_set() to configure LED
polarity modes. Function will pass the index with the LED index and a
bitmap with all the required modes to set.
Current supported modes are:
- active-low with the flag PHY_LED_ACTIVE_LOW. LED is set to active-low
to turn it ON.
- inactive-high-impedance with the flag PHY_LED_INACTIVE_HIGH_IMPEDANCE.
LED is set to high impedance to turn it OFF.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20240125203702.4552-4-ansuelsmth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/phy_device.c | 16 ++++++++++++++++
include/linux/phy.h | 22 ++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index a42df2c1bd04..3741c0c3bf4a 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3092,6 +3092,7 @@ static int of_phy_led(struct phy_device *phydev,
struct device *dev = &phydev->mdio.dev;
struct led_init_data init_data = {};
struct led_classdev *cdev;
+ unsigned long modes = 0;
struct phy_led *phyled;
u32 index;
int err;
@@ -3109,6 +3110,21 @@ static int of_phy_led(struct phy_device *phydev,
if (index > U8_MAX)
return -EINVAL;
+ if (of_property_read_bool(led, "active-low"))
+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
+ if (of_property_read_bool(led, "inactive-high-impedance"))
+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
+
+ if (modes) {
+ /* Return error if asked to set polarity modes but not supported */
+ if (!phydev->drv->led_polarity_set)
+ return -EINVAL;
+
+ err = phydev->drv->led_polarity_set(phydev, index, modes);
+ if (err)
+ return err;
+ }
+
phyled->index = index;
if (phydev->drv->led_brightness_set)
cdev->brightness_set_blocking = phy_led_set_brightness;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 1351b802ffcf..7e82fb9331b9 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -849,6 +849,15 @@ struct phy_plca_status {
bool pst;
};
+/* Modes for PHY LED configuration */
+enum phy_led_modes {
+ PHY_LED_ACTIVE_LOW = 0,
+ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1,
+
+ /* keep it last */
+ __PHY_LED_MODES_NUM,
+};
+
/**
* struct phy_led: An LED driven by the PHY
*
@@ -1142,6 +1151,19 @@ struct phy_driver {
int (*led_hw_control_get)(struct phy_device *dev, u8 index,
unsigned long *rules);
+ /**
+ * @led_polarity_set: Set the LED polarity modes
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @modes: bitmap of LED polarity modes
+ *
+ * Configure LED with all the required polarity modes in @modes
+ * to make it correctly turn ON or OFF.
+ *
+ * Returns 0, or an error code.
+ */
+ int (*led_polarity_set)(struct phy_device *dev, int index,
+ unsigned long modes);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
--
2.34.1
@@ -1,7 +1,7 @@
From d389cc01295ebd7be228c8240f0061134b27f215 Mon Sep 17 00:00:00 2001
From 424ddb5d5d8ce06c578cc08cbedf519c42dd8b69 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 21 Sep 2023 11:12:55 +0200
Subject: [PATCH 08/20] net: mvmdio: Support setting the MDC frequency on XSMI
Date: Mon, 4 Dec 2023 11:08:11 +0100
Subject: [PATCH 02/19] net: mvmdio: Support setting the MDC frequency on XSMI
controllers
Organization: Addiva Elektronik
@@ -10,12 +10,16 @@ MDC frequency. If not specified, the driver will leave the divisor
untouched.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20231204100811.2708884-4-tobias@waldekranz.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/ethernet/marvell/mvmdio.c | 45 +++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
drivers/net/ethernet/marvell/mvmdio.c | 44 +++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 37e20c2702b5..a33f63b7f773 100644
index 2ef613a237d8..11f564e88a7d 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -53,6 +53,13 @@
@@ -32,7 +36,7 @@ index 37e20c2702b5..a33f63b7f773 100644
/*
* SMI Timeout measurements:
* - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
@@ -237,6 +244,41 @@ static int orion_mdio_xsmi_write_c45(struct mii_bus *bus, int mii_id,
@@ -225,6 +232,40 @@ static int orion_mdio_xsmi_write_c45(struct mii_bus *bus, int mii_id,
return 0;
}
@@ -69,12 +73,11 @@ index 37e20c2702b5..a33f63b7f773 100644
+ cfg |= div;
+ writel(cfg, dev->regs + MVMDIO_XSMI_CFG_REG);
+}
+
+
static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
{
struct orion_mdio_dev *dev = dev_id;
@@ -315,6 +357,9 @@ static int orion_mdio_probe(struct platform_device *pdev)
@@ -303,6 +344,9 @@ static int orion_mdio_probe(struct platform_device *pdev)
dev_warn(&pdev->dev,
"unsupported number of clocks, limiting to the first "
__stringify(ARRAY_SIZE(dev->clk)) "\n");
@@ -1,7 +1,7 @@
From 1d6f30fce9f4516730439f72ee2134301d37654d Mon Sep 17 00:00:00 2001
From 337cf21833cef6ab456a8562338de88ab1a84ead Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 13:08:29 +0200
Subject: [PATCH 02/20] net: dsa: mv88e6xxx: Create API to read a single stat
Date: Thu, 14 Dec 2023 14:50:23 +0100
Subject: [PATCH 03/19] net: dsa: mv88e6xxx: Create API to read a single stat
counter
Organization: Addiva Elektronik
@@ -12,17 +12,20 @@ than the whole set.
This is a preparatory change for the upcoming standard ethtool
statistics support (i.e. "eth-mac", "eth-ctrl" etc.).
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mv88e6xxx/chip.c | 160 ++++++++++++++++++-------------
drivers/net/dsa/mv88e6xxx/chip.c | 162 ++++++++++++++++++-------------
drivers/net/dsa/mv88e6xxx/chip.h | 27 +++---
2 files changed, 105 insertions(+), 82 deletions(-)
2 files changed, 106 insertions(+), 83 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 0d4b236d1e34..139f4d55a284 100644
index 5ad51271a534..db6aa08c66cc 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1082,7 +1082,7 @@ static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
@@ -1012,7 +1012,7 @@ static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
};
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
@@ -31,16 +34,16 @@ index 0d4b236d1e34..139f4d55a284 100644
int port, u16 bank1_select,
u16 histogram)
{
@@ -1265,59 +1265,82 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
@@ -1195,59 +1195,82 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
return count;
}
-static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data, int types,
- u16 bank1_select, u16 histogram)
+static int mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- struct mv88e6xxx_hw_stat *stat;
- int i, j;
@@ -64,9 +67,9 @@ index 0d4b236d1e34..139f4d55a284 100644
- }
- }
- return j;
+static int mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+{
+ if (!(stat->type & STATS_TYPE_BANK0))
+ return 0;
@@ -78,9 +81,9 @@ index 0d4b236d1e34..139f4d55a284 100644
-static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static int mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_PORT,
@@ -96,9 +99,9 @@ index 0d4b236d1e34..139f4d55a284 100644
-static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static int mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
- 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
@@ -113,9 +116,9 @@ index 0d4b236d1e34..139f4d55a284 100644
-static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static int mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+static size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
@@ -133,15 +136,16 @@ index 0d4b236d1e34..139f4d55a284 100644
}
-static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
+static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
- uint64_t *data)
+static size_t mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
- MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
- 0);
+ struct mv88e6xxx_hw_stat *stat;
+ int i, j;
+ size_t i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
+ stat = &mv88e6xxx_hw_stats[i];
@@ -151,12 +155,12 @@ index 0d4b236d1e34..139f4d55a284 100644
}
static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
@@ -1333,10 +1356,9 @@ static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
@@ -1263,10 +1286,9 @@ static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
- int count = 0;
+ int count;
+ size_t count;
- if (chip->info->ops->stats_get_stats)
- count = chip->info->ops->stats_get_stats(chip, port, data);
@@ -164,7 +168,7 @@ index 0d4b236d1e34..139f4d55a284 100644
mv88e6xxx_reg_lock(chip);
if (chip->info->ops->serdes_get_stats) {
@@ -4198,7 +4220,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
@@ -3987,7 +4009,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -173,16 +177,16 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4236,7 +4258,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -4025,7 +4047,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
.serdes_power = mv88e6185_serdes_power,
.serdes_get_lane = mv88e6185_serdes_get_lane,
@@ -4279,7 +4301,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.ppu_enable = mv88e6185_g1_ppu_enable,
.ppu_disable = mv88e6185_g1_ppu_disable,
@@ -4066,7 +4088,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -191,7 +195,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4325,7 +4347,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -4108,7 +4130,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -200,7 +204,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4368,7 +4390,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -4151,7 +4173,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -209,7 +213,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4417,7 +4439,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
@@ -4200,7 +4222,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -218,7 +222,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4479,7 +4501,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -4255,7 +4277,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -227,7 +231,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4517,7 +4539,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -4293,7 +4315,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -236,7 +240,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4565,7 +4587,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -4341,7 +4363,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -245,7 +249,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4614,7 +4636,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -4390,7 +4412,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -254,7 +258,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4670,7 +4692,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -4441,7 +4463,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -263,7 +267,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4719,7 +4741,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -4490,7 +4512,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -272,7 +276,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4771,7 +4793,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -4535,7 +4557,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -281,7 +285,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4822,7 +4844,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -4584,7 +4606,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -290,7 +294,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4887,7 +4909,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -4642,7 +4664,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -299,7 +303,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4950,7 +4972,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -4698,7 +4720,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -308,7 +312,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5016,7 +5038,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -4757,7 +4779,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -317,7 +321,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5076,7 +5098,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = {
@@ -4810,7 +4832,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6250_stats_get_sset_count,
.stats_get_strings = mv88e6250_stats_get_strings,
@@ -326,7 +330,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6250_watchdog_ops,
@@ -5123,7 +5145,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -4857,7 +4879,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -335,7 +339,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5189,7 +5211,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -4916,7 +4938,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -344,7 +348,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5236,7 +5258,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -4963,7 +4985,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -353,7 +357,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5285,7 +5307,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -5012,7 +5034,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -362,7 +366,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5350,7 +5372,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -5070,7 +5092,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -371,7 +375,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5396,7 +5418,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -5116,7 +5138,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -380,7 +384,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5447,7 +5469,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -5167,7 +5189,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -389,7 +393,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5516,7 +5538,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -5229,7 +5251,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -398,7 +402,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5585,7 +5607,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -5291,7 +5313,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -407,7 +411,7 @@ index 0d4b236d1e34..139f4d55a284 100644
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5654,7 +5676,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
@@ -5353,7 +5375,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -417,7 +421,7 @@ index 0d4b236d1e34..139f4d55a284 100644
* CPU port, only per port CPU port which is set via
* .port_set_upstream_port method.
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 0ad34b2d8913..268c97cde8d8 100644
index c54d305a1d83..85eb293381a7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -318,6 +318,17 @@ struct mv88e6xxx_mst {
@@ -444,14 +448,14 @@ index 0ad34b2d8913..268c97cde8d8 100644
int (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
- int (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data);
+ int (*stats_get_stat)(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data);
+ size_t (*stats_get_stat)(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data);
int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
int (*set_egress_port)(struct mv88e6xxx_chip *chip,
enum mv88e6xxx_egress_direction direction,
@@ -736,17 +748,6 @@ struct mv88e6xxx_ptp_ops {
u32 cc_mult_dem;
@@ -727,17 +739,6 @@ struct mv88e6xxx_pcs_ops {
};
-#define STATS_TYPE_PORT BIT(0)
@@ -1,88 +0,0 @@
From 6a612f46152d8567a16b7b15fdcc3081cbdbb3fb Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 21:15:52 +0200
Subject: [PATCH 04/20] net: dsa: mv88e6xxx: Add "eth-mac" counter group
support
Organization: Addiva Elektronik
After this change, mv88e6xxx ports can report the applicable subset of
their counters using ethtool's standardized "eth-mac" counter group.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 52 ++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 4afe5c212a36..2cfc072b41b1 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1403,6 +1403,57 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
}
+static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+#define MV88E6XXX_ETH_MAC_STAT_MAPPING(_id, _member) \
+ [MV88E6XXX_HW_STAT_ID_ ## _id] = \
+ offsetof(struct ethtool_eth_mac_stats, stats._member) \
+
+ static const size_t stat_map[MV88E6XXX_HW_STAT_ID_MAX] = {
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(out_unicast, FramesTransmittedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(single, SingleCollisionFrames),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(multiple, MultipleCollisionFrames),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(in_unicast, FramesReceivedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(in_fcs_error, FrameCheckSequenceErrors),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(out_octets, OctetsTransmittedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(deferred, FramesWithDeferredXmissions),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(late, LateCollisions),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(in_good_octets, OctetsReceivedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(out_multicasts, MulticastFramesXmittedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(out_broadcasts, BroadcastFramesXmittedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(excessive, FramesWithExcessiveDeferral),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(in_multicasts, MulticastFramesReceivedOK),
+ MV88E6XXX_ETH_MAC_STAT_MAPPING(in_broadcasts, BroadcastFramesReceivedOK),
+ };
+ struct mv88e6xxx_chip *chip = ds->priv;
+ const struct mv88e6xxx_hw_stat *stat;
+ enum mv88e6xxx_hw_stat_id id;
+ u64 *member;
+ int ret;
+
+ mv88e6xxx_reg_lock(chip);
+ ret = mv88e6xxx_stats_snapshot(chip, port);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (ret < 0)
+ return;
+
+ stat = mv88e6xxx_hw_stats;
+ for (id = 0; id < MV88E6XXX_HW_STAT_ID_MAX; id++, stat++) {
+ if (!stat_map[id])
+ continue;
+
+ member = (u64 *)(((char *)mac_stats) + stat_map[id]);
+ mv88e6xxx_stats_get_stat(chip, port, stat, member);
+ }
+
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.MulticastFramesXmittedOK;
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.BroadcastFramesXmittedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.MulticastFramesReceivedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.BroadcastFramesReceivedOK;
+}
+
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -7162,6 +7213,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
+ .get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.port_enable = mv88e6xxx_port_enable,
.port_disable = mv88e6xxx_port_disable,
--
2.34.1
@@ -1,7 +1,7 @@
From f960475a96d2852d06ee062c970e35074f87659c Mon Sep 17 00:00:00 2001
From dbdbfd57998b4f8224146ac94cd5d0a577326087 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 5 Sep 2023 21:10:15 +0200
Subject: [PATCH 03/20] net: dsa: mv88e6xxx: Give each hw stat an ID
Date: Thu, 14 Dec 2023 14:50:25 +0100
Subject: [PATCH 04/19] net: dsa: mv88e6xxx: Give each hw stat an ID
Organization: Addiva Elektronik
With the upcoming standard counter group support, we are no longer
@@ -10,18 +10,21 @@ the requested group.
Therefore, create an enum with an ID for each stat, such that
mv88e6xxx_hw_stats[] can be subscripted with a human-readable ID
corresponding to the counters name.
corresponding to the counter's name.
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mv88e6xxx/chip.c | 141 +++++++++++++++++--------------
1 file changed, 78 insertions(+), 63 deletions(-)
drivers/net/dsa/mv88e6xxx/chip.c | 138 +++++++++++++++++--------------
1 file changed, 75 insertions(+), 63 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 139f4d55a284..4afe5c212a36 100644
index db6aa08c66cc..80787f1e205c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1019,68 +1019,83 @@ static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
@@ -949,66 +949,78 @@ static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
return chip->info->ops->stats_snapshot(chip, port);
}
@@ -85,87 +88,82 @@ index 139f4d55a284..4afe5c212a36 100644
- { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, },
- { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, },
- { "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
+#define MV88E6XXX_HW_STAT_MAPPER(_fn) \
+ _fn(in_good_octets, 8, 0x00, STATS_TYPE_BANK0) \
+ _fn(in_bad_octets, 4, 0x02, STATS_TYPE_BANK0) \
+ _fn(in_unicast, 4, 0x04, STATS_TYPE_BANK0) \
+ _fn(in_broadcasts, 4, 0x06, STATS_TYPE_BANK0) \
+ _fn(in_multicasts, 4, 0x07, STATS_TYPE_BANK0) \
+ _fn(in_pause, 4, 0x16, STATS_TYPE_BANK0) \
+ _fn(in_undersize, 4, 0x18, STATS_TYPE_BANK0) \
+ _fn(in_fragments, 4, 0x19, STATS_TYPE_BANK0) \
+ _fn(in_oversize, 4, 0x1a, STATS_TYPE_BANK0) \
+ _fn(in_jabber, 4, 0x1b, STATS_TYPE_BANK0) \
+ _fn(in_rx_error, 4, 0x1c, STATS_TYPE_BANK0) \
+ _fn(in_fcs_error, 4, 0x1d, STATS_TYPE_BANK0) \
+ _fn(out_octets, 8, 0x0e, STATS_TYPE_BANK0) \
+ _fn(out_unicast, 4, 0x10, STATS_TYPE_BANK0) \
+ _fn(out_broadcasts, 4, 0x13, STATS_TYPE_BANK0) \
+ _fn(out_multicasts, 4, 0x12, STATS_TYPE_BANK0) \
+ _fn(out_pause, 4, 0x15, STATS_TYPE_BANK0) \
+ _fn(excessive, 4, 0x11, STATS_TYPE_BANK0) \
+ _fn(collisions, 4, 0x1e, STATS_TYPE_BANK0) \
+ _fn(deferred, 4, 0x05, STATS_TYPE_BANK0) \
+ _fn(single, 4, 0x14, STATS_TYPE_BANK0) \
+ _fn(multiple, 4, 0x17, STATS_TYPE_BANK0) \
+ _fn(out_fcs_error, 4, 0x03, STATS_TYPE_BANK0) \
+ _fn(late, 4, 0x1f, STATS_TYPE_BANK0) \
+ _fn(hist_64bytes, 4, 0x08, STATS_TYPE_BANK0) \
+ _fn(hist_65_127bytes, 4, 0x09, STATS_TYPE_BANK0) \
+ _fn(hist_128_255bytes, 4, 0x0a, STATS_TYPE_BANK0) \
+ _fn(hist_256_511bytes, 4, 0x0b, STATS_TYPE_BANK0) \
+ _fn(hist_512_1023bytes, 4, 0x0c, STATS_TYPE_BANK0) \
+ _fn(hist_1024_max_bytes, 4, 0x0d, STATS_TYPE_BANK0) \
+ _fn(sw_in_discards, 4, 0x10, STATS_TYPE_PORT) \
+ _fn(sw_in_filtered, 2, 0x12, STATS_TYPE_PORT) \
+ _fn(sw_out_filtered, 2, 0x13, STATS_TYPE_PORT) \
+ _fn(in_discards, 4, 0x00, STATS_TYPE_BANK1) \
+ _fn(in_filtered, 4, 0x01, STATS_TYPE_BANK1) \
+ _fn(in_accepted, 4, 0x02, STATS_TYPE_BANK1) \
+ _fn(in_bad_accepted, 4, 0x03, STATS_TYPE_BANK1) \
+ _fn(in_good_avb_class_a, 4, 0x04, STATS_TYPE_BANK1) \
+ _fn(in_good_avb_class_b, 4, 0x05, STATS_TYPE_BANK1) \
+ _fn(in_bad_avb_class_a, 4, 0x06, STATS_TYPE_BANK1) \
+ _fn(in_bad_avb_class_b, 4, 0x07, STATS_TYPE_BANK1) \
+ _fn(tcam_counter_0, 4, 0x08, STATS_TYPE_BANK1) \
+ _fn(tcam_counter_1, 4, 0x09, STATS_TYPE_BANK1) \
+ _fn(tcam_counter_2, 4, 0x0a, STATS_TYPE_BANK1) \
+ _fn(tcam_counter_3, 4, 0x0b, STATS_TYPE_BANK1) \
+ _fn(in_da_unknown, 4, 0x0e, STATS_TYPE_BANK1) \
+ _fn(in_management, 4, 0x0f, STATS_TYPE_BANK1) \
+ _fn(out_queue_0, 4, 0x10, STATS_TYPE_BANK1) \
+ _fn(out_queue_1, 4, 0x11, STATS_TYPE_BANK1) \
+ _fn(out_queue_2, 4, 0x12, STATS_TYPE_BANK1) \
+ _fn(out_queue_3, 4, 0x13, STATS_TYPE_BANK1) \
+ _fn(out_queue_4, 4, 0x14, STATS_TYPE_BANK1) \
+ _fn(out_queue_5, 4, 0x15, STATS_TYPE_BANK1) \
+ _fn(out_queue_6, 4, 0x16, STATS_TYPE_BANK1) \
+ _fn(out_queue_7, 4, 0x17, STATS_TYPE_BANK1) \
+ _fn(out_cut_through, 4, 0x18, STATS_TYPE_BANK1) \
+ _fn(out_octets_a, 4, 0x1a, STATS_TYPE_BANK1) \
+ _fn(out_octets_b, 4, 0x1b, STATS_TYPE_BANK1) \
+ _fn(out_management, 4, 0x1f, STATS_TYPE_BANK1) \
+#define MV88E6XXX_HW_STAT_MAPPER(_fn) \
+ _fn(in_good_octets, 8, 0x00, STATS_TYPE_BANK0), \
+ _fn(in_bad_octets, 4, 0x02, STATS_TYPE_BANK0), \
+ _fn(in_unicast, 4, 0x04, STATS_TYPE_BANK0), \
+ _fn(in_broadcasts, 4, 0x06, STATS_TYPE_BANK0), \
+ _fn(in_multicasts, 4, 0x07, STATS_TYPE_BANK0), \
+ _fn(in_pause, 4, 0x16, STATS_TYPE_BANK0), \
+ _fn(in_undersize, 4, 0x18, STATS_TYPE_BANK0), \
+ _fn(in_fragments, 4, 0x19, STATS_TYPE_BANK0), \
+ _fn(in_oversize, 4, 0x1a, STATS_TYPE_BANK0), \
+ _fn(in_jabber, 4, 0x1b, STATS_TYPE_BANK0), \
+ _fn(in_rx_error, 4, 0x1c, STATS_TYPE_BANK0), \
+ _fn(in_fcs_error, 4, 0x1d, STATS_TYPE_BANK0), \
+ _fn(out_octets, 8, 0x0e, STATS_TYPE_BANK0), \
+ _fn(out_unicast, 4, 0x10, STATS_TYPE_BANK0), \
+ _fn(out_broadcasts, 4, 0x13, STATS_TYPE_BANK0), \
+ _fn(out_multicasts, 4, 0x12, STATS_TYPE_BANK0), \
+ _fn(out_pause, 4, 0x15, STATS_TYPE_BANK0), \
+ _fn(excessive, 4, 0x11, STATS_TYPE_BANK0), \
+ _fn(collisions, 4, 0x1e, STATS_TYPE_BANK0), \
+ _fn(deferred, 4, 0x05, STATS_TYPE_BANK0), \
+ _fn(single, 4, 0x14, STATS_TYPE_BANK0), \
+ _fn(multiple, 4, 0x17, STATS_TYPE_BANK0), \
+ _fn(out_fcs_error, 4, 0x03, STATS_TYPE_BANK0), \
+ _fn(late, 4, 0x1f, STATS_TYPE_BANK0), \
+ _fn(hist_64bytes, 4, 0x08, STATS_TYPE_BANK0), \
+ _fn(hist_65_127bytes, 4, 0x09, STATS_TYPE_BANK0), \
+ _fn(hist_128_255bytes, 4, 0x0a, STATS_TYPE_BANK0), \
+ _fn(hist_256_511bytes, 4, 0x0b, STATS_TYPE_BANK0), \
+ _fn(hist_512_1023bytes, 4, 0x0c, STATS_TYPE_BANK0), \
+ _fn(hist_1024_max_bytes, 4, 0x0d, STATS_TYPE_BANK0), \
+ _fn(sw_in_discards, 4, 0x10, STATS_TYPE_PORT), \
+ _fn(sw_in_filtered, 2, 0x12, STATS_TYPE_PORT), \
+ _fn(sw_out_filtered, 2, 0x13, STATS_TYPE_PORT), \
+ _fn(in_discards, 4, 0x00, STATS_TYPE_BANK1), \
+ _fn(in_filtered, 4, 0x01, STATS_TYPE_BANK1), \
+ _fn(in_accepted, 4, 0x02, STATS_TYPE_BANK1), \
+ _fn(in_bad_accepted, 4, 0x03, STATS_TYPE_BANK1), \
+ _fn(in_good_avb_class_a, 4, 0x04, STATS_TYPE_BANK1), \
+ _fn(in_good_avb_class_b, 4, 0x05, STATS_TYPE_BANK1), \
+ _fn(in_bad_avb_class_a, 4, 0x06, STATS_TYPE_BANK1), \
+ _fn(in_bad_avb_class_b, 4, 0x07, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_0, 4, 0x08, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_1, 4, 0x09, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_2, 4, 0x0a, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_3, 4, 0x0b, STATS_TYPE_BANK1), \
+ _fn(in_da_unknown, 4, 0x0e, STATS_TYPE_BANK1), \
+ _fn(in_management, 4, 0x0f, STATS_TYPE_BANK1), \
+ _fn(out_queue_0, 4, 0x10, STATS_TYPE_BANK1), \
+ _fn(out_queue_1, 4, 0x11, STATS_TYPE_BANK1), \
+ _fn(out_queue_2, 4, 0x12, STATS_TYPE_BANK1), \
+ _fn(out_queue_3, 4, 0x13, STATS_TYPE_BANK1), \
+ _fn(out_queue_4, 4, 0x14, STATS_TYPE_BANK1), \
+ _fn(out_queue_5, 4, 0x15, STATS_TYPE_BANK1), \
+ _fn(out_queue_6, 4, 0x16, STATS_TYPE_BANK1), \
+ _fn(out_queue_7, 4, 0x17, STATS_TYPE_BANK1), \
+ _fn(out_cut_through, 4, 0x18, STATS_TYPE_BANK1), \
+ _fn(out_octets_a, 4, 0x1a, STATS_TYPE_BANK1), \
+ _fn(out_octets_b, 4, 0x1b, STATS_TYPE_BANK1), \
+ _fn(out_management, 4, 0x1f, STATS_TYPE_BANK1), \
+ /* */
+
+#define MV88E6XXX_HW_STAT_ENTRY(_string, _size, _reg, _type) \
+ { #_string, _size, _reg, _type },
+ { #_string, _size, _reg, _type }
+static const struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
+ MV88E6XXX_HW_STAT_MAPPER(MV88E6XXX_HW_STAT_ENTRY)
};
+#define MV88E6XXX_HW_STAT_ENUM(_string, _size, _reg, _type) \
+ MV88E6XXX_HW_STAT_ID_ ## _string,
+enum mv88e6xxx_hw_stat_id {
+ MV88E6XXX_HW_STAT_MAPPER(MV88E6XXX_HW_STAT_ENUM)
+
+ MV88E6XXX_HW_STAT_ID_MAX
+};
+
+
+#define MV88E6XXX_HW_STAT_ENUM(_string, _size, _reg, _type) \
+ MV88E6XXX_HW_STAT_ID_ ## _string
+enum mv88e6xxx_hw_stat_id {
+ MV88E6XXX_HW_STAT_MAPPER(MV88E6XXX_HW_STAT_ENUM)
};
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
const struct mv88e6xxx_hw_stat *s,
int port, u16 bank1_select,
@@ -1125,7 +1140,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
@@ -1055,7 +1067,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
uint8_t *data, int types)
{
@@ -174,7 +172,7 @@ index 139f4d55a284..4afe5c212a36 100644
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
@@ -1206,7 +1221,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
@@ -1136,7 +1148,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
int types)
{
@@ -183,13 +181,13 @@ index 139f4d55a284..4afe5c212a36 100644
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
@@ -1333,7 +1348,7 @@ static int mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
@@ -1263,7 +1275,7 @@ static size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
static size_t mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
- struct mv88e6xxx_hw_stat *stat;
+ const struct mv88e6xxx_hw_stat *stat;
int i, j;
size_t i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
--
@@ -0,0 +1,78 @@
From 26815572016d9851ec6362f23746035fb933acf3 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 14 Dec 2023 14:50:26 +0100
Subject: [PATCH 05/19] net: dsa: mv88e6xxx: Add "eth-mac" counter group
support
Organization: Addiva Elektronik
Report the applicable subset of an mv88e6xxx port's counters using
ethtool's standardized "eth-mac" counter group.
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mv88e6xxx/chip.c | 39 ++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80787f1e205c..8daed568582f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1330,6 +1330,44 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
}
+static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int ret;
+
+ ret = mv88e6xxx_stats_snapshot(chip, port);
+ if (ret < 0)
+ return;
+
+#define MV88E6XXX_ETH_MAC_STAT_MAP(_id, _member) \
+ mv88e6xxx_stats_get_stat(chip, port, \
+ &mv88e6xxx_hw_stats[MV88E6XXX_HW_STAT_ID_ ## _id], \
+ &mac_stats->stats._member)
+
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_unicast, FramesTransmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(single, SingleCollisionFrames);
+ MV88E6XXX_ETH_MAC_STAT_MAP(multiple, MultipleCollisionFrames);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_unicast, FramesReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_fcs_error, FrameCheckSequenceErrors);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_octets, OctetsTransmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(deferred, FramesWithDeferredXmissions);
+ MV88E6XXX_ETH_MAC_STAT_MAP(late, LateCollisions);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_good_octets, OctetsReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_multicasts, MulticastFramesXmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_broadcasts, BroadcastFramesXmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(excessive, FramesWithExcessiveDeferral);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_multicasts, MulticastFramesReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_broadcasts, BroadcastFramesReceivedOK);
+
+#undef MV88E6XXX_ETH_MAC_STAT_MAP
+
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.MulticastFramesXmittedOK;
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.BroadcastFramesXmittedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.MulticastFramesReceivedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.BroadcastFramesReceivedOK;
+}
+
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -6851,6 +6889,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
+ .get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.port_max_mtu = mv88e6xxx_get_max_mtu,
.port_change_mtu = mv88e6xxx_change_mtu,
--
2.34.1
@@ -1,91 +0,0 @@
From a85c55f3232d402780a22d42859bdc81150469b4 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 6 Sep 2023 10:55:53 +0200
Subject: [PATCH 05/20] net: dsa: mv88e6xxx: Add "rmon" counter group support
Organization: Addiva Elektronik
After this change, mv88e6xxx ports can report the applicable subset of
their counters using ethtool's standardized "rmon" counter group.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 56 ++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2cfc072b41b1..90dcd6c3be31 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1454,6 +1454,61 @@ static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
mac_stats->stats.FramesReceivedOK += mac_stats->stats.BroadcastFramesReceivedOK;
}
+static void mv88e6xxx_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+#define MV88E6XXX_RMON_STAT_MAPPING(_id, _member) \
+ [MV88E6XXX_HW_STAT_ID_ ## _id] = \
+ offsetof(struct ethtool_rmon_stats, stats._member) \
+
+ static const size_t stat_map[MV88E6XXX_HW_STAT_ID_MAX] = {
+ MV88E6XXX_RMON_STAT_MAPPING(in_undersize, undersize_pkts),
+ MV88E6XXX_RMON_STAT_MAPPING(in_oversize, oversize_pkts),
+ MV88E6XXX_RMON_STAT_MAPPING(in_fragments, fragments),
+ MV88E6XXX_RMON_STAT_MAPPING(in_jabber, jabbers),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_64bytes, hist[0]),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_65_127bytes, hist[1]),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_128_255bytes, hist[2]),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_256_511bytes, hist[3]),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_512_1023bytes, hist[4]),
+ MV88E6XXX_RMON_STAT_MAPPING(hist_1024_max_bytes, hist[5]),
+ };
+ static const struct ethtool_rmon_hist_range rmon_ranges[] = {
+ { 64, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 65535 },
+ {}
+ };
+ struct mv88e6xxx_chip *chip = ds->priv;
+ const struct mv88e6xxx_hw_stat *stat;
+ enum mv88e6xxx_hw_stat_id id;
+ u64 *member;
+ int ret;
+
+ mv88e6xxx_reg_lock(chip);
+ ret = mv88e6xxx_stats_snapshot(chip, port);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (ret < 0)
+ return;
+
+ stat = mv88e6xxx_hw_stats;
+ for (id = 0; id < MV88E6XXX_HW_STAT_ID_MAX; id++, stat++) {
+ if (!stat_map[id])
+ continue;
+
+ member = (u64 *)(((char *)rmon_stats) + stat_map[id]);
+ mv88e6xxx_stats_get_stat(chip, port, stat, member);
+ }
+
+ *ranges = rmon_ranges;
+}
+
+
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -7214,6 +7269,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
+ .get_rmon_stats = mv88e6xxx_get_rmon_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.port_enable = mv88e6xxx_port_enable,
.port_disable = mv88e6xxx_port_disable,
--
2.34.1
@@ -1,40 +0,0 @@
From 6f684b1b9eb8a307b77aa4baa8531e2c423112af Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 21 Sep 2023 11:10:26 +0200
Subject: [PATCH 06/20] arm64: dts: marvell: cp11x: Provide clock names for
MDIO controllers
Organization: Addiva Elektronik
This will let the driver figure out the rate of the core clk, such
that custom MDC frequencies can be supported.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
arch/arm64/boot/dts/marvell/armada-cp11x.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi
index 4ec1aae0a3a9..f268017498a9 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi
@@ -180,6 +180,8 @@ CP11X_LABEL(mdio): mdio@12a200 {
reg = <0x12a200 0x10>;
clocks = <&CP11X_LABEL(clk) 1 9>, <&CP11X_LABEL(clk) 1 5>,
<&CP11X_LABEL(clk) 1 6>, <&CP11X_LABEL(clk) 1 18>;
+ clock-names = "gop_clk", "mg_clk",
+ "mg_core_clk", "axi_clk";
status = "disabled";
};
@@ -190,6 +192,8 @@ CP11X_LABEL(xmdio): mdio@12a600 {
reg = <0x12a600 0x10>;
clocks = <&CP11X_LABEL(clk) 1 5>,
<&CP11X_LABEL(clk) 1 6>, <&CP11X_LABEL(clk) 1 18>;
+ clock-names = "mg_clk",
+ "mg_core_clk", "axi_clk";
status = "disabled";
};
--
2.34.1
@@ -0,0 +1,100 @@
From cc5badac76e76692eb516a5c086fcf54a5a93080 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 14 Dec 2023 14:50:27 +0100
Subject: [PATCH 06/19] net: dsa: mv88e6xxx: Limit histogram counters to
ingress traffic
Organization: Addiva Elektronik
Chips in this family only have one set of histogram counters, which
can be used to count ingressing and/or egressing traffic. mv88e6xxx
has, up until this point, kept the hardware default of counting both
directions.
In the mean time, standard counter group support has been added to
ethtool. Via that interface, drivers may report ingress-only and
egress-only histograms separately - but not combined.
In order for mv88e6xxx to maximize amount of diagnostic information
that can be exported via standard interfaces, we opt to limit the
histogram counters to ingress traffic only. Which will allow us to
export them via the standard "rmon" group in an upcoming commit.
The reason for choosing ingress-only over egress-only, is to be
compatible with RFC2819 (RMON MIB).
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mv88e6xxx/chip.c | 6 +++---
drivers/net/dsa/mv88e6xxx/global1.c | 7 +++----
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8daed568582f..1b3a5b0b2b25 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1215,7 +1215,7 @@ static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
return 0;
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
}
@@ -1227,7 +1227,7 @@ static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
return 0;
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
}
@@ -1240,7 +1240,7 @@ static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
*data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
return 1;
}
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 174c773b38c2..49444a72ff09 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -462,8 +462,7 @@ int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip)
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_HIST_MODE_MASK,
- MV88E6390_G1_CTL2_HIST_MODE_RX |
- MV88E6390_G1_CTL2_HIST_MODE_TX);
+ MV88E6390_G1_CTL2_HIST_MODE_RX);
}
int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index)
@@ -491,7 +490,7 @@ int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
if (err)
return err;
- val |= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
+ val |= MV88E6XXX_G1_STATS_OP_HIST_RX;
err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
@@ -506,7 +505,7 @@ int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
MV88E6XXX_G1_STATS_OP_BUSY |
MV88E6XXX_G1_STATS_OP_CAPTURE_PORT |
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX | port);
+ MV88E6XXX_G1_STATS_OP_HIST_RX | port);
if (err)
return err;
--
2.34.1
@@ -0,0 +1,80 @@
From 35ecc84237bfccbe5b93c0aef6c07cc506d43070 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 14 Dec 2023 14:50:28 +0100
Subject: [PATCH 07/19] net: dsa: mv88e6xxx: Add "rmon" counter group support
Organization: Addiva Elektronik
Report the applicable subset of an mv88e6xxx port's counters using
ethtool's standardized "rmon" counter group.
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/mv88e6xxx/chip.c | 42 ++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 1b3a5b0b2b25..f4b61fcd4541 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1368,6 +1368,47 @@ static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
mac_stats->stats.FramesReceivedOK += mac_stats->stats.BroadcastFramesReceivedOK;
}
+static void mv88e6xxx_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ static const struct ethtool_rmon_hist_range rmon_ranges[] = {
+ { 64, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 65535 },
+ {}
+ };
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int ret;
+
+ ret = mv88e6xxx_stats_snapshot(chip, port);
+ if (ret < 0)
+ return;
+
+#define MV88E6XXX_RMON_STAT_MAP(_id, _member) \
+ mv88e6xxx_stats_get_stat(chip, port, \
+ &mv88e6xxx_hw_stats[MV88E6XXX_HW_STAT_ID_ ## _id], \
+ &rmon_stats->stats._member)
+
+ MV88E6XXX_RMON_STAT_MAP(in_undersize, undersize_pkts);
+ MV88E6XXX_RMON_STAT_MAP(in_oversize, oversize_pkts);
+ MV88E6XXX_RMON_STAT_MAP(in_fragments, fragments);
+ MV88E6XXX_RMON_STAT_MAP(in_jabber, jabbers);
+ MV88E6XXX_RMON_STAT_MAP(hist_64bytes, hist[0]);
+ MV88E6XXX_RMON_STAT_MAP(hist_65_127bytes, hist[1]);
+ MV88E6XXX_RMON_STAT_MAP(hist_128_255bytes, hist[2]);
+ MV88E6XXX_RMON_STAT_MAP(hist_256_511bytes, hist[3]);
+ MV88E6XXX_RMON_STAT_MAP(hist_512_1023bytes, hist[4]);
+ MV88E6XXX_RMON_STAT_MAP(hist_1024_max_bytes, hist[5]);
+
+#undef MV88E6XXX_RMON_STAT_MAP
+
+ *ranges = rmon_ranges;
+}
+
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
@@ -6890,6 +6931,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
+ .get_rmon_stats = mv88e6xxx_get_rmon_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.port_max_mtu = mv88e6xxx_get_max_mtu,
.port_change_mtu = mv88e6xxx_change_mtu,
--
2.34.1
@@ -1,120 +0,0 @@
From d5e03e7b44c8ac414927751097d8d65caffc33b4 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:19:40 +0200
Subject: [PATCH 07/20] net: mvmdio: Avoid excessive sleeps in polled mode
Organization: Addiva Elektronik
Before this change, when operating in polled mode, i.e. no IRQ is
available, every individual C45 access would be hit with a 150us sleep
after the bus access.
For example, on a board with a CN9130 SoC connected to an MV88X3310
PHY, a single C45 read would take around 165us:
root@infix:~$ mdio f212a600.mdio-mii mmd 4:1 bench 0xc003
Performed 1000 reads in 165ms
By replacing the long sleep with a tighter poll loop, we observe a 10x
increase in bus throughput:
root@infix:~$ mdio f212a600.mdio-mii mmd 4:1 bench 0xc003
Performed 1000 reads in 15ms
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/ethernet/marvell/mvmdio.c | 41 +++++++++++----------------
1 file changed, 16 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 8662543ca5c8..37e20c2702b5 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -58,11 +59,6 @@
* - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled)
*/
#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
-#define MVMDIO_SMI_POLL_INTERVAL_MIN 45
-#define MVMDIO_SMI_POLL_INTERVAL_MAX 55
-
-#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150
-#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160
struct orion_mdio_dev {
void __iomem *regs;
@@ -84,8 +80,6 @@ enum orion_mdio_bus_type {
struct orion_mdio_ops {
int (*is_done)(struct orion_mdio_dev *);
- unsigned int poll_interval_min;
- unsigned int poll_interval_max;
};
/* Wait for the SMI unit to be ready for another operation
@@ -94,23 +88,24 @@ static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
struct mii_bus *bus)
{
struct orion_mdio_dev *dev = bus->priv;
- unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
- unsigned long end = jiffies + timeout;
- int timedout = 0;
+ unsigned long end, timeout;
+ int done, timedout;
- while (1) {
- if (ops->is_done(dev))
+ if (dev->err_interrupt <= 0) {
+ if (!read_poll_timeout_atomic(ops->is_done, done, done, 2,
+ MVMDIO_SMI_TIMEOUT, false, dev))
return 0;
- else if (timedout)
- break;
-
- if (dev->err_interrupt <= 0) {
- usleep_range(ops->poll_interval_min,
- ops->poll_interval_max);
+ } else {
+ timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
+ end = jiffies + timeout;
+ timedout = 0;
+
+ while (1) {
+ if (ops->is_done(dev))
+ return 0;
+ else if (timedout)
+ break;
- if (time_is_before_jiffies(end))
- ++timedout;
- } else {
/* wait_event_timeout does not guarantee a delay of at
* least one whole jiffie, so timeout must be no less
* than two.
@@ -135,8 +130,6 @@ static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
static const struct orion_mdio_ops orion_mdio_smi_ops = {
.is_done = orion_mdio_smi_is_done,
- .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
- .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
};
static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
@@ -194,8 +187,6 @@ static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
.is_done = orion_mdio_xsmi_is_done,
- .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
- .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
};
static int orion_mdio_xsmi_read_c45(struct mii_bus *bus, int mii_id,
--
2.34.1
View File
@@ -1,7 +1,7 @@
From 913a57a304e8024f4cea872fa904cee867c469a2 Mon Sep 17 00:00:00 2001
From 7750d0a5bfae46ab783e8e7087b70175860f808c Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 16 Nov 2023 19:44:32 +0100
Subject: [PATCH 14/20] net: dsa: mv88e6xxx: Add LED infrastructure
Subject: [PATCH 09/19] net: dsa: mv88e6xxx: Add LED infrastructure
Organization: Addiva Elektronik
Parse DT for LEDs and register them for devices that support it,
@@ -10,16 +10,16 @@ though no actual implementations exist yet.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 8 +-
drivers/net/dsa/mv88e6xxx/chip.h | 17 +++
drivers/net/dsa/mv88e6xxx/chip.c | 5 +-
drivers/net/dsa/mv88e6xxx/chip.h | 16 +++
drivers/net/dsa/mv88e6xxx/leds.c | 184 +++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/leds.h | 12 ++
5 files changed, 221 insertions(+), 1 deletion(-)
5 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c
create mode 100644 drivers/net/dsa/mv88e6xxx/leds.h
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 1409e691ab77..ab07996aeb7f 100644
index a9a9651187db..6720d9303914 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
@@ -27,11 +27,11 @@ index 1409e691ab77..ab07996aeb7f 100644
mv88e6xxx-objs += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
+mv88e6xxx-objs += leds.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
mv88e6xxx-objs += pcs-6185.o
mv88e6xxx-objs += pcs-6352.o
mv88e6xxx-objs += pcs-639x.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 90dcd6c3be31..d343ea5cc4a1 100644
index f4b61fcd4541..a3016d5e005d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -37,6 +37,7 @@
@@ -42,32 +42,25 @@ index 90dcd6c3be31..d343ea5cc4a1 100644
#include "phy.h"
#include "port.h"
#include "ptp.h"
@@ -4259,11 +4260,16 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
@@ -4012,7 +4013,9 @@ static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
return err;
}
static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
{
- return mv88e6xxx_setup_devlink_regions_port(ds, port);
+ int err = 0;
+
+ err = err ? : mv88e6xxx_setup_devlink_regions_port(ds, port);
+ err = err ? : mv88e6xxx_port_setup_leds(ds, port);
+ return err;
}
static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
{
+ /* LED resources are devm_ managed */
mv88e6xxx_teardown_devlink_regions_port(ds, port);
}
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 268c97cde8d8..fb0d2584af1b 100644
index 85eb293381a7..d0dca152e714 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -205,6 +205,7 @@ struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops;
@@ -206,6 +206,7 @@ struct mv88e6xxx_gpio_ops;
struct mv88e6xxx_avb_ops;
struct mv88e6xxx_ptp_ops;
struct mv88e6xxx_pcs_ops;
+struct mv88e6xxx_led_ops;
struct mv88e6xxx_irq {
@@ -81,7 +74,7 @@ index 268c97cde8d8..fb0d2584af1b 100644
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
@@ -672,6 +675,9 @@ struct mv88e6xxx_ops {
@@ -653,6 +656,9 @@ struct mv88e6xxx_ops {
/* Precision Time Protocol operations */
const struct mv88e6xxx_ptp_ops *ptp_ops;
@@ -91,9 +84,11 @@ index 268c97cde8d8..fb0d2584af1b 100644
/* Phylink */
void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port,
struct phylink_config *config);
@@ -748,6 +754,17 @@ struct mv88e6xxx_ptp_ops {
u32 cc_mult_dem;
};
@@ -736,7 +742,17 @@ struct mv88e6xxx_pcs_ops {
void (*pcs_teardown)(struct mv88e6xxx_chip *chip, int port);
struct phylink_pcs *(*pcs_select)(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode);
+};
+struct mv88e6xxx_led_ops {
+ int (*brightness_set)(struct mv88e6xxx_led *led,
@@ -104,11 +99,9 @@ index 268c97cde8d8..fb0d2584af1b 100644
+ unsigned long flags);
+ int (*hw_control_set)(struct mv88e6xxx_led *led, unsigned long flags);
+ int (*hw_control_get)(struct mv88e6xxx_led *led, unsigned long *flags);
+};
+
};
static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip)
{
return chip->info->max_sid > 0 &&
diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c
new file mode 100644
index 000000000000..42e1661e1f47
@@ -1,200 +0,0 @@
From 46bbea6b9d692ac7460e4e278cedee9f88b6da0b Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:38:10 +0200
Subject: [PATCH 09/20] net: phy: marvell10g: Support firmware loading on
88X3310
Organization: Addiva Elektronik
If a device is found waiting for firmware to be loaded into its RAM,
ask userspace for the binary and load it over XMDIO.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/marvell10g.c | 143 +++++++++++++++++++++++++++++++++++
1 file changed, 143 insertions(+)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index d4bb90d76881..155f439d9c1c 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -25,6 +25,7 @@
#include <linux/bitfield.h>
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
#include <linux/phy.h>
@@ -50,6 +51,13 @@ enum {
MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_PMA_BOOT = 0xc050,
MV_PMA_BOOT_FATAL = BIT(0),
+ MV_PMA_BOOT_PRGS_MASK = 0x0006,
+ MV_PMA_BOOT_PRGS_INIT = 0x0000,
+ MV_PMA_BOOT_PRGS_WAIT = 0x0002,
+ MV_PMA_BOOT_PRGS_CSUM = 0x0004,
+ MV_PMA_BOOT_PRGS_JRAM = 0x0006,
+ MV_PMA_BOOT_APP_STARTED = BIT(4),
+ MV_PMA_BOOT_APP_LOADED = BIT(6),
MV_PCS_BASE_T = 0x0000,
MV_PCS_BASE_R = 0x1000,
@@ -96,6 +104,12 @@ enum {
MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
+ /* Firmware downloading */
+ MV_PCS_FW_ADDR_LOW = 0xd0f0,
+ MV_PCS_FW_ADDR_HIGH = 0xd0f1,
+ MV_PCS_FW_DATA = 0xd0f2,
+ MV_PCS_FW_CSUM = 0xd0f3,
+
/* SerDes reinitialization 88E21X0 */
MV_AN_21X0_SERDES_CTRL2 = 0x800f,
MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13),
@@ -499,6 +513,129 @@ static const struct sfp_upstream_ops mv3310_sfp_ops = {
.module_insert = mv3310_sfp_insert,
};
+struct mv3310_fw_hdr {
+ struct {
+ u32 size;
+ u32 addr;
+ u16 csum;
+ } __packed data;
+
+ u8 flags;
+#define MV3310_FW_HDR_DATA_ONLY BIT(6)
+
+ u8 port_skip;
+ u32 next_hdr;
+ u16 csum;
+
+ u8 pad[14];
+} __packed;
+
+static int mv3310_load_fw_sect(struct phy_device *phydev,
+ const struct mv3310_fw_hdr *hdr, const u8 *data)
+{
+ int err = 0;
+ size_t i;
+ u16 csum;
+
+ dev_dbg(&phydev->mdio.dev, "Loading %u byte %s section at 0x%08x\n",
+ hdr->data.size,
+ (hdr->flags & MV3310_FW_HDR_DATA_ONLY) ? "data" : "executable",
+ hdr->data.addr);
+
+ for (i = 0, csum = 0; i < hdr->data.size; i++)
+ csum += data[i];
+
+ if ((u16)~csum != hdr->data.csum) {
+ dev_err(&phydev->mdio.dev, "Corrupt section data\n");
+ return -EINVAL;
+ }
+
+ phy_lock_mdio_bus(phydev);
+
+ /* Any existing checksum is cleared by a read */
+ __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM);
+
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_LOW, hdr->data.addr & 0xffff);
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_HIGH, hdr->data.addr >> 16);
+
+ for (i = 0; i < hdr->data.size; i += 2) {
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_DATA,
+ (data[i + 1] << 8) | data[i]);
+ }
+
+ csum = __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM);
+ if ((u16)~csum != hdr->data.csum) {
+ dev_err(&phydev->mdio.dev, "Download failed\n");
+ err = -EIO;
+ goto unlock;
+ }
+
+ if (hdr->flags & MV3310_FW_HDR_DATA_ONLY)
+ goto unlock;
+
+ __phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT, 0, MV_PMA_BOOT_APP_LOADED);
+ mdelay(200);
+ if (!(__phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT) & MV_PMA_BOOT_APP_STARTED)) {
+ dev_err(&phydev->mdio.dev, "Application did not startup\n");
+ err = -ENOSYS;
+ }
+
+unlock:
+ phy_unlock_mdio_bus(phydev);
+ return err;
+}
+
+static int mv3310_load_fw(struct phy_device *phydev)
+{
+ const struct firmware *fw;
+ struct mv3310_fw_hdr hdr;
+ const u8 *sect;
+ size_t i;
+ u16 csum;
+ int err;
+
+ /* dev_info(&phydev->mdio.dev, "Requ */
+ err = request_firmware(&fw, "x33x0fw.hdr", &phydev->mdio.dev);
+ if (err)
+ return err;
+
+ if (fw->size & 1) {
+ err = -EINVAL;
+ goto release;
+ }
+
+ for (sect = fw->data; (sect + sizeof(hdr)) < (fw->data + fw->size);) {
+ memcpy(&hdr, sect, sizeof(hdr));
+ hdr.data.size = cpu_to_le32(hdr.data.size);
+ hdr.data.addr = cpu_to_le32(hdr.data.addr);
+ hdr.data.csum = cpu_to_le16(hdr.data.csum);
+ hdr.next_hdr = cpu_to_le32(hdr.next_hdr);
+ hdr.csum = cpu_to_le16(hdr.csum);
+
+ for (i = 0, csum = 0; i < offsetof(struct mv3310_fw_hdr, csum); i++)
+ csum += sect[i];
+
+ if ((u16)~csum != hdr.csum) {
+ dev_err(&phydev->mdio.dev, "Corrupt section header\n");
+ err = -EINVAL;
+ break;
+ }
+
+ err = mv3310_load_fw_sect(phydev, &hdr, sect + sizeof(hdr));
+ if (err)
+ break;
+
+ if (!hdr.next_hdr)
+ break;
+
+ sect = fw->data + hdr.next_hdr;
+ }
+
+release:
+ release_firmware(fw);
+ return err;
+}
+
static int mv3310_probe(struct phy_device *phydev)
{
const struct mv3310_chip *chip = to_mv3310_chip(phydev);
@@ -520,6 +657,12 @@ static int mv3310_probe(struct phy_device *phydev)
return -ENODEV;
}
+ if ((ret & MV_PMA_BOOT_PRGS_MASK) == MV_PMA_BOOT_PRGS_WAIT) {
+ ret = mv3310_load_fw(phydev);
+ if (ret)
+ return ret;
+ }
+
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
--
2.34.1
@@ -1,64 +0,0 @@
From 312d3efde0fbe7cec3bf7ba1908c213c9cf69337 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:33 +0200
Subject: [PATCH 10/20] led: trig: netdev: Fix requesting offload device
Organization: Addiva Elektronik
When the netdev trigger is activates, it tries to determine what
device the LED blinks for, and what the current blink mode is.
The documentation for hw_control_get() says:
* Return 0 on success, a negative error number on failing parsing the
* initial mode. Error from this function is NOT FATAL as the device
* may be in a not supported initial state by the attached LED trigger.
*/
For the Marvell PHY and the Armada 370-rd board, the initial LED blink
mode is not supported by the trigger, so it returns an error. This
resulted in not getting the device the LED is blinking for. As a
result, the device is unknown and offloaded is never performed.
Change to condition to always get the device if offloading is
supported, and reduce the scope of testing for an error from
hw_control_get() to skip setting trigger internal state if there is an
error.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-2-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/leds/trigger/ledtrig-netdev.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 03c58e50cc44..e9e4da217249 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -564,15 +564,17 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
/* Check if hw control is active by default on the LED.
* Init already enabled mode in hw control.
*/
- if (supports_hw_control(led_cdev) &&
- !led_cdev->hw_control_get(led_cdev, &mode)) {
+ if (supports_hw_control(led_cdev)) {
dev = led_cdev->hw_control_get_device(led_cdev);
if (dev) {
const char *name = dev_name(dev);
set_device_name(trigger_data, name, strlen(name));
trigger_data->hw_control = true;
- trigger_data->mode = mode;
+
+ rc = led_cdev->hw_control_get(led_cdev, &mode);
+ if (!rc)
+ trigger_data->mode = mode;
}
}
--
2.34.1
@@ -1,7 +1,7 @@
From 8510028fa738493a46b235057ed166f9bbbf0ed4 Mon Sep 17 00:00:00 2001
From 63fcd626fdb108d2ac07cb0aa16b91fc43894bff Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 16 Nov 2023 21:59:35 +0100
Subject: [PATCH 15/20] net: dsa: mv88e6xxx: Add LED support for 6393X
Subject: [PATCH 10/19] net: dsa: mv88e6xxx: Add LED support for 6393X
Organization: Addiva Elektronik
Trigger support:
@@ -19,17 +19,17 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
5 files changed, 269 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index d343ea5cc4a1..7d6b2b85fc31 100644
index a3016d5e005d..ed4dec48a6f8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -5833,6 +5833,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
@@ -5492,6 +5492,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
+ .led_ops = &mv88e6393x_led_ops,
.phylink_get_caps = mv88e6393x_phylink_get_caps,
.pcs_ops = &mv88e6393x_pcs_ops,
};
diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c
index 42e1661e1f47..b2a55d96b506 100644
--- a/drivers/net/dsa/mv88e6xxx/leds.c
@@ -288,10 +288,10 @@ index 8afa2a0c0527..542345d23dc5 100644
#endif /* _MV88E6XXX_LEDS_H */
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index dd66ec902d4c..e6733a3ab19f 100644
index 5394a8cf7bf1..66073a1ef260 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1569,6 +1569,39 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
@@ -1539,6 +1539,39 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
}
@@ -1,38 +0,0 @@
From 83322015e7960ba0f1f3698e36333cfb6aecb931 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:36 +0200
Subject: [PATCH 11/20] leds: trig-netdev: Disable offload on deactivation of
trigger
Organization: Addiva Elektronik
Ensure that the offloading of blinking is stopped when the trigger is
deactivated. Calling led_set_brightness() is documented as stopping
offload and setting the LED to a constant brightness.
Suggested-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-5-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/leds/trigger/ledtrig-netdev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index e9e4da217249..cc3261543a5e 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -595,6 +595,8 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev)
cancel_delayed_work_sync(&trigger_data->work);
+ led_set_brightness(led_cdev, LED_OFF);
+
dev_put(trigger_data->net_dev);
kfree(trigger_data);
--
2.34.1
@@ -1,7 +1,7 @@
From f65e3c7e250d2a3775041bf894e5b8d051b5da98 Mon Sep 17 00:00:00 2001
From 0bc6f19d18d7c0e374c824bcc86433b04210a378 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 12 Mar 2024 10:27:24 +0100
Subject: [PATCH 20/20] net: dsa: mv88e6xxx: Fix timeout on waiting for PPU on
Subject: [PATCH 11/19] net: dsa: mv88e6xxx: Fix timeout on waiting for PPU on
6393X
Organization: Addiva Elektronik
@@ -15,7 +15,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7d6b2b85fc31..109456d74691 100644
index ed4dec48a6f8..f9e78610a55e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -87,7 +87,7 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
@@ -0,0 +1,74 @@
From fe60e3ad1e3b43a924c311658b15a1106e813661 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 16 Jan 2024 16:00:55 +0100
Subject: [PATCH 12/19] net: dsa: Support MDB memberships whose L2 addresses
overlap
Organization: Addiva Elektronik
Multiple IP multicast groups (32 for v4, 2^80 for v6) map to the same
L2 address. This means that switchdev drivers may receive multiple MDB
additions for a particular L2 group on the same port. Since these were
not reference counted before this change, removing a group membership
after two overlapping memberships had been added would result in the
membership being removed from hardware, even though one reference to
the address still remained.
Steps to reproduce:
root@infix:~# mvls atu | grep 01:02:03
root@infix:~# bridge mdb add dev br0 port e8 grp 238.1.2.3 permanent
root@infix:~# bridge mdb add dev br0 port e8 grp 239.1.2.3 permanent
root@infix:~# mvls atu | grep 01:02:03
01:00:5e:01:02:03 1 static - - . . . . . . . . 8 . .
root@infix:~# bridge mdb del dev br0 port e8 grp 239.1.2.3
root@infix:~# mvls atu | grep 01:02:03
root@infix:~#
Therefore, reference count MDB memberships and keep them in hardware
as long as the count is positive. Fortunately, all the infrastructure
needed to do this is already in place, since it is also needed on CPU
and DSA ports. Thus, "implement" this by simply removing the guards
which previously skipped reference countung on user ports.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
net/dsa/switch.c | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 1a42f9317334..2ad13e23635e 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -164,14 +164,6 @@ static int dsa_port_do_mdb_add(struct dsa_port *dp,
int port = dp->index;
int err = 0;
- /* No need to bother with refcounting for user ports */
- if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp))) {
- err = ds->ops->port_mdb_add(ds, port, mdb, db);
- trace_dsa_mdb_add_hw(dp, mdb->addr, mdb->vid, &db, err);
-
- return err;
- }
-
mutex_lock(&dp->addr_lists_lock);
a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid, db);
@@ -216,14 +208,6 @@ static int dsa_port_do_mdb_del(struct dsa_port *dp,
int port = dp->index;
int err = 0;
- /* No need to bother with refcounting for user ports */
- if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp))) {
- err = ds->ops->port_mdb_del(ds, port, mdb, db);
- trace_dsa_mdb_del_hw(dp, mdb->addr, mdb->vid, &db, err);
-
- return err;
- }
-
mutex_lock(&dp->addr_lists_lock);
a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid, db);
--
2.34.1
@@ -1,158 +0,0 @@
From a4f09c743da21f09b0fcc6e5842d665490f9f70e Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:34 +0200
Subject: [PATCH 12/20] net: phy: phy_device: Call into the PHY driver to set
LED offload
Organization: Addiva Elektronik
Linux LEDs can be requested to perform hardware accelerated blinking
to indicate link, RX, TX etc. Pass the rules for blinking to the PHY
driver, if it implements the ops needed to determine if a given
pattern can be offloaded, to offload it, and what the current offload
is. Additionally implement the op needed to get what device the LED is
for.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/phy_device.c | 68 ++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 33 +++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c7cf61fe41cf..d096d9d63617 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3020,6 +3020,61 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
return err;
}
+static __maybe_unused struct device *
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+
+ if (phydev->attached_dev)
+ return &phydev->attached_dev->dev;
+ return NULL;
+}
+
+static int __maybe_unused
+phy_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int __maybe_unused
+phy_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
@@ -3057,6 +3112,19 @@ static int of_phy_led(struct phy_device *phydev,
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ if (phydev->drv->led_hw_is_supported &&
+ phydev->drv->led_hw_control_set &&
+ phydev->drv->led_hw_control_get) {
+ cdev->hw_control_is_supported = phy_led_hw_is_supported;
+ cdev->hw_control_set = phy_led_hw_control_set;
+ cdev->hw_control_get = phy_led_hw_control_get;
+ cdev->hw_control_trigger = "netdev";
+ }
+
+ cdev->hw_control_get_device = phy_led_hw_control_get_device;
+#endif
cdev->max_brightness = 1;
init_data.devicename = dev_name(&phydev->mdio.dev);
init_data.fwnode = of_fwnode_handle(led);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 11c1e91563d4..0f9e4598c596 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1104,6 +1104,39 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);
+ /**
+ * @led_hw_is_supported: Can the HW support the given rules.
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The core is interested in these rules
+ *
+ * Return 0 if yes, -EOPNOTSUPP if not, or an error code.
+ */
+ int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_set: Set the HW to control the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The rules used to control the LED
+ *
+ * Returns 0, or a an error code.
+ */
+ int (*led_hw_control_set)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_get: Get how the HW is controlling the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules Pointer to the rules used to control the LED
+ *
+ * Set *@rules to how the HW is currently blinking. Returns 0
+ * on success, or a error code if the current blinking cannot
+ * be represented in rules, or some other error happens.
+ */
+ int (*led_hw_control_get)(struct phy_device *dev, u8 index,
+ unsigned long *rules);
+
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
--
2.34.1
@@ -0,0 +1,241 @@
From 5f5bf4a50e98c5aff05fe85994a981253ae85987 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:38:10 +0200
Subject: [PATCH 13/19] net: phy: marvell10g: Support firmware loading on
88X3310
Organization: Addiva Elektronik
When probing, if a device is waiting for firmware to be loaded into
its RAM, ask userspace for the binary and load it over XMDIO.
We have no choice but to bail out of the probe if firmware is not
available, as the device does not have any built-in image on which to
fall back.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/marvell10g.c | 161 +++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index d4bb90d76881..ec9ea5e947f9 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -25,6 +25,7 @@
#include <linux/bitfield.h>
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
#include <linux/phy.h>
@@ -50,6 +51,10 @@ enum {
MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_PMA_BOOT = 0xc050,
MV_PMA_BOOT_FATAL = BIT(0),
+ MV_PMA_BOOT_PRGS_MASK = 0x0006,
+ MV_PMA_BOOT_PRGS_WAIT = 0x0002,
+ MV_PMA_BOOT_APP_STARTED = BIT(4),
+ MV_PMA_BOOT_APP_LOADED = BIT(6),
MV_PCS_BASE_T = 0x0000,
MV_PCS_BASE_R = 0x1000,
@@ -96,6 +101,12 @@ enum {
MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
+ /* Firmware downloading */
+ MV_PCS_FW_ADDR_LOW = 0xd0f0,
+ MV_PCS_FW_ADDR_HIGH = 0xd0f1,
+ MV_PCS_FW_DATA = 0xd0f2,
+ MV_PCS_FW_CSUM = 0xd0f3,
+
/* SerDes reinitialization 88E21X0 */
MV_AN_21X0_SERDES_CTRL2 = 0x800f,
MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13),
@@ -149,6 +160,8 @@ struct mv3310_chip {
int (*select_mactype)(unsigned long *interfaces);
int (*init_interface)(struct phy_device *phydev, int mactype);
+ const char *firmware_path;
+
#ifdef CONFIG_HWMON
int (*hwmon_read_temp_reg)(struct phy_device *phydev);
#endif
@@ -499,6 +512,145 @@ static const struct sfp_upstream_ops mv3310_sfp_ops = {
.module_insert = mv3310_sfp_insert,
};
+struct mv3310_fw_hdr {
+ __le32 data_size;
+ __le32 data_addr;
+ __le16 data_csum;
+ __le16 flags;
+#define MV3310_FW_HDR_DATA_ONLY BIT(6)
+ __le32 next_hdr;
+ __le16 csum;
+
+ u8 pad[14];
+} __packed;
+
+struct mv3310_fw_sect_info {
+ const u8 *data;
+ u32 size;
+ u32 addr;
+ u16 csum;
+};
+
+static int mv3310_load_fw_sect(struct phy_device *phydev,
+ const struct mv3310_fw_sect_info *si)
+{
+ size_t i;
+ u16 csum;
+
+ dev_dbg(&phydev->mdio.dev, "Loading %u byte section at 0x%08x\n",
+ si->size, si->addr);
+
+ for (i = 0, csum = 0; i < si->size; i++)
+ csum += si->data[i];
+
+ if ((u16)~csum != si->csum) {
+ dev_err(&phydev->mdio.dev, "Corrupt section data\n");
+ return -EINVAL;
+ }
+
+ /* Any existing checksum is cleared by a read */
+ __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM);
+
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_LOW, si->addr & 0xffff);
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_ADDR_HIGH, si->addr >> 16);
+
+ for (i = 0; i < si->size; i += 2) {
+ __phy_write_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_DATA,
+ (si->data[i + 1] << 8) | si->data[i]);
+ }
+
+ csum = __phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_FW_CSUM);
+ if ((u16)~csum != si->csum) {
+ dev_err(&phydev->mdio.dev, "Download failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mv3310_load_fw(struct phy_device *phydev)
+{
+ const struct mv3310_chip *chip = to_mv3310_chip(phydev);
+ struct mv3310_fw_sect_info si;
+ const struct firmware *fw;
+ struct mv3310_fw_hdr hdr;
+ bool need_boot = false;
+ const u8 *sect;
+ size_t i;
+ u32 next;
+ u16 csum;
+ int err;
+
+ if (!chip->firmware_path)
+ return -EOPNOTSUPP;
+
+ err = request_firmware(&fw, chip->firmware_path, &phydev->mdio.dev);
+ if (err)
+ return err;
+
+ if (fw->size & 1) {
+ err = -EINVAL;
+ goto release;
+ }
+
+ phy_lock_mdio_bus(phydev);
+
+ for (sect = fw->data; (sect + sizeof(hdr)) < (fw->data + fw->size);) {
+ memcpy(&hdr, sect, sizeof(hdr));
+
+ for (i = 0, csum = 0; i < offsetof(struct mv3310_fw_hdr, csum); i++)
+ csum += sect[i];
+
+ if ((u16)~csum != le16_to_cpu(hdr.csum)) {
+ dev_err(&phydev->mdio.dev, "Corrupt section header\n");
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ si.data = sect + sizeof(hdr);
+ si.size = le32_to_cpu(hdr.data_size);
+ si.addr = le32_to_cpu(hdr.data_addr);
+ si.csum = le16_to_cpu(hdr.data_csum);
+
+ if ((si.data + si.size) > (fw->data + fw->size)) {
+ dev_err(&phydev->mdio.dev, "Invalid section length\n");
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ err = mv3310_load_fw_sect(phydev, &si);
+ if (err)
+ goto unlock;
+
+ if (!(le16_to_cpu(hdr.flags) & MV3310_FW_HDR_DATA_ONLY))
+ need_boot = true;
+
+ next = le32_to_cpu(hdr.next_hdr);
+ if (!next)
+ break;
+
+ sect = fw->data + next;
+ }
+
+ if (need_boot) {
+ __phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT, 0,
+ MV_PMA_BOOT_APP_LOADED);
+ mdelay(200);
+ if (!(__phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT) &
+ MV_PMA_BOOT_APP_STARTED)) {
+ dev_err(&phydev->mdio.dev, "Firmware boot failed\n");
+ err = -ENODEV;
+ }
+ }
+
+unlock:
+ phy_unlock_mdio_bus(phydev);
+
+release:
+ release_firmware(fw);
+ return err;
+}
+
static int mv3310_probe(struct phy_device *phydev)
{
const struct mv3310_chip *chip = to_mv3310_chip(phydev);
@@ -520,6 +672,12 @@ static int mv3310_probe(struct phy_device *phydev)
return -ENODEV;
}
+ if ((ret & MV_PMA_BOOT_PRGS_MASK) == MV_PMA_BOOT_PRGS_WAIT) {
+ ret = mv3310_load_fw(phydev);
+ if (ret)
+ return ret;
+ }
+
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1165,6 +1323,8 @@ static const struct mv3310_chip mv3310_type = {
.select_mactype = mv3310_select_mactype,
.init_interface = mv3310_init_interface,
+ .firmware_path = "mrvl/x3310fw.hdr",
+
#ifdef CONFIG_HWMON
.hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg,
#endif
@@ -1428,4 +1588,5 @@ static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
};
MODULE_DEVICE_TABLE(mdio, mv3310_tbl);
MODULE_DESCRIPTION("Marvell Alaska X/M multi-gigabit Ethernet PHY driver");
+MODULE_FIRMWARE("mrvl/x3310fw.hdr");
MODULE_LICENSE("GPL");
--
2.34.1
@@ -1,7 +1,7 @@
From b70f0aa3eb77567a057c2f42f5012a3e009a95c8 Mon Sep 17 00:00:00 2001
From 27d5241d3ddf70d65af5f4dd029f99f0fea866a5 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 21 Nov 2023 20:15:24 +0100
Subject: [PATCH 16/20] net: phy: marvell10g: Fix power-up when strapped to
Subject: [PATCH 14/19] net: phy: marvell10g: Fix power-up when strapped to
start powered down
Organization: Addiva Elektronik
@@ -15,33 +15,33 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 05ad7c769e24..1d86ee10650e 100644
index ec9ea5e947f9..5a1e89d3fbeb 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -782,11 +782,23 @@ static int mv3310_power_down(struct phy_device *phydev)
@@ -335,11 +335,23 @@ static int mv3310_power_down(struct phy_device *phydev)
static int mv3310_power_up(struct phy_device *phydev)
{
+ static const u16 resets[][2] = {
+ { MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_CTRL1 },
+ { MDIO_MMD_PCS, MV_PCS_1000BASEX + MDIO_CTRL1 },
+ { MDIO_MMD_PCS, MV_PCS_BASE_T + MDIO_CTRL1 },
+ { MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_CTRL1 },
+ { MDIO_MMD_PCS, MV_PCS_BASE_T + MDIO_CTRL1 },
+ { MDIO_MMD_PMAPMD, MDIO_CTRL1 },
+ { MDIO_MMD_VEND2, MV_V2_PORT_CTRL },
+ };
struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
- int ret;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(resets); i++) {
+ ret = phy_clear_bits_mmd(phydev, resets[i][0], resets[i][1],
+ MDIO_CTRL1_LPOWER);
+ if (ret)
+ break;
+ }
- ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
- MV_V2_PORT_CTRL_PWRDOWN);
+ for (i = 0; i < ARRAY_SIZE(resets); i++) {
+ ret = phy_clear_bits_mmd(phydev, resets[i][0], resets[i][1],
+ ret = ret ? : phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+ MV_V2_PORT_CTRL_PWRDOWN);
+ if (ret)
+ break;
+
+ }
/* Sometimes, the power down bit doesn't clear immediately, and
* a read of this register causes the bit not to clear. Delay
@@ -1,7 +1,7 @@
From 5adf394404d4c8ac25fb1e36d7d3f23b699b3104 Mon Sep 17 00:00:00 2001
From e389ee690ce56ef20863aeabdf389bed842d7f42 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 15 Nov 2023 20:58:42 +0100
Subject: [PATCH 13/20] net: phy: marvell10g: Add LED support for 88X3310
Subject: [PATCH 15/19] net: phy: marvell10g: Add LED support for 88X3310
Organization: Addiva Elektronik
Pickup the LEDs from the state in which the hardware reset or
@@ -15,16 +15,16 @@ Trigger support:
- "timer": Map 60-100 ms periods to the fast rate (81ms) and 1000-1600
ms periods to the slow rate (1300ms). Defer everything else to
software blinking
- "netdev": Offload (per-medium) link or duplex information to the
solid behavior; tx and/or rx activity to blink behavior.
- "netdev": Offload link or duplex information to the solid behavior;
tx and/or rx activity to blink behavior.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/marvell10g.c | 455 +++++++++++++++++++++++++++++++++++
1 file changed, 455 insertions(+)
drivers/net/phy/marvell10g.c | 422 +++++++++++++++++++++++++++++++++++
1 file changed, 422 insertions(+)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 155f439d9c1c..05ad7c769e24 100644
index 5a1e89d3fbeb..745aeb367ef8 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -28,6 +28,7 @@
@@ -35,13 +35,15 @@ index 155f439d9c1c..05ad7c769e24 100644
#include <linux/phy.h>
#include <linux/sfp.h>
#include <linux/netdevice.h>
@@ -136,6 +137,14 @@ enum {
@@ -133,6 +134,16 @@ enum {
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7,
+ MV_V2_LED0_CONTROL = 0xf020,
+ MV_V2_LED_CONTROL_POLARITY_MASK = 0x0003,
+ MV_V2_LED_CONTROL_POLARITY_SHIFT = 0,
+ MV_V2_LED_CONTROL_ACTIVE_HIGH = BIT(0),
+ MV_V2_LED_CONTROL_TRISTATE = BIT(1),
+ MV_V2_LED_CONTROL_BLINK_RATE = BIT(2),
+ MV_V2_LED_CONTROL_SOLID_FUNC_MASK = 0x00f8,
+ MV_V2_LED_CONTROL_SOLID_FUNC_SHIFT = 3,
@@ -50,7 +52,15 @@ index 155f439d9c1c..05ad7c769e24 100644
MV_V2_PORT_INTR_STS = 0xf040,
MV_V2_PORT_INTR_MASK = 0xf043,
MV_V2_PORT_INTR_STS_WOL_EN = BIT(8),
@@ -168,6 +177,16 @@ struct mv3310_chip {
@@ -155,6 +166,7 @@ enum {
struct mv3310_chip {
bool (*has_downshift)(struct phy_device *phydev);
void (*init_supported_interfaces)(unsigned long *mask);
+ int (*leds_probe)(struct phy_device *phydev);
int (*get_mactype)(struct phy_device *phydev);
int (*set_mactype)(struct phy_device *phydev, int mactype);
int (*select_mactype)(unsigned long *interfaces);
@@ -167,6 +179,13 @@ struct mv3310_chip {
#endif
};
@@ -58,16 +68,13 @@ index 155f439d9c1c..05ad7c769e24 100644
+
+struct mv3310_led {
+ u8 index;
+ u16 fw_ctrl;
+
+ unsigned copper:1;
+ unsigned fiber:1;
+ u16 ctrl;
+};
+
struct mv3310_priv {
DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
@@ -178,6 +197,8 @@ struct mv3310_priv {
@@ -177,6 +196,8 @@ struct mv3310_priv {
struct device *hwmon_dev;
char *hwmon_name;
@@ -76,7 +83,7 @@ index 155f439d9c1c..05ad7c769e24 100644
};
static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
@@ -185,6 +206,431 @@ static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
@@ -184,6 +205,396 @@ static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
return phydev->drv->driver_data;
}
@@ -150,7 +157,6 @@ index 155f439d9c1c..05ad7c769e24 100644
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ *flagsp = flags;
@@ -184,12 +190,7 @@ index 155f439d9c1c..05ad7c769e24 100644
+
+ if (solid) {
+ if (link) {
+ if (led->copper)
+ *solid = MV3310_LED_FUNC_LINK_COPPER;
+ else if (led->fiber)
+ *solid = MV3310_LED_FUNC_LINK_FIBER;
+ else
+ *solid = MV3310_LED_FUNC_LINK;
+ *solid = MV3310_LED_FUNC_LINK;
+ } else if (duplex) {
+ switch (duplex) {
+ case BIT(TRIGGER_NETDEV_HALF_DUPLEX):
@@ -254,7 +255,7 @@ index 155f439d9c1c..05ad7c769e24 100644
+ enum mv3310_led_func blink,
+ bool slow_blink)
+{
+ u16 ctrl = led->fw_ctrl;
+ u16 ctrl = led->ctrl;
+
+ ctrl &= ~MV_V2_LED_CONTROL_SOLID_FUNC_MASK;
+ ctrl &= ~MV_V2_LED_CONTROL_BLINK_FUNC_MASK;
@@ -270,124 +271,36 @@ index 155f439d9c1c..05ad7c769e24 100644
+ MV_V2_LED0_CONTROL + led->index, ctrl);
+}
+
+
+enum mv3310_led_polarity {
+ MV3310_LED_POLARITY_ACTIVE_LOW = 0x0,
+ MV3310_LED_POLARITY_ACTIVE_HIGH = 0x1,
+ MV3310_LED_POLARITY_ACTIVE_LOW_TRISTATE = 0x2,
+ MV3310_LED_POLARITY_ACTIVE_HIGH_TRISTATE = 0x3,
+};
+
+static const char *mv3310_led_polarity_name[] = {
+ [MV3310_LED_POLARITY_ACTIVE_LOW] = "active-low",
+ [MV3310_LED_POLARITY_ACTIVE_HIGH] = "active-high",
+ [MV3310_LED_POLARITY_ACTIVE_LOW_TRISTATE] = "active-low-tristate",
+ [MV3310_LED_POLARITY_ACTIVE_HIGH_TRISTATE] = "active-high-tristate",
+};
+
+static int mv3310_led_polarity_from_str(const char *str,
+ enum mv3310_led_polarity *polarity)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mv3310_led_polarity_name); i++) {
+ if (!mv3310_led_polarity_name[i])
+ continue;
+
+ if (!strcmp(mv3310_led_polarity_name[i], str)) {
+ *polarity = i;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int mv3310_led_probe_of(struct phy_device *phydev,
+ struct device_node *np)
+static int mv3310_led_polarity_set(struct phy_device *phydev,
+ int index, unsigned long modes)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ enum mv3310_led_polarity polarity;
+ struct mv3310_led *led;
+ const char *str;
+ u32 index;
+ u16 ctrl;
+ int err;
+
+ err = of_property_read_u32(np, "reg", &index);
+ if (index < 0 || index >= MV3310_N_LEDS)
+ return -ENODEV;
+
+ led = &priv->led[index];
+ ctrl = led->ctrl;
+
+ if (test_bit(PHY_LED_ACTIVE_LOW, &modes))
+ ctrl &= ~MV_V2_LED_CONTROL_ACTIVE_HIGH;
+ else
+ ctrl |= MV_V2_LED_CONTROL_ACTIVE_HIGH;
+
+ if (test_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes))
+ ctrl |= MV_V2_LED_CONTROL_TRISTATE;
+ else
+ ctrl &= ~MV_V2_LED_CONTROL_TRISTATE;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index, ctrl);
+ if (err)
+ return err;
+
+ if (index >= MV3310_N_LEDS)
+ return -EINVAL;
+
+ led = &priv->led[index];
+ ctrl = led->fw_ctrl;
+
+ err = of_property_read_string(np, "marvell,media", &str);
+ if (!err) {
+ if (!strcmp(str, "copper"))
+ led->copper = 1;
+ else if (!strcmp(str, "fiber"))
+ led->fiber = 1;
+ }
+
+ err = of_property_read_string(np, "marvell,polarity", &str);
+ err = err ? : mv3310_led_polarity_from_str(str, &polarity);
+ if (!err) {
+ ctrl &= ~MV_V2_LED_CONTROL_POLARITY_MASK;
+ ctrl |= polarity << MV_V2_LED_CONTROL_POLARITY_SHIFT;
+ }
+
+ if (ctrl != led->fw_ctrl) {
+ led->fw_ctrl = ctrl;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index, ctrl);
+ }
+
+ return 0;
+}
+
+static int mv3310_leds_probe(struct phy_device *phydev)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *pnp, *np;
+ int err, val, index;
+
+ /* Save the state config left by HW reset or bootloader, this
+ * may be further refined by configuration from DT, if
+ * available.
+ *
+ * The resulting state is used as the fallback when no trigger
+ * is active.
+ */
+ for (index = 0; index < MV3310_N_LEDS; index++) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index);
+ if (val < 0)
+ return val;
+
+ priv->led[index] = (struct mv3310_led) {
+ .index = index,
+ .fw_ctrl = val,
+ };
+ }
+
+ if (!node)
+ return 0;
+
+ pnp = of_get_child_by_name(node, "leds");
+ if (!pnp)
+ return 0;
+
+ for_each_available_child_of_node(pnp, np) {
+ err = mv3310_led_probe_of(phydev, np);
+ if (err)
+ return err;
+ }
+
+ led->ctrl = ctrl;
+ return 0;
+}
+
@@ -504,25 +417,93 @@ index 155f439d9c1c..05ad7c769e24 100644
+ return mv3310_led_flags_from_funcs(led, solid, blink, flags);
+}
+
+static int mv3310_led_probe_of(struct phy_device *phydev,
+ struct device_node *np)
+{
+ u32 index;
+ int err;
+
+ err = of_property_read_u32(np, "reg", &index);
+ if (err)
+ return err;
+
+ if (index >= MV3310_N_LEDS)
+ return -EINVAL;
+
+ /* mv3310_led_polarity_set() will not be called unless the
+ * device tree specifies a mode that of_phy_led() considers to
+ * be a non-default configuration. I.e., something other than
+ * (active-high, drive low on inactive). But the 3310's HW
+ * default is (active-low, drive low on inactive). Therefore,
+ * configure all LEDs defined in the DT with the kernel
+ * defaults, and then let of_phy_led() set the final value if
+ * the config deviates from that.
+ */
+ return mv3310_led_polarity_set(phydev, index, 0);
+}
+
+static int mv3310_leds_probe(struct phy_device *phydev)
+{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *pnp, *np;
+ int err, val, index;
+
+ for (index = 0; index < MV3310_N_LEDS; index++) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ MV_V2_LED0_CONTROL + index);
+ if (val < 0)
+ return val;
+
+ priv->led[index] = (struct mv3310_led) {
+ .index = index,
+ .ctrl = val,
+ };
+ }
+
+ if (!node)
+ return 0;
+
+ pnp = of_get_child_by_name(node, "leds");
+ if (!pnp)
+ return 0;
+
+ for_each_available_child_of_node(pnp, np) {
+ err = mv3310_led_probe_of(phydev, np);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_HWMON
static umode_t mv3310_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
@@ -697,6 +1143,10 @@ static int mv3310_probe(struct phy_device *phydev)
@@ -724,6 +1135,10 @@ static int mv3310_probe(struct phy_device *phydev)
if (ret)
return ret;
+ ret = mv3310_leds_probe(phydev);
+ ret = chip->leds_probe ? chip->leds_probe(phydev) : 0;
+ if (ret)
+ return ret;
+
chip->init_supported_interfaces(priv->supported_interfaces);
return phy_sfp_probe(phydev, &mv3310_sfp_ops);
@@ -1502,6 +1952,11 @@ static struct phy_driver mv3310_drivers[] = {
@@ -1330,6 +1745,7 @@ static void mv2111_init_supported_interfaces(unsigned long *mask)
static const struct mv3310_chip mv3310_type = {
.has_downshift = mv3310_has_downshift,
.init_supported_interfaces = mv3310_init_supported_interfaces,
+ .leds_probe = mv3310_leds_probe,
.get_mactype = mv3310_get_mactype,
.set_mactype = mv3310_set_mactype,
.select_mactype = mv3310_select_mactype,
@@ -1531,6 +1947,12 @@ static struct phy_driver mv3310_drivers[] = {
.set_loopback = genphy_c45_loopback,
.get_wol = mv3110_get_wol,
.set_wol = mv3110_set_wol,
+ .led_polarity_set = mv3310_led_polarity_set,
+ .led_brightness_set = mv3310_led_brightness_set,
+ .led_blink_set = mv3310_led_blink_set,
+ .led_hw_is_supported = mv3310_led_hw_is_supported,
@@ -0,0 +1,80 @@
From 3113b64290b5b7b20c294535c12ea4c732a02f51 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 12 Dec 2023 09:51:05 +0100
Subject: [PATCH 16/19] net: phy: marvell10g: Support LEDs tied to a single
media side
Organization: Addiva Elektronik
In a combo-port setup, i.e. where both the copper and fiber interface
are available to the user, the LEDs may be physically located either
by the RJ45 jack, or by an SFP cage.
For those scenarios, allow the device tree to indicate that an LED is
tied to a particular media side, and use that information to refine
the offloading of the "netdev" trigger, such that LEDs attached to the
RJ45 jack only lights up when a copper link is established, and vice
versa for the SFP cage.
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
drivers/net/phy/marvell10g.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 745aeb367ef8..58c2f9626ba3 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -184,6 +184,9 @@ struct mv3310_chip {
struct mv3310_led {
u8 index;
u16 ctrl;
+
+ unsigned copper:1;
+ unsigned fiber:1;
};
struct mv3310_priv {
@@ -308,7 +311,12 @@ static int mv3310_led_funcs_from_flags(struct mv3310_led *led,
if (solid) {
if (link) {
- *solid = MV3310_LED_FUNC_LINK;
+ if (led->copper)
+ *solid = MV3310_LED_FUNC_LINK_COPPER;
+ else if (led->fiber)
+ *solid = MV3310_LED_FUNC_LINK_FIBER;
+ else
+ *solid = MV3310_LED_FUNC_LINK;
} else if (duplex) {
switch (duplex) {
case BIT(TRIGGER_NETDEV_HALF_DUPLEX):
@@ -538,6 +546,9 @@ static int mv3310_led_hw_control_get(struct phy_device *phydev, u8 index,
static int mv3310_led_probe_of(struct phy_device *phydev,
struct device_node *np)
{
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ struct mv3310_led *led;
+ const char *media;
u32 index;
int err;
@@ -548,6 +559,16 @@ static int mv3310_led_probe_of(struct phy_device *phydev,
if (index >= MV3310_N_LEDS)
return -EINVAL;
+ led = &priv->led[index];
+
+ err = of_property_read_string(np, "marvell,media", &media);
+ if (!err) {
+ if (!strcmp(media, "copper"))
+ led->copper = 1;
+ else if (!strcmp(media, "fiber"))
+ led->fiber = 1;
+ }
+
/* mv3310_led_polarity_set() will not be called unless the
* device tree specifies a mode that of_phy_led() considers to
* be a non-default configuration. I.e., something other than
--
2.34.1
@@ -1,7 +1,7 @@
From dd693e037f0dd799e77af397b4d23190b66e9cf1 Mon Sep 17 00:00:00 2001
From 2570c2350d3d614a31e14dd87d0e99e8fcb5096b Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Fri, 24 Nov 2023 23:29:55 +0100
Subject: [PATCH 17/20] nvmem: layouts: onie-tlv: Let device probe even when
Subject: [PATCH 17/19] nvmem: layouts: onie-tlv: Let device probe even when
TLV is invalid
Organization: Addiva Elektronik
@@ -1,7 +1,7 @@
From 7072b44955fc0bdc4b3e96648f2ff9c3e9d68c8e Mon Sep 17 00:00:00 2001
From 681ce95c15bff94ac83eb26db3c718594f8dfa16 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Mon, 4 Mar 2024 16:47:28 +0100
Subject: [PATCH 18/20] net: bridge: avoid classifying unknown multicast as
Subject: [PATCH 18/19] net: bridge: avoid classifying unknown multicast as
mrouters_only
Organization: Addiva Elektronik
@@ -40,10 +40,10 @@ index f95326fce6bb..2b1320025ec2 100644
};
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 4f5098d33a46..a512c8ad9860 100644
index a6e94ceb7c9a..44c12cb210b5 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -269,6 +269,9 @@ int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
@@ -277,6 +277,9 @@ int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
case BR_BOOLOPT_MST_ENABLE:
err = br_mst_set_enabled(br, on, extack);
break;
@@ -53,7 +53,7 @@ index 4f5098d33a46..a512c8ad9860 100644
default:
/* shouldn't be called with unsupported options */
WARN_ON(1);
@@ -287,6 +290,8 @@ int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
@@ -295,6 +298,8 @@ int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
return br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED);
case BR_BOOLOPT_MST_ENABLE:
return br_opt_get(br, BROPT_MST_ENABLED);
@@ -103,10 +103,10 @@ index 9a5ea06236bd..5f537dbd597a 100644
br_stp_timer_init(br);
br_multicast_init(br);
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index bb1ab53e54e0..c5ac65628a7a 100644
index 7431f89e897b..5f574d60e7ee 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -197,14 +197,19 @@ static struct net_bridge_port *maybe_deliver(
@@ -198,14 +198,19 @@ static struct net_bridge_port *maybe_deliver(
/* called under rcu_read_lock */
void br_flood(struct net_bridge *br, struct sk_buff *skb,
@@ -128,7 +128,7 @@ index bb1ab53e54e0..c5ac65628a7a 100644
list_for_each_entry_rcu(p, &br->port_list, list) {
/* Do not flood unicast traffic to ports that turn it off, nor
* other traffic if flood off, except for traffic we originate
@@ -215,6 +220,11 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
@@ -216,6 +221,11 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
continue;
break;
case BR_PKT_MULTICAST:
@@ -154,10 +154,10 @@ index c729528b5e85..2817d0c785be 100644
br_multicast_flood(mdst, skb, brmctx, local_rcv, false);
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 96d1fc78dd39..ab3ee0651ebe 100644
index 38373b4fb7dd..994dacaaab7e 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -3771,6 +3771,11 @@ static void br_multicast_err_count(const struct net_bridge *br,
@@ -3775,6 +3775,11 @@ static void br_multicast_err_count(const struct net_bridge *br,
u64_stats_update_end(&pstats->syncp);
}
@@ -169,7 +169,7 @@ index 96d1fc78dd39..ab3ee0651ebe 100644
static void br_multicast_pim(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
const struct sk_buff *skb)
@@ -3817,7 +3822,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge_mcast *brmctx,
@@ -3821,7 +3826,8 @@ static int br_multicast_ipv4_rcv(struct net_bridge_mcast *brmctx,
if (err == -ENOMSG) {
if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) {
@@ -179,7 +179,7 @@ index 96d1fc78dd39..ab3ee0651ebe 100644
} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
if (ip_hdr(skb)->protocol == IPPROTO_PIM)
br_multicast_pim(brmctx, pmctx, skb);
@@ -3886,7 +3892,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge_mcast *brmctx,
@@ -3890,7 +3896,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge_mcast *brmctx,
if (err == -ENOMSG || err == -ENODATA) {
if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
@@ -190,10 +190,10 @@ index 96d1fc78dd39..ab3ee0651ebe 100644
ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr))
br_ip6_multicast_mrd_rcv(brmctx, pmctx, skb);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index a63b32c1638e..4798588f15c7 100644
index 82e63908dce8..a85771f9fdbf 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -479,6 +479,7 @@ enum net_bridge_opts {
@@ -480,6 +480,7 @@ enum net_bridge_opts {
BROPT_VLAN_BRIDGE_BINDING,
BROPT_MCAST_VLAN_SNOOPING_ENABLED,
BROPT_MST_ENABLED,
@@ -201,7 +201,7 @@ index a63b32c1638e..4798588f15c7 100644
};
struct net_bridge {
@@ -877,8 +878,8 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb,
@@ -880,8 +881,8 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb,
bool local_rcv, bool local_orig);
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
void br_flood(struct net_bridge *br, struct sk_buff *skb,
@@ -212,7 +212,7 @@ index a63b32c1638e..4798588f15c7 100644
/* return true if both source port and dest port are isolated */
static inline bool br_skb_isolated(const struct net_bridge_port *to,
@@ -1394,6 +1395,19 @@ static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
@@ -1396,6 +1397,19 @@ static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
{
}
@@ -1,7 +1,7 @@
From 3c48022ab2eda9ab62b680a97c88934a62137ebf Mon Sep 17 00:00:00 2001
From 2482848726a5b8185a04d90891693a1713f894b5 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Tue, 5 Mar 2024 06:44:41 +0100
Subject: [PATCH 19/20] net: bridge: Ignore router ports when forwarding L2
Subject: [PATCH 19/19] net: bridge: Ignore router ports when forwarding L2
multicast
Organization: Addiva Elektronik
@@ -17,10 +17,10 @@ Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 4798588f15c7..cac15339ecae 100644
index a85771f9fdbf..eb68fd5e0b86 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -1073,7 +1073,10 @@ br_multicast_get_first_rport_node(struct net_bridge_mcast *brmctx,
@@ -1075,7 +1075,10 @@ br_multicast_get_first_rport_node(struct net_bridge_mcast *brmctx,
if (skb->protocol == htons(ETH_P_IPV6))
return rcu_dereference(hlist_first_rcu(&brmctx->ip6_mc_router_list));
#endif