* [PATCH net-next 1/3] leds: trigger: netdev: Extend speeds up to 100G
2026-05-20 20:03 [PATCH net-next 0/3] dd LED support for fbnic mike.marciniszyn
@ 2026-05-20 20:03 ` mike.marciniszyn
2026-05-20 20:16 ` Andrew Lunn
2026-05-20 20:03 ` [PATCH net-next 2/3] net: eth: fbnic: Store max_speed from firmware dialog mike.marciniszyn
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: mike.marciniszyn @ 2026-05-20 20:03 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Alexander Duyck, Jakub Kicinski,
kernel-team, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Russell King, Daniel Golle, Kees Cook, Simon Horman,
Dimitri Daskalakis, Jacob Keller, Lee Trager, Mohsin Bashir,
Alok Tiwari, Chengfeng Ye, Andy Shevchenko, Andrew Lunn
Cc: mike.marciniszyn, linux-kernel, linux-leds, netdev
From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
Add 25G, 40G, 50G, and 100G as available speeds to the netdev LED trigger.
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
---
drivers/leds/trigger/ledtrig-netdev.c | 46 ++++++++++++++++++++++++++-
include/linux/leds.h | 4 +++
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 12cb3311ea22..3c758a4cbaec 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -128,6 +128,22 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
trigger_data->link_speed == SPEED_10000)
blink_on = true;
+ if (test_bit(TRIGGER_NETDEV_LINK_25000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_25000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_40000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_40000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_50000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_50000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_100000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_100000)
+ blink_on = true;
+
if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) &&
trigger_data->duplex == DUPLEX_HALF)
blink_on = true;
@@ -337,6 +353,10 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
case TRIGGER_NETDEV_LINK_2500:
case TRIGGER_NETDEV_LINK_5000:
case TRIGGER_NETDEV_LINK_10000:
+ case TRIGGER_NETDEV_LINK_25000:
+ case TRIGGER_NETDEV_LINK_40000:
+ case TRIGGER_NETDEV_LINK_50000:
+ case TRIGGER_NETDEV_LINK_100000:
case TRIGGER_NETDEV_HALF_DUPLEX:
case TRIGGER_NETDEV_FULL_DUPLEX:
case TRIGGER_NETDEV_TX:
@@ -373,6 +393,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
case TRIGGER_NETDEV_LINK_2500:
case TRIGGER_NETDEV_LINK_5000:
case TRIGGER_NETDEV_LINK_10000:
+ case TRIGGER_NETDEV_LINK_25000:
+ case TRIGGER_NETDEV_LINK_40000:
+ case TRIGGER_NETDEV_LINK_50000:
+ case TRIGGER_NETDEV_LINK_100000:
case TRIGGER_NETDEV_HALF_DUPLEX:
case TRIGGER_NETDEV_FULL_DUPLEX:
case TRIGGER_NETDEV_TX:
@@ -396,7 +420,11 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
test_bit(TRIGGER_NETDEV_LINK_1000, &mode) ||
test_bit(TRIGGER_NETDEV_LINK_2500, &mode) ||
test_bit(TRIGGER_NETDEV_LINK_5000, &mode) ||
- test_bit(TRIGGER_NETDEV_LINK_10000, &mode)))
+ test_bit(TRIGGER_NETDEV_LINK_10000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_25000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_40000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_50000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_100000, &mode)))
return -EINVAL;
cancel_delayed_work_sync(&trigger_data->work);
@@ -433,6 +461,10 @@ DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500);
DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000);
DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000);
+DEFINE_NETDEV_TRIGGER(link_25000, TRIGGER_NETDEV_LINK_25000);
+DEFINE_NETDEV_TRIGGER(link_40000, TRIGGER_NETDEV_LINK_40000);
+DEFINE_NETDEV_TRIGGER(link_50000, TRIGGER_NETDEV_LINK_50000);
+DEFINE_NETDEV_TRIGGER(link_100000, TRIGGER_NETDEV_LINK_100000);
DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
@@ -521,6 +553,10 @@ static umode_t netdev_trig_link_speed_visible(struct kobject *kobj,
CHECK_LINK_MODE_ATTR(2500);
CHECK_LINK_MODE_ATTR(5000);
CHECK_LINK_MODE_ATTR(10000);
+ CHECK_LINK_MODE_ATTR(25000);
+ CHECK_LINK_MODE_ATTR(40000);
+ CHECK_LINK_MODE_ATTR(50000);
+ CHECK_LINK_MODE_ATTR(100000);
}
return 0;
@@ -533,6 +569,10 @@ static struct attribute *netdev_trig_link_speed_attrs[] = {
&dev_attr_link_2500.attr,
&dev_attr_link_5000.attr,
&dev_attr_link_10000.attr,
+ &dev_attr_link_25000.attr,
+ &dev_attr_link_40000.attr,
+ &dev_attr_link_50000.attr,
+ &dev_attr_link_100000.attr,
NULL
};
@@ -668,6 +708,10 @@ static void netdev_trig_work(struct work_struct *work)
test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_25000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_40000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_50000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_100000, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode);
interval = jiffies_to_msecs(
diff --git a/include/linux/leds.h b/include/linux/leds.h
index b16b803cc1ac..bf31c246d9e2 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -607,6 +607,10 @@ enum led_trigger_netdev_modes {
TRIGGER_NETDEV_LINK_2500,
TRIGGER_NETDEV_LINK_5000,
TRIGGER_NETDEV_LINK_10000,
+ TRIGGER_NETDEV_LINK_25000,
+ TRIGGER_NETDEV_LINK_40000,
+ TRIGGER_NETDEV_LINK_50000,
+ TRIGGER_NETDEV_LINK_100000,
TRIGGER_NETDEV_HALF_DUPLEX,
TRIGGER_NETDEV_FULL_DUPLEX,
TRIGGER_NETDEV_TX,
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next 2/3] net: eth: fbnic: Store max_speed from firmware dialog
2026-05-20 20:03 [PATCH net-next 0/3] dd LED support for fbnic mike.marciniszyn
2026-05-20 20:03 ` [PATCH net-next 1/3] leds: trigger: netdev: Extend speeds up to 100G mike.marciniszyn
@ 2026-05-20 20:03 ` mike.marciniszyn
2026-05-20 20:03 ` [PATCH net-next 3/3] net: eth: fbnic: Add led support mike.marciniszyn
2026-05-20 20:14 ` [PATCH net-next 0/3] dd LED support for fbnic Andrew Lunn
3 siblings, 0 replies; 14+ messages in thread
From: mike.marciniszyn @ 2026-05-20 20:03 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Alexander Duyck, Jakub Kicinski,
kernel-team, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Russell King, Daniel Golle, Kees Cook, Simon Horman,
Dimitri Daskalakis, Jacob Keller, Lee Trager, Mohsin Bashir,
Alok Tiwari, Chengfeng Ye, Andy Shevchenko, Andrew Lunn
Cc: mike.marciniszyn, linux-kernel, linux-leds, netdev
From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
The OCP spec required LED signalling to signal the difference
between both below and at max speed capability.
The firmware init dialog already contains that attribute
so store it to support follow-on patches.
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 3 +++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
index 0c6812fcf185..59015769ca28 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
@@ -561,6 +561,7 @@ static const struct fbnic_tlv_index fbnic_fw_cap_resp_index[] = {
FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_ACTIVE_FW_SLOT),
FBNIC_TLV_ATTR_STRING(FBNIC_FW_CAP_RESP_VERSION_COMMIT_STR,
FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_FW_MAX_LINK_SPEED),
FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_BMC_ALL_MULTI),
FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_FW_LINK_SPEED),
FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_FW_LINK_FEC),
@@ -667,6 +668,8 @@ static int fbnic_fw_parse_cap_resp(void *opaque, struct fbnic_tlv_msg **results)
fbd->fw_cap.active_slot =
fta_get_uint(results, FBNIC_FW_CAP_RESP_ACTIVE_FW_SLOT);
+ fbd->fw_cap.max_link_speed =
+ fta_get_uint(results, FBNIC_FW_CAP_RESP_FW_MAX_LINK_SPEED);
fbd->fw_cap.link_speed =
fta_get_uint(results, FBNIC_FW_CAP_RESP_FW_LINK_SPEED);
fbd->fw_cap.link_fec =
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
index d84723e4cfa3..55c2ebc223d0 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -58,6 +58,7 @@ struct fbnic_fw_cap {
u8 need_bmc_macda_sync : 1;
u8 all_multi : 1;
u8 link_speed;
+ u8 max_link_speed;
u8 link_fec;
u32 anti_rollback_version;
};
@@ -241,6 +242,8 @@ enum {
FBNIC_FW_CAP_RESP_STORED_CMRT_COMMIT_STR = 0x10,
FBNIC_FW_CAP_RESP_UEFI_VERSION = 0x11,
FBNIC_FW_CAP_RESP_UEFI_COMMIT_STR = 0x12,
+ FBNIC_FW_CAP_RESP_FW_MAX_LINK_SPEED = 0x13,
+ /* 0x14 reserved */
FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION = 0x15,
FBNIC_FW_CAP_RESP_MSG_MAX
};
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH net-next 3/3] net: eth: fbnic: Add led support
2026-05-20 20:03 [PATCH net-next 0/3] dd LED support for fbnic mike.marciniszyn
2026-05-20 20:03 ` [PATCH net-next 1/3] leds: trigger: netdev: Extend speeds up to 100G mike.marciniszyn
2026-05-20 20:03 ` [PATCH net-next 2/3] net: eth: fbnic: Store max_speed from firmware dialog mike.marciniszyn
@ 2026-05-20 20:03 ` mike.marciniszyn
2026-05-20 20:37 ` Andrew Lunn
2026-05-20 20:14 ` [PATCH net-next 0/3] dd LED support for fbnic Andrew Lunn
3 siblings, 1 reply; 14+ messages in thread
From: mike.marciniszyn @ 2026-05-20 20:03 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Alexander Duyck, Jakub Kicinski,
kernel-team, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Russell King, Daniel Golle, Kees Cook, Simon Horman,
Dimitri Daskalakis, Jacob Keller, Lee Trager, Mohsin Bashir,
Alok Tiwari, Chengfeng Ye, Andy Shevchenko, Andrew Lunn
Cc: mike.marciniszyn, linux-kernel, linux-leds, netdev
From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
This patch adds the LED support for fbnic and adds the
user /sys/class/leds interfaces based on CONFIG_FBNIC_LEDS.
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
---
drivers/net/ethernet/meta/Kconfig | 8 +
drivers/net/ethernet/meta/fbnic/Makefile | 2 +
drivers/net/ethernet/meta/fbnic/fbnic.h | 13 +
drivers/net/ethernet/meta/fbnic/fbnic_csr.h | 15 ++
.../net/ethernet/meta/fbnic/fbnic_devlink.c | 4 +
.../net/ethernet/meta/fbnic/fbnic_ethtool.c | 59 +++++
drivers/net/ethernet/meta/fbnic/fbnic_led.c | 228 +++++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 239 ++++++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 62 +++++
drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 8 +
.../net/ethernet/meta/fbnic/fbnic_phylink.c | 2 +
11 files changed, 640 insertions(+)
create mode 100644 drivers/net/ethernet/meta/fbnic/fbnic_led.c
diff --git a/drivers/net/ethernet/meta/Kconfig b/drivers/net/ethernet/meta/Kconfig
index ca5c7ac2a5bc..a8ca2aaf798a 100644
--- a/drivers/net/ethernet/meta/Kconfig
+++ b/drivers/net/ethernet/meta/Kconfig
@@ -35,4 +35,12 @@ config FBNIC
To compile this driver as a module, choose M here. The module
will be called fbnic. MSI-X interrupt support is required.
+config FBNIC_LEDS
+ def_bool LEDS_TRIGGER_NETDEV
+ depends on FBNIC && LEDS_CLASS
+ depends on LEDS_CLASS=y || FBNIC=m
+ help
+ Optional support for controlling the NIC LEDs with the netdev
+ LED trigger.
+
endif # NET_VENDOR_META
diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile
index 72c41af65364..7f3b70a1f444 100644
--- a/drivers/net/ethernet/meta/fbnic/Makefile
+++ b/drivers/net/ethernet/meta/fbnic/Makefile
@@ -26,3 +26,5 @@ fbnic-y := fbnic_csr.o \
fbnic_tlv.o \
fbnic_txrx.o \
# End of objects
+
+fbnic-$(CONFIG_FBNIC_LEDS) += fbnic_led.o
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index d0715695c43e..cf98beca53d3 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -97,6 +97,11 @@ struct fbnic_dev {
struct fbnic_fw_log fw_log;
+ /* Used to synchronize updates to LED state and CSR */
+ struct mutex led_mutex;
+ bool led_link_up;
+ struct fbnic_led_cdev leds[FBNIC_NUM_LEDS];
+
/* MDIO bus for PHYs */
struct mii_bus *mdio_bus;
@@ -243,6 +248,14 @@ void fbnic_dbg_exit(void);
void fbnic_rpc_reset_valid_entries(struct fbnic_dev *fbd);
+#if IS_ENABLED(CONFIG_FBNIC_LEDS)
+int fbnic_led_init(struct fbnic_dev *fbd);
+void fbnic_led_exit(struct fbnic_dev *fbd);
+#else
+static inline int fbnic_led_init(struct fbnic_dev *fbd) { return 0; }
+static inline void fbnic_led_exit(struct fbnic_dev *fbd) {}
+#endif
+
int fbnic_mdiobus_create(struct fbnic_dev *fbd);
void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
index 64b958df7774..6f4ae091652b 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
@@ -857,6 +857,21 @@ enum {
#define FBNIC_SIG_PCS_INTR_LINK_DOWN CSR_BIT(1)
#define FBNIC_SIG_PCS_INTR_LINK_UP CSR_BIT(0)
#define FBNIC_SIG_PCS_INTR_MASK 0x11816 /* 0x46058 */
+#define FBNIC_SIG_LED 0x11820 /* 0x46080 */
+#define FBNIC_SIG_LED_OVERRIDE_EN CSR_GENMASK(2, 0)
+#define FBNIC_SIG_LED_OVERRIDE_VAL CSR_GENMASK(6, 4)
+
+enum {
+ FBNIC_SIG_LED_OVERRIDE_ACTIVITY = 0x1,
+ FBNIC_SIG_LED_OVERRIDE_AMBER = 0x2,
+ FBNIC_SIG_LED_OVERRIDE_BLUE = 0x4,
+};
+
+#define FBNIC_SIG_LED_BLINK_RATE_MASK CSR_GENMASK(11, 8)
+enum {
+ FBNIC_SIG_LED_BLINK_RATE_5HZ = 0xf,
+};
+
#define FBNIC_CSR_END_SIG 0x1184e /* CSR section delimiter */
#define FBNIC_CSR_START_MAC_STAT 0x11a00
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c b/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c
index 546e1c12d287..8aabec5143cd 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c
@@ -622,6 +622,8 @@ void fbnic_devlink_free(struct fbnic_dev *fbd)
{
struct devlink *devlink = priv_to_devlink(fbd);
+ mutex_destroy(&fbd->led_mutex);
+
devlink_free(devlink);
}
@@ -651,6 +653,8 @@ struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
+ mutex_init(&fbd->led_mutex);
+
return fbd;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index f14de2366854..3904081e24f9 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -2005,6 +2005,64 @@ fbnic_get_rmon_stats(struct net_device *netdev,
*ranges = fbnic_rmon_ranges;
}
+/**
+ * fbnic_set_phys_id - Used to strobe the MAC LEDs in a recognizable pattern
+ * @netdev: Interface/port to strobe the LEDs for
+ * @phys_id_state: State requested by the call
+ *
+ * This function can really be broken down into two parts. There are the
+ * ACTIVE/INACTIVE states which really are meant to be defining the start
+ * and stop of the LED strobing. There is also the ON/OFF states which are
+ * used to provide us with a way of telling us that we should be turning
+ * the LED on and/or off.
+ *
+ * We translate these calls and pass them off to the MAC layer. They will
+ * be used to initialize a strobe, then on and off will be used to cycle
+ * between the patterns, and finally we will restore the original LED state.
+ *
+ * We will return 2 when we are requested to go active. This will tell the
+ * call that it will need to call back to turn on/off the LED twice every
+ * second.
+ *
+ * Return: blink in half second intervals on success, negative value on failure
+ */
+static int fbnic_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state phys_id_state)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct fbnic_dev *fbd = fbn->fbd;
+ const struct fbnic_mac *mac;
+ int cycle_interval = 0;
+ int state;
+
+ mac = fbd->mac;
+
+ if (!mac || !mac->set_led_state)
+ return -EOPNOTSUPP;
+
+ switch (phys_id_state) {
+ case ETHTOOL_ID_ACTIVE:
+ state = FBNIC_LED_STROBE_INIT;
+ cycle_interval = 2;
+ break;
+ case ETHTOOL_ID_INACTIVE:
+ state = FBNIC_LED_RESTORE;
+ break;
+ case ETHTOOL_ID_ON:
+ state = FBNIC_LED_ON;
+ break;
+ case ETHTOOL_ID_OFF:
+ state = FBNIC_LED_OFF;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mac->set_led_state(fbd, state);
+
+ return cycle_interval;
+}
+
static void fbnic_get_link_ext_stats(struct net_device *netdev,
struct ethtool_link_ext_stats *stats)
{
@@ -2062,6 +2120,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
.get_eth_mac_stats = fbnic_get_eth_mac_stats,
.get_eth_ctrl_stats = fbnic_get_eth_ctrl_stats,
.get_rmon_stats = fbnic_get_rmon_stats,
+ .set_phys_id = fbnic_set_phys_id,
};
void fbnic_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_led.c b/drivers/net/ethernet/meta/fbnic/fbnic_led.c
new file mode 100644
index 000000000000..44d0dc1be448
--- /dev/null
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_led.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <uapi/linux/uleds.h>
+
+#include "fbnic.h"
+#include "fbnic_csr.h"
+#include "fbnic_mac.h"
+#include "fbnic_netdev.h"
+
+#define led_classdev_to_fbnic_led(cdev) \
+ container_of(cdev, struct fbnic_led_cdev, led)
+
+static const char *fbnic_led_names[FBNIC_NUM_LEDS] = {
+ "activity",
+ "link-amber",
+ "link-blue"
+};
+
+static void fbnic_led_get_name(struct fbnic_dev *fbd,
+ int led_idx, char *name)
+{
+ snprintf(name, LED_MAX_NAME_SIZE, "%s-%s",
+ fbd->netdev->name, fbnic_led_names[led_idx]);
+}
+
+static int fbnic_led_get_idx(struct fbnic_dev *fbd,
+ struct fbnic_led_cdev *ldev)
+{
+ return ldev - &fbd->leds[0];
+}
+
+static struct fbnic_dev *led_cdev_to_fbd(struct led_classdev *led_cdev)
+{
+ struct fbnic_led_cdev *ldev = led_classdev_to_fbnic_led(led_cdev);
+
+ return ldev->fbd;
+}
+
+static u32 fbnic_led_get_supported_modes(struct fbnic_dev *fbd, int led_idx)
+{
+ u32 modes = 0;
+
+ if (led_idx == FBNIC_LED_ACTIVITY) {
+ modes = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
+
+ return modes;
+ }
+
+ /* Set modes for link LEDs - note 40G not supported */
+ modes = BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_25000) |
+ BIT(TRIGGER_NETDEV_LINK_50000) |
+ BIT(TRIGGER_NETDEV_LINK_100000);
+
+ return modes;
+}
+
+static int fbnic_led_hw_ctl_set(struct led_classdev *led_cdev,
+ unsigned long flags)
+{
+ struct fbnic_led_cdev *ldev = led_classdev_to_fbnic_led(led_cdev);
+ struct fbnic_dev *fbd = led_cdev_to_fbd(led_cdev);
+ int led_idx = fbnic_led_get_idx(fbd, ldev);
+ u32 supported_modes;
+
+ supported_modes = fbnic_led_get_supported_modes(fbd, led_idx);
+
+ if (flags & ~supported_modes)
+ return -EINVAL;
+
+ /* Turn on activity LED only when both the TX and RX flags are set. */
+ if (led_idx == FBNIC_LED_ACTIVITY && (flags & supported_modes) &&
+ flags != supported_modes) {
+ dev_warn(fbd->dev,
+ "Invalid activity LED mode(s): 0x%lx\n", flags);
+ return -EINVAL;
+ }
+
+ /* Preserve the configured modes for restoration after LED strobe */
+ mutex_lock(&fbd->led_mutex);
+ ldev->enabled_modes = flags;
+
+ if (ldev->strobe_mode)
+ dev_warn(fbd->dev,
+ "LED config takes effect after strobe completes.\n");
+
+ fbnic_led_update_csr(fbd);
+ mutex_unlock(&fbd->led_mutex);
+
+ return 0;
+}
+
+static int fbnic_led_hw_ctl_get(struct led_classdev *led_cdev,
+ unsigned long *flags)
+{
+ struct fbnic_led_cdev *ldev = led_classdev_to_fbnic_led(led_cdev);
+ struct fbnic_dev *fbd = led_cdev_to_fbd(led_cdev);
+
+ mutex_lock(&fbd->led_mutex);
+
+ *flags = ldev->enabled_modes;
+
+ mutex_unlock(&fbd->led_mutex);
+
+ return 0;
+}
+
+static struct device *fbnic_led_hw_ctl_get_device(struct led_classdev *led_cdev)
+{
+ struct fbnic_dev *fbd = led_cdev_to_fbd(led_cdev);
+ struct net_device *netdev = fbd->netdev;
+
+ return &netdev->dev;
+}
+
+static int fbnic_led_hw_ctl_is_supported(struct led_classdev *led_cdev,
+ unsigned long flags)
+{
+ struct fbnic_led_cdev *ldev = led_classdev_to_fbnic_led(led_cdev);
+ struct fbnic_dev *fbd = led_cdev_to_fbd(led_cdev);
+ int led_idx = fbnic_led_get_idx(fbd, ldev);
+ u32 modes;
+
+ modes = fbnic_led_get_supported_modes(fbd, led_idx);
+
+ if (led_idx == FBNIC_LED_ACTIVITY && (flags & modes) && flags != modes)
+ return -EOPNOTSUPP;
+ if (flags & ~modes)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int fbnic_led_brightness_set_blocking(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct fbnic_led_cdev *ldev = led_classdev_to_fbnic_led(led_cdev);
+ struct fbnic_dev *fbd = led_cdev_to_fbd(led_cdev);
+ int led_idx = fbnic_led_get_idx(fbd, ldev);
+
+ mutex_lock(&fbd->led_mutex);
+ if (!brightness) {
+ fbd->leds[led_idx].enabled_modes = 0;
+ fbd->leds[led_idx].strobe_mode = 0;
+ } else {
+ u32 mode;
+
+ switch (led_idx) {
+ case FBNIC_LED_ACTIVITY:
+ fbd->leds[led_idx].enabled_modes =
+ BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
+ break;
+ default:
+ mode = fbnic_led_get_link_speed_mode(fbd);
+ fbd->leds[led_idx].enabled_modes = mode;
+ break;
+ }
+ }
+
+ fbnic_led_update_csr(fbd);
+
+ mutex_unlock(&fbd->led_mutex);
+
+ return 0;
+}
+
+static int fbnic_led_setup(struct fbnic_dev *fbd, int led_idx)
+{
+ struct pci_dev *pdev = to_pci_dev(fbd->dev);
+ struct led_classdev *led_cdev;
+
+ fbd->leds[led_idx].fbd = fbd;
+ led_cdev = &fbd->leds[led_idx].led;
+ led_cdev->name = fbd->leds[led_idx].name;
+ fbnic_led_get_name(fbd, led_idx, fbd->leds[led_idx].name);
+ led_cdev->max_brightness = 1;
+ led_cdev->hw_control_trigger = "netdev";
+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
+ led_cdev->hw_control_set = fbnic_led_hw_ctl_set;
+ led_cdev->hw_control_get = fbnic_led_hw_ctl_get;
+ led_cdev->hw_control_get_device = fbnic_led_hw_ctl_get_device;
+ led_cdev->hw_control_is_supported = fbnic_led_hw_ctl_is_supported;
+ led_cdev->brightness_set_blocking = fbnic_led_brightness_set_blocking;
+
+ return led_classdev_register(&pdev->dev, led_cdev);
+}
+
+/**
+ * fbnic_led_init - initialize the linux led interface for fbnic
+ *
+ * @fbd: FBNIC device structure
+ *
+ * Return: zero on success, negative value on failure
+ *
+ * This function creates three led devices for the fbnic device. One for the
+ * activity LED and two for the color LEDs. The successful initialization
+ * creates <netdev>-activity, <netdev>-link-amber and <netdev>-link-blue
+ * under /sys/class/leds/
+ */
+int fbnic_led_init(struct fbnic_dev *fbd)
+{
+ int i, ret;
+
+ for (i = 0; i < FBNIC_NUM_LEDS; i++) {
+ ret = fbnic_led_setup(fbd, i);
+
+ if (ret)
+ goto err_led_setup;
+ }
+
+ return 0;
+
+err_led_setup:
+ while (i--)
+ led_classdev_unregister(&fbd->leds[i].led);
+
+ return ret;
+}
+
+void fbnic_led_exit(struct fbnic_dev *fbd)
+{
+ int i;
+
+ for (i = 0; i < FBNIC_NUM_LEDS; i++)
+ led_classdev_unregister(&fbd->leds[i].led);
+}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
index 53b7a938b4c2..c6b1130f9159 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
@@ -623,6 +623,53 @@ static bool fbnic_pmd_update_state(struct fbnic_dev *fbd, bool signal_detect)
return false;
}
+u32 fbnic_get_link_speed(u8 link_speed)
+{
+ switch (link_speed) {
+ case FBNIC_FW_LINK_MODE_25CR:
+ return SPEED_25000;
+ case FBNIC_FW_LINK_MODE_50CR2:
+ case FBNIC_FW_LINK_MODE_50CR:
+ return SPEED_50000;
+ case FBNIC_FW_LINK_MODE_100CR2:
+ return SPEED_100000;
+ default:
+ return 0;
+ }
+}
+
+static void fbnic_set_led_state(struct fbnic_dev *fbd, int state)
+{
+ mutex_lock(&fbd->led_mutex);
+
+ /* alternating amber,blue IDs device every half second */
+ switch (state) {
+ case FBNIC_LED_OFF: /* amber on, blue off */
+ fbd->leds[FBNIC_LED_LINK_AMBER].strobe_mode = FBNIC_STROBE_ON;
+ fbd->leds[FBNIC_LED_LINK_BLUE].strobe_mode = FBNIC_STROBE_OFF;
+ break;
+ case FBNIC_LED_ON: /* amber off, blue on */
+ fbd->leds[FBNIC_LED_LINK_AMBER].strobe_mode = FBNIC_STROBE_OFF;
+ fbd->leds[FBNIC_LED_LINK_BLUE].strobe_mode = FBNIC_STROBE_ON;
+ break;
+ case FBNIC_LED_RESTORE:
+ fbd->leds[FBNIC_LED_LINK_AMBER].strobe_mode =
+ FBNIC_STROBE_DISABLED;
+ fbd->leds[FBNIC_LED_LINK_BLUE].strobe_mode =
+ FBNIC_STROBE_DISABLED;
+ break;
+ case FBNIC_LED_STROBE_INIT: /* a no-op */
+ /* Initialization is a no-op; LED toggling happens on ON/OFF */
+ goto out_unlock;
+ default:
+ goto out_unlock;
+ }
+
+ fbnic_led_update_csr(fbd);
+out_unlock:
+ mutex_unlock(&fbd->led_mutex);
+}
+
static bool fbnic_mac_get_link(struct fbnic_dev *fbd, u8 aui, u8 fec)
{
bool link;
@@ -967,6 +1014,7 @@ static const struct fbnic_mac fbnic_mac_asic = {
.link_down = fbnic_mac_link_down_asic,
.link_up = fbnic_mac_link_up_asic,
.get_sensor = fbnic_mac_get_sensor_asic,
+ .set_led_state = fbnic_set_led_state,
};
/**
@@ -987,6 +1035,197 @@ int fbnic_mac_init(struct fbnic_dev *fbd)
return 0;
}
+/**
+ * __fbnic_led_get_link_speed_mode - Get link speed mode
+ * @curr_speed: ethtool speed
+ *
+ * Return: netdev trigger bit on success, 0 if link speed is not supported
+ *
+ * Convert ethtool speed to mode bit using parameter
+ */
+static u32
+__fbnic_led_get_link_speed_mode(u32 curr_speed)
+{
+ switch (curr_speed) {
+ case SPEED_25000:
+ return BIT(TRIGGER_NETDEV_LINK_25000);
+ case SPEED_50000:
+ return BIT(TRIGGER_NETDEV_LINK_50000);
+ case SPEED_100000:
+ return BIT(TRIGGER_NETDEV_LINK_100000);
+ default:
+ return 0;
+ }
+}
+
+/**
+ * fbnic_led_get_link_speed_mode - Get link speed mode
+ * @fbd: FBNIC Device pointer
+ *
+ * Return: Link speed mode on success, 0 if link speed is not supported
+ *
+ * For the current link speed, this function returns trigger mode bit
+ */
+u32 fbnic_led_get_link_speed_mode(struct fbnic_dev *fbd)
+{
+ u32 curr_speed = fbnic_get_link_speed(fbd->fw_cap.link_speed);
+
+ return __fbnic_led_get_link_speed_mode(curr_speed);
+}
+
+/**
+ * fbnic_led_set_modes_ocp - Set LED state based on OCP link speed
+ * @fbd: FBNIC Device pointer
+ *
+ * Set LED state based on OCP link speed. This function sets up the
+ * LED state based on the current link speed while accounting for the
+ * OCP specs. Called from fbnic_led_link_up() on link state changes.
+ */
+void fbnic_led_set_modes_ocp(struct fbnic_dev *fbd)
+{
+ u32 speed_mode, curr_speed, max_speed;
+
+ lockdep_assert_held(&fbd->led_mutex);
+
+ /* Turn on the activity LED independent of the link speed */
+ fbd->leds[FBNIC_LED_ACTIVITY].enabled_modes = BIT(TRIGGER_NETDEV_TX) |
+ BIT(TRIGGER_NETDEV_RX);
+ fbd->leds[FBNIC_LED_LINK_BLUE].enabled_modes = 0;
+ fbd->leds[FBNIC_LED_LINK_AMBER].enabled_modes = 0;
+
+ curr_speed = fbnic_get_link_speed(fbd->fw_cap.link_speed);
+ if (!curr_speed) {
+ dev_warn(fbd->dev,
+ "Unsupported link speed detected.\n");
+ goto bail;
+ }
+
+ /* can't be zero */
+ speed_mode = __fbnic_led_get_link_speed_mode(curr_speed);
+
+ /* need max_speed for amber/blue leds values */
+ max_speed = fbnic_get_link_speed(fbd->fw_cap.max_link_speed);
+ if (!max_speed) {
+ dev_warn(fbd->dev,
+ "Unsupported max link speed detected.\n");
+ goto bail;
+ }
+
+ /* Set the LED modes according to OCP specs */
+ if (curr_speed < max_speed)
+ fbd->leds[FBNIC_LED_LINK_AMBER].enabled_modes = speed_mode;
+ else
+ fbd->leds[FBNIC_LED_LINK_BLUE].enabled_modes = speed_mode;
+
+bail:
+ /* sync csr with above changes */
+ fbnic_led_update_csr(fbd);
+}
+
+static u32 fbnic_led_get_current_mode(struct fbnic_dev *fbd)
+{
+ u32 modes = BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX);
+
+ if (fbd->led_link_up) {
+ modes |= BIT(TRIGGER_NETDEV_LINK);
+ modes |= fbnic_led_get_link_speed_mode(fbd);
+ }
+
+ return modes;
+}
+
+/**
+ * fbnic_led_get_state - Get current LED state
+ * @fbd: FBNIC Device pointer
+ * @led_idx: LED index
+ *
+ * Get current LED state. This function returns the current LED state
+ * based on the currently configured enabled modes. If current configured
+ * modes are not set, it returns LED_OFF.
+ */
+static int fbnic_led_get_state(struct fbnic_dev *fbd, int led_idx)
+{
+ u8 strobe_mode = fbd->leds[led_idx].strobe_mode;
+ int led_state = LED_OFF;
+ u32 mask;
+
+ if (strobe_mode == FBNIC_STROBE_ON)
+ return LED_ON;
+ if (strobe_mode == FBNIC_STROBE_OFF)
+ return LED_OFF;
+
+ mask = fbnic_led_get_current_mode(fbd);
+ led_state = (mask & fbd->leds[led_idx].enabled_modes) ?
+ LED_ON : LED_OFF;
+
+ return led_state;
+}
+
+/**
+ * fbnic_led_update_csr - Update LED CSR
+ * @fbd: FBNIC Device pointer
+ *
+ * This function updates the LED CSR. This should be called every time
+ * the link speed changes, or when the enabled modes are changed via
+ * the linux LED API.
+ */
+void fbnic_led_update_csr(struct fbnic_dev *fbd)
+{
+ u32 led_csr = FBNIC_SIG_LED_ACTIVITY_OFF;
+ int led_state;
+
+ lockdep_assert_held(&fbd->led_mutex);
+
+ led_state = fbnic_led_get_state(fbd, FBNIC_LED_ACTIVITY);
+ if (led_state == LED_ON)
+ led_csr = FBNIC_SIG_LED_ACTIVITY_DEFAULT;
+
+ led_state = fbnic_led_get_state(fbd, FBNIC_LED_LINK_AMBER);
+ if (led_state == LED_ON)
+ led_csr |= FBNIC_SIG_LED_AMBER_ON;
+
+ led_state = fbnic_led_get_state(fbd, FBNIC_LED_LINK_BLUE);
+ if (led_state == LED_ON)
+ led_csr |= FBNIC_SIG_LED_BLUE_ON;
+
+ dev_dbg(fbd->dev, "writing led_csr %x\n", led_csr);
+ wr32(fbd, FBNIC_SIG_LED, led_csr);
+}
+
+/**
+ * fbnic_led_link_up - Update LED state on link up
+ * @fbd: FBNIC Device pointer
+ *
+ * Called from phylink mac_link_up callback. Sets the internal link state
+ * and configures LED modes according to OCP specs based on current link speed.
+ */
+void fbnic_led_link_up(struct fbnic_dev *fbd)
+{
+ mutex_lock(&fbd->led_mutex);
+
+ fbd->led_link_up = true;
+ fbnic_led_set_modes_ocp(fbd);
+
+ mutex_unlock(&fbd->led_mutex);
+}
+
+/**
+ * fbnic_led_link_down - Update LED state on link down
+ * @fbd: FBNIC Device pointer
+ *
+ * Called from phylink mac_link_down callback. Clears the internal link state
+ * and updates the LED CSR to reflect link-down condition.
+ */
+void fbnic_led_link_down(struct fbnic_dev *fbd)
+{
+ mutex_lock(&fbd->led_mutex);
+
+ fbd->led_link_up = false;
+ fbnic_led_update_csr(fbd);
+
+ mutex_unlock(&fbd->led_mutex);
+}
+
int fbnic_mac_ps_protect_to_config(struct fbnic_dev *fbd, u16 timeout_ms)
{
u16 old_timeout_ms = fbd->ps_timeout;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
index 10f30e0e8f69..089afdde7b55 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
@@ -5,6 +5,8 @@
#define _FBNIC_MAC_H_
#include <linux/types.h>
+#include <linux/leds.h>
+#include <uapi/linux/uleds.h>
struct fbnic_dev;
@@ -33,6 +35,27 @@ struct fbnic_dev;
FBNIC_MAC_RXB_PS_TO_MS(FIELD_MAX(FBNIC_RXB_PAUSE_STORM_THLD_TIME))
#define FBNIC_MAX_JUMBO_FRAME_SIZE 9742
+#define FBNIC_NUM_LEDS 3
+
+struct fbnic_led_cdev {
+ char name[LED_MAX_NAME_SIZE];
+ struct led_classdev led;
+ struct fbnic_dev *fbd;
+ u32 enabled_modes;
+ u8 strobe_mode;
+};
+
+enum {
+ FBNIC_STROBE_DISABLED = 0,
+ FBNIC_STROBE_ON = 1,
+ FBNIC_STROBE_OFF = 2,
+};
+
+enum {
+ FBNIC_LED_ACTIVITY = 0,
+ FBNIC_LED_LINK_AMBER,
+ FBNIC_LED_LINK_BLUE,
+};
/* States loosely based on section 136.8.11.7.5 of IEEE 802.3-2022 Ethernet
* Standard. These are needed to track the state of the PHY as it has a delay
@@ -58,6 +81,13 @@ enum {
FBNIC_LINK_EVENT_DOWN = 2,
};
+enum {
+ FBNIC_LED_STROBE_INIT,
+ FBNIC_LED_ON,
+ FBNIC_LED_OFF,
+ FBNIC_LED_RESTORE,
+};
+
/* Treat the FEC bits as a bitmask laid out as follows:
* Bit 0: RS Enabled
* Bit 1: BASER(Firecode) Enabled
@@ -91,6 +121,29 @@ enum fbnic_sensor_id {
FBNIC_SENSOR_VOLTAGE, /* Voltage in millivolts */
};
+#define FBNIC_SIG_LED_ACTIVITY_DEFAULT \
+ FIELD_PREP(FBNIC_SIG_LED_BLINK_RATE_MASK, \
+ FBNIC_SIG_LED_BLINK_RATE_5HZ)
+#define FBNIC_SIG_LED_ACTIVITY_ON \
+ FIELD_PREP(FBNIC_SIG_LED_OVERRIDE_EN, \
+ FBNIC_SIG_LED_OVERRIDE_ACTIVITY)
+/* override_en=1 with override_val=0 forces the activity LED off
+ * while preserving the default blink rate setting
+ */
+#define FBNIC_SIG_LED_ACTIVITY_OFF \
+ (FBNIC_SIG_LED_ACTIVITY_DEFAULT | \
+ FBNIC_SIG_LED_ACTIVITY_ON)
+#define FBNIC_SIG_LED_AMBER_ON \
+ (FIELD_PREP(FBNIC_SIG_LED_OVERRIDE_EN, \
+ FBNIC_SIG_LED_OVERRIDE_AMBER) | \
+ FIELD_PREP(FBNIC_SIG_LED_OVERRIDE_VAL, \
+ FBNIC_SIG_LED_OVERRIDE_AMBER))
+#define FBNIC_SIG_LED_BLUE_ON \
+ (FIELD_PREP(FBNIC_SIG_LED_OVERRIDE_EN, \
+ FBNIC_SIG_LED_OVERRIDE_BLUE) | \
+ FIELD_PREP(FBNIC_SIG_LED_OVERRIDE_VAL, \
+ FBNIC_SIG_LED_OVERRIDE_BLUE))
+
/* This structure defines the interface hooks for the MAC. The MAC hooks
* will be configured as a const struct provided with a set of function
* pointers.
@@ -112,6 +165,8 @@ enum fbnic_sensor_id {
* Configure MAC for link down event
* void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause);
* Configure MAC for link up event;
+ * void (*set_led_state)(struct fbnic_dev *fbd, int state);
+ * Configure MAC for physical identification states
*
*/
struct fbnic_mac {
@@ -139,10 +194,17 @@ struct fbnic_mac {
void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause);
int (*get_sensor)(struct fbnic_dev *fbd, int id, long *val);
+ void (*set_led_state)(struct fbnic_dev *fbd, int state);
};
int fbnic_mac_init(struct fbnic_dev *fbd);
void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec);
+u32 fbnic_led_get_link_speed_mode(struct fbnic_dev *fbd);
+u32 fbnic_get_link_speed(u8 link_speed);
+void fbnic_led_set_modes_ocp(struct fbnic_dev *fbd);
+void fbnic_led_update_csr(struct fbnic_dev *fbd);
+void fbnic_led_link_up(struct fbnic_dev *fbd);
+void fbnic_led_link_down(struct fbnic_dev *fbd);
int fbnic_mac_ps_protect_to_config(struct fbnic_dev *fbd, u16 timeout);
void fbnic_mac_ps_protect_handler(struct fbnic_dev *fbd);
bool fbnic_mac_check_tx_pause(struct fbnic_dev *fbd);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
index 7e85b480203c..06a40081f603 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c
@@ -368,9 +368,16 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "Netdev registration failed: %d\n", err);
goto ifm_destroy_ptp;
}
+ err = fbnic_led_init(fbd);
+ if (err) {
+ dev_err(&pdev->dev, "led init failed: %d\n", err);
+ goto led_init_fail;
+ }
return 0;
+led_init_fail:
+ fbnic_netdev_unregister(netdev);
ifm_destroy_ptp:
fbnic_ptp_destroy(fbd);
ifm_free_netdev:
@@ -408,6 +415,7 @@ static void fbnic_remove(struct pci_dev *pdev)
if (!fbnic_init_failure(fbd)) {
struct net_device *netdev = fbd->netdev;
+ fbnic_led_exit(fbd);
fbnic_netdev_unregister(netdev);
cancel_delayed_work_sync(&fbd->service_task);
fbnic_ptp_destroy(fbd);
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 09c5225111be..86fccef901cc 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -154,6 +154,7 @@ fbnic_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
struct fbnic_dev *fbd = fbn->fbd;
fbd->mac->link_down(fbd);
+ fbnic_led_link_down(fbd);
fbn->link_down_events++;
}
@@ -172,6 +173,7 @@ fbnic_phylink_mac_link_up(struct phylink_config *config,
fbnic_config_drop_mode(fbn, tx_pause);
fbd->mac->link_up(fbd, tx_pause, rx_pause);
+ fbnic_led_link_up(fbd);
}
static const struct phylink_mac_ops fbnic_phylink_mac_ops = {
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread