Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177595600
D58749.1794814104.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
18 KB
Referenced Files
None
Subscribers
None
D58749.1794814104.diff
View Options
diff --git a/share/man/man4/aq.4 b/share/man/man4/aq.4
--- a/share/man/man4/aq.4
+++ b/share/man/man4/aq.4
@@ -3,7 +3,7 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd July 9, 2026
+.Dd August 6, 2026
.Dt AQ 4
.Os
.Sh NAME
@@ -79,6 +79,35 @@
.It
Marvell AQC116C (10Mb/100Mb/1Gb RJ45)
.El
+.Sh SYSCTL VARIABLES
+The following read-only variables are available per interface as
+.Va dev.aq.%d.%s ,
+where
+.Ar %d
+is the interface number.
+Each is present only when the adapter's firmware supports it.
+.Bl -tag -width indent
+.It Va temperature
+The PHY die temperature.
+.It Va fw_link_up
+The number of link up transitions counted by the firmware.
+.It Va fw_link_down
+The number of link down transitions counted by the firmware.
+Comparing this against the transitions logged by the driver
+distinguishes a single link event from a flapping link.
+.El
+.Pp
+The following variables tune the driver's own tracing:
+.Bl -tag -width indent
+.It Va debug
+Trace verbosity: 0 disables tracing, 3 reports errors, 4 adds warnings,
+5 adds traces and 6 adds detail.
+The default is 3.
+.It Va debug_categories
+Bit mask selecting the traced categories: init 1, config 2, tx 4, rx 8,
+intr 16 and fw 32.
+All categories are enabled by default.
+.El
.Sh SEE ALSO
.Xr arp 4 ,
.Xr miibus 4 ,
diff --git a/sys/dev/aq/aq2_fw.c b/sys/dev/aq/aq2_fw.c
--- a/sys/dev/aq/aq2_fw.c
+++ b/sys/dev/aq/aq2_fw.c
@@ -39,10 +39,14 @@
enum aq_fw_link_speed speed);
static int aq2_fw_get_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state *mode,
enum aq_fw_link_speed *speed, enum aq_fw_link_fc *fc);
+static int aq2_fw_get_link_info(struct aq_hw *hw, struct aq_hw_link_info *info);
static int aq2_fw_get_mac_addr(struct aq_hw *hw, uint8_t *mac);
static int aq2_fw_get_stats(struct aq_hw *hw, struct aq_hw_stats *stats);
+static int aq2_fw_get_link_counters(struct aq_hw *hw, uint32_t *up,
+ uint32_t *down);
static int aq2_fw_get_temp(struct aq_hw *hw, int *temp_mc);
static int aq2_fw_get_thermal_limit(struct aq_hw *hw, int *limit_mc);
+static int aq2_fw_get_phy_hot_warning(struct aq_hw *hw, bool *hot);
/* Coherent OUT-window read, bracketed by the transaction id. */
static int
@@ -369,6 +373,21 @@
return (0);
}
+static int
+aq2_fw_get_link_info(struct aq_hw *hw, struct aq_hw_link_info *info)
+{
+ uint32_t v;
+
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_OUT_LINK_STATUS_REG);
+
+ info->full_duplex =
+ (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_DUPLEX) != 0;
+ info->eee = (v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_EEE) != 0;
+ info->state = v & AQ2_FW_INTERFACE_OUT_LINK_STATUS_STATE;
+
+ return (0);
+}
+
/* A2 firmware stats; layout depends on interface version. */
struct aq2_fw_statistics_a0 {
uint32_t link_up;
@@ -474,6 +493,30 @@
return (0);
}
+/* Only the A0 interface layout carries the link transition counters. */
+static int
+aq2_fw_get_link_counters(struct aq_hw *hw, uint32_t *up, uint32_t *down)
+{
+ union aq2_fw_statistics u;
+ int err;
+
+ if (hw->aq2_iface != AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0)
+ return (ENOTSUP);
+
+ err = aq2_fw_interface_buffer_read(hw, AQ2_FW_INTERFACE_OUT_STATS_REG,
+ (uint32_t *)&u, sizeof(u));
+ if (err != 0) {
+ trace_error(hw, dbg_fw,
+ "aq2> link counter read FAILED, error %d", err);
+ return (err);
+ }
+
+ *up = u.a0.link_up;
+ *down = u.a0.link_down;
+
+ return (0);
+}
+
static int
aq2_fw_get_temp(struct aq_hw *hw, int *temp_mc)
{
@@ -543,14 +586,37 @@
return (0);
}
+static int
+aq2_fw_get_phy_hot_warning(struct aq_hw *hw, bool *hot)
+{
+ uint32_t health;
+ int err;
+
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_REG, &health,
+ sizeof(health));
+ if (err != 0)
+ return (err);
+
+ if ((health & AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_READY) == 0)
+ return (ENXIO);
+
+ *hot = (health & AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_HOT) != 0;
+
+ return (0);
+}
+
const struct aq_firmware_ops aq2_fw_ops = {
.reset = aq2_fw_reset,
.set_mode = aq2_fw_set_mode,
.get_mode = aq2_fw_get_mode,
+ .get_link_info = aq2_fw_get_link_info,
.get_mac_addr = aq2_fw_get_mac_addr,
.get_stats = aq2_fw_get_stats,
+ .get_link_counters = aq2_fw_get_link_counters,
.get_temp = aq2_fw_get_temp,
.get_phy_fault = aq2_fw_get_phy_fault,
+ .get_phy_hot_warning = aq2_fw_get_phy_hot_warning,
.phy_reset = NULL, /* A2 clears thermal shutdown on its own reset */
.thermal_arm = NULL, /* A2 firmware ships thermal shutdown armed */
.get_thermal_limit = aq2_fw_get_thermal_limit,
diff --git a/sys/dev/aq/aq2_hw.h b/sys/dev/aq/aq2_hw.h
--- a/sys/dev/aq/aq2_hw.h
+++ b/sys/dev/aq/aq2_hw.h
@@ -237,6 +237,7 @@
#define AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_REG 0x13620
#define AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_READY 0x00000001
#define AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_FAULT 0x00000002
+#define AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_HOT 0x00000004
#define AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE 0x0000ff00
#define AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE_S 8
diff --git a/sys/dev/aq/aq_device.h b/sys/dev/aq/aq_device.h
--- a/sys/dev/aq/aq_device.h
+++ b/sys/dev/aq/aq_device.h
@@ -123,6 +123,8 @@
bool linkup;
uint32_t link_speed; /* Mbit/s last announced to the stack */
uint16_t phy_fault_last; /* last fault code reported */
+ bool phy_hot_last; /* last over-temperature warning */
+ bool link_read_failed; /* link state read is failing */
enum aq_thermal_state {
AQ_THERMAL_NORMAL = 0, /* no thermal shutdown pending */
AQ_THERMAL_COOLING, /* shut down; waiting to cool */
diff --git a/sys/dev/aq/aq_fw.h b/sys/dev/aq/aq_fw.h
--- a/sys/dev/aq/aq_fw.h
+++ b/sys/dev/aq/aq_fw.h
@@ -65,15 +65,24 @@
int (*set_mode)(struct aq_hw* hw, enum aq_hw_fw_mpi_state mode, enum aq_fw_link_speed speed);
int (*get_mode)(struct aq_hw* hw, enum aq_hw_fw_mpi_state* mode, enum aq_fw_link_speed* speed, enum aq_fw_link_fc* fc);
+ /* Reports duplex, EEE and the firmware link state beyond the rate. */
+ int (*get_link_info)(struct aq_hw* hw, struct aq_hw_link_info* info);
+
int (*get_mac_addr)(struct aq_hw* hw, uint8_t* mac_addr);
int (*get_stats)(struct aq_hw* hw, struct aq_hw_stats* stats);
+ /* Reports the firmware's own link transition counters. */
+ int (*get_link_counters)(struct aq_hw* hw, uint32_t* up, uint32_t* down);
+
/* Reports millidegrees Celsius. */
int (*get_temp)(struct aq_hw* hw, int* temp_mc);
/* Reports the PHY global fault code; zero means no fault. */
int (*get_phy_fault)(struct aq_hw* hw, uint16_t* fault);
+ /* Reports the pre-shutdown PHY over-temperature warning. */
+ int (*get_phy_hot_warning)(struct aq_hw* hw, bool* hot);
+
/* Resets the PHY (clears a latched thermal shutdown). */
int (*phy_reset)(struct aq_hw* hw);
diff --git a/sys/dev/aq/aq_hw.h b/sys/dev/aq/aq_hw.h
--- a/sys/dev/aq/aq_hw.h
+++ b/sys/dev/aq/aq_hw.h
@@ -162,6 +162,12 @@
bool fc_tx;
};
+struct aq_hw_link_info {
+ bool full_duplex;
+ bool eee;
+ uint8_t state;
+};
+
struct aq_hw {
void *aq_dev;
device_t dev;
diff --git a/sys/dev/aq/aq_irq.c b/sys/dev/aq/aq_irq.c
--- a/sys/dev/aq/aq_irq.c
+++ b/sys/dev/aq/aq_irq.c
@@ -39,6 +39,7 @@
#include <sys/param.h>
#include <sys/bitstring.h>
#include <sys/kernel.h>
+#include <sys/sbuf.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <net/if.h>
@@ -149,6 +150,34 @@
"holding link down until it cools\n");
}
+/* Pre-trip warning: the PHY is hot but the firmware has not shut it down. */
+static void
+aq_thermal_report_hot(struct aq_dev *aq_dev)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ int temp_mc;
+ bool hot;
+
+ if (hw->fw_ops->get_phy_hot_warning == NULL ||
+ hw->fw_ops->get_phy_hot_warning(hw, &hot) != 0)
+ return;
+
+ /* Report each edge once; the bit stays set for the whole excursion. */
+ if (hot == aq_dev->phy_hot_last)
+ return;
+ aq_dev->phy_hot_last = hot;
+
+ if (!hot) {
+ device_printf(aq_dev->dev, "PHY temperature normal again\n");
+ return;
+ }
+ if (hw->fw_ops->get_temp(hw, &temp_mc) == 0)
+ device_printf(aq_dev->dev, "PHY over-temperature warning, "
+ "temp %d C\n", temp_mc / 1000);
+ else
+ device_printf(aq_dev->dev, "PHY over-temperature warning\n");
+}
+
/* Recover after cooldown: A1 needs a PHY reset then re-init, A2 re-inits alone. */
static void
aq_thermal_poll(struct aq_dev *aq_dev)
@@ -159,6 +188,7 @@
switch (aq_dev->thermal_state) {
case AQ_THERMAL_NORMAL:
+ aq_thermal_report_hot(aq_dev);
if (aq_dev->linkup)
return;
/* The F/W raises the fault a poll after it drops the link. */
@@ -211,6 +241,72 @@
iflib_admin_intr_deferred(aq_dev->ctx);
}
+static const char *
+aq_fc_string(const struct aq_hw_fc_info *fc)
+{
+
+ if (fc->fc_rx && fc->fc_tx)
+ return ("rx/tx");
+ if (fc->fc_rx)
+ return ("rx");
+ if (fc->fc_tx)
+ return ("tx");
+ return ("none");
+}
+
+static void
+aq_link_report_up(struct aq_dev *aq_dev, uint32_t link_speed,
+ const struct aq_hw_fc_info *fc)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ struct aq_hw_link_info info;
+
+ if (hw->fw_ops->get_link_info != NULL &&
+ hw->fw_ops->get_link_info(hw, &info) == 0) {
+ device_printf(aq_dev->dev, "link UP: speed=%u, %s-duplex, "
+ "flowcontrol %s, EEE %s\n", link_speed,
+ info.full_duplex ? "full" : "half", aq_fc_string(fc),
+ info.eee ? "on" : "off");
+ return;
+ }
+ device_printf(aq_dev->dev, "link UP: speed=%u, flowcontrol %s\n",
+ link_speed, aq_fc_string(fc));
+}
+
+/*
+ * The firmware raises a PHY fault a poll after it drops the link, so a
+ * thermal trip usually reports only its temperature here; aq_thermal_poll()
+ * names it on the following poll.
+ */
+static void
+aq_link_report_down(struct aq_dev *aq_dev)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ struct aq_hw_link_info info;
+ struct sbuf sb;
+ char detail[96];
+ int temp_mc;
+ uint16_t fault;
+
+ sbuf_new(&sb, detail, sizeof(detail), SBUF_FIXEDLEN);
+
+ if (hw->fw_ops->get_phy_fault != NULL &&
+ hw->fw_ops->get_phy_fault(hw, &fault) == 0 && fault != 0)
+ sbuf_printf(&sb, ", PHY fault 0x%04x", fault);
+ if (hw->fw_ops->get_link_info != NULL &&
+ hw->fw_ops->get_link_info(hw, &info) == 0)
+ sbuf_printf(&sb, ", F/W link state %u", info.state);
+ if (hw->fw_ops->get_temp != NULL &&
+ hw->fw_ops->get_temp(hw, &temp_mc) == 0)
+ sbuf_printf(&sb, ", temp %d C", temp_mc / 1000);
+
+ if (sbuf_finish(&sb) != 0)
+ device_printf(aq_dev->dev, "link DOWN\n");
+ else
+ device_printf(aq_dev->dev, "link DOWN%s\n", sbuf_data(&sb));
+ sbuf_delete(&sb);
+}
+
void
aq_if_update_admin_status(if_ctx_t ctx)
{
@@ -221,7 +317,17 @@
struct aq_hw_fc_info fc_neg;
- aq_hw_get_link_state(hw, &link_speed, &fc_neg);
+ int err;
+
+ err = aq_hw_get_link_state(hw, &link_speed, &fc_neg);
+ if (err != 0 && !aq_dev->link_read_failed) {
+ aq_dev->link_read_failed = true;
+ device_printf(aq_dev->dev, "link state read failed, error %d; "
+ "holding the last known state\n", err);
+ } else if (err == 0 && aq_dev->link_read_failed) {
+ aq_dev->link_read_failed = false;
+ device_printf(aq_dev->dev, "link state read recovered\n");
+ }
/* A stopped or half-initialized interface has no link. */
running = (if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING) != 0;
@@ -229,12 +335,10 @@
link_speed = 0;
/* A retrain can change the speed without ever dropping the link. */
- if (link_speed != 0U &&
+ if (err == 0 && link_speed != 0U &&
(!aq_dev->linkup || link_speed != aq_dev->link_speed)) {
if (!aq_dev->linkup) {
- if (bootverbose)
- device_printf(aq_dev->dev,
- "link UP: speed=%d\n", link_speed);
+ aq_link_report_up(aq_dev, link_speed, &fc_neg);
aq_dev->phy_fault_last = 0;
} else
device_printf(aq_dev->dev, "link speed=%d\n",
@@ -251,10 +355,11 @@
aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
/* update ITR settings according new link speed */
- aq_hw_interrupt_moderation_set(hw);
- } else if (link_speed == 0U && aq_dev->linkup) { /* link was UP */
- if (bootverbose)
- device_printf(aq_dev->dev, "link DOWN\n");
+ if (aq_hw_interrupt_moderation_set(hw) != 0)
+ device_printf(aq_dev->dev,
+ "could not update interrupt moderation\n");
+ } else if (err == 0 && link_speed == 0U && aq_dev->linkup) {
+ aq_link_report_down(aq_dev);
aq_dev->linkup = 0;
aq_dev->link_speed = 0;
diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c
--- a/sys/dev/aq/aq_main.c
+++ b/sys/dev/aq/aq_main.c
@@ -405,7 +405,12 @@
__func__, rc);
goto fail;
}
- aq_hw_capabilities(softc);
+ rc = aq_hw_capabilities(softc);
+ if (rc != 0) {
+ device_printf(softc->dev, "unsupported device %04x:%04x\n",
+ pci_get_vendor(softc->dev), pci_get_device(softc->dev));
+ goto fail;
+ }
rc = aq_hw_get_mac_permanent(hw, hw->mac_addr);
if (rc != 0) {
@@ -525,7 +530,8 @@
sysctl_ctx_free(&softc->aq_sysctl_ctx);
- aq_hw_deinit(&softc->hw);
+ if (aq_hw_deinit(&softc->hw) != 0)
+ device_printf(softc->dev, "could not shut the hardware down\n");
for (i = 0; i < softc->rx_rings_count; i++)
iflib_irq_free(ctx, &softc->rx_rings[i]->irq);
@@ -558,7 +564,9 @@
AQ_DBG_ENTER();
aq_if_stop(ctx);
- aq_hw_deinit(&softc->hw);
+ if (aq_hw_deinit(&softc->hw) != 0)
+ device_printf(softc->dev,
+ "could not shut the hardware down for suspend\n");
/* iflib_device_suspend() does not stop the interface for us. */
if_setdrvflagbits(iflib_get_ifp(ctx), IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
@@ -810,15 +818,28 @@
aq_if_rx_queue_intr_enable(ctx, i);
}
- aq_hw_start(hw);
+ err = aq_hw_start(hw);
+ if (err != 0)
+ device_printf(softc->dev, "could not start the datapath: %d\n",
+ err);
aq_if_enable_intr(ctx);
- aq_hw_rss_hash_set(&softc->hw, softc->rss_key);
- aq_hw_rss_set(&softc->hw, softc->rss_table);
+ err = aq_hw_rss_hash_set(&softc->hw, softc->rss_key);
+ if (err != 0)
+ device_printf(softc->dev, "could not set the RSS key: %d\n",
+ err);
+ err = aq_hw_rss_set(&softc->hw, softc->rss_table);
+ if (err != 0)
+ device_printf(softc->dev,
+ "could not set the RSS indirection table: %d\n", err);
/* A2 selects UDP hashing per-protocol in REDIR2; A1 uses the filter. */
- if (!IS_CHIP_FEATURE(hw, ATLANTIC2))
- aq_hw_udp_rss_enable(hw, (aq_rss_hashconfig() &
+ if (!IS_CHIP_FEATURE(hw, ATLANTIC2)) {
+ err = aq_hw_udp_rss_enable(hw, (aq_rss_hashconfig() &
(RSS_HASHTYPE_RSS_UDP_IPV4 | RSS_HASHTYPE_RSS_UDP_IPV6 |
RSS_HASHTYPE_RSS_UDP_IPV6_EX)) != 0);
+ if (err != 0)
+ device_printf(softc->dev,
+ "could not configure UDP RSS hashing: %d\n", err);
+ }
err = aq_hw_set_link_speed(hw, hw->link_rate);
if (err != 0)
device_printf(softc->dev, "could not set link speed: %d\n", err);
@@ -848,15 +869,20 @@
aq_if_disable_intr(ctx);
for (i = 0; i < softc->tx_rings_count; i++) {
- aq_ring_tx_stop(hw, softc->tx_rings[i]);
+ if (aq_ring_tx_stop(hw, softc->tx_rings[i]) != 0)
+ device_printf(softc->dev,
+ "could not stop TX ring %d\n", i);
softc->tx_rings[i]->tx_head = 0;
softc->tx_rings[i]->tx_tail = 0;
}
for (i = 0; i < softc->rx_rings_count; i++) {
- aq_ring_rx_stop(hw, softc->rx_rings[i]);
+ if (aq_ring_rx_stop(hw, softc->rx_rings[i]) != 0)
+ device_printf(softc->dev,
+ "could not stop RX ring %d\n", i);
}
- aq_hw_reset(&softc->hw, true);
+ if (aq_hw_reset(&softc->hw, true) != 0)
+ device_printf(softc->dev, "could not reset the MAC on stop\n");
memset(&softc->last_stats, 0, sizeof(softc->last_stats));
/* Each bring-up gets its own budget of re-init attempts. */
softc->init_retries = 0;
@@ -897,7 +923,11 @@
return (0);
mac_addr = LLADDR(dl);
- aq_hw_mac_addr_set(hw, mac_addr, count + 1);
+ if (aq_hw_mac_addr_set(hw, mac_addr, count + 1) != 0) {
+ device_printf(softc->dev,
+ "could not program multicast address %6D\n", mac_addr, ":");
+ return (0);
+ }
aq_log_detail(hw, "set %d mc address %6D", count + 1, mac_addr, ":");
return (1);
@@ -1171,7 +1201,9 @@
int vlan_tag = -1;
int i;
- hw_atl_b0_hw_vlan_promisc_set(hw, true);
+ if (hw_atl_b0_hw_vlan_promisc_set(hw, true) != 0)
+ device_printf(softc->dev,
+ "could not open the VLAN filter for update\n");
for (i = 0; i < AQ_HW_VLAN_MAX_FILTERS; i++) {
bit_ffs_at(softc->vlan_tags, bit_pos, 4096, &vlan_tag);
if (vlan_tag != -1) {
@@ -1185,7 +1217,9 @@
}
}
- hw_atl_b0_hw_vlan_set(hw, aq_vlans);
+ if (hw_atl_b0_hw_vlan_set(hw, aq_vlans) != 0)
+ device_printf(softc->dev,
+ "could not program the VLAN filter table\n");
if (hw_atl_b0_hw_vlan_promisc_set(hw,
aq_is_vlan_promisc_required(softc) ||
(if_getflags(iflib_get_ifp(softc->ctx)) & IFF_PROMISC) != 0) != 0)
@@ -1397,6 +1431,25 @@
return (sysctl_handle_int(oidp, &val, 0, req));
}
+/* arg2 selects the counter: 0 = link up, 1 = link down. */
+static int
+aq_sysctl_fw_link_counter(SYSCTL_HANDLER_ARGS)
+{
+ struct aq_dev *softc = arg1;
+ uint32_t up, down;
+ int error;
+
+ if (softc->hw.fw_ops == NULL ||
+ softc->hw.fw_ops->get_link_counters == NULL)
+ return (ENOTSUP);
+
+ error = softc->hw.fw_ops->get_link_counters(&softc->hw, &up, &down);
+ if (error != 0)
+ return (error);
+
+ return (sysctl_handle_32(oidp, arg2 == 0 ? &up : &down, 0, req));
+}
+
static void
aq_add_stats_sysctls(struct aq_dev *softc)
{
@@ -1407,6 +1460,7 @@
struct aq_stats *stats = &softc->curr_stats;
struct sysctl_oid *stat_node, *queue_node;
struct sysctl_oid_list *stat_list, *queue_list;
+ uint32_t link_up, link_down;
int temp_mc;
#define QUEUE_NAME_LEN 32
@@ -1431,6 +1485,21 @@
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, softc, 0,
aq_sysctl_temperature, "IK", "PHY temperature");
+ /* Only some firmware interface versions count link transitions. */
+ if (softc->hw.fw_ops != NULL &&
+ softc->hw.fw_ops->get_link_counters != NULL &&
+ softc->hw.fw_ops->get_link_counters(&softc->hw, &link_up,
+ &link_down) != ENOTSUP) {
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fw_link_up",
+ CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE, softc, 0,
+ aq_sysctl_fw_link_counter, "IU",
+ "Link up transitions counted by the firmware");
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fw_link_down",
+ CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE, softc, 1,
+ aq_sysctl_fw_link_counter, "IU",
+ "Link down transitions counted by the firmware");
+ }
+
/* Driver Statistics */
for (int i = 0; i < softc->tx_rings_count; i++) {
struct aq_ring *ring = softc->tx_rings[i];
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 16, 7:28 AM (23 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41742377
Default Alt Text
D58749.1794814104.diff (18 KB)
Attached To
Mode
D58749: aq(4): report link transitions and previously silent failures
Attached
Detach File
Event Timeline