Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F171576370
D59593.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D59593.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 August 15, 2026
+.Dd September 11, 2026
.Dt AQ 4
.Os
.Sh NAME
@@ -159,6 +159,24 @@
also reports the approximate distance to the fault in metres.
.El
.Pp
+The following variable controls the PHY thermal shutdown.
+It is present only on adapters whose firmware reports a PHY temperature
+and lets the driver arm the shutdown, and it may also be set as a
+.Xr loader.conf 5
+tunable:
+.Bl -tag -width indent
+.It Va thermal_shutdown.enabled
+Arm the PHY's autonomous thermal shutdown.
+Armed, the PHY drops the link when its die passes the threshold the
+board provisions; the driver reports the trip, waits for the PHY to
+cool, and brings the link back.
+The default, 1, arms the shutdown on every adapter that supports it,
+whether or not its firmware ships it armed; 0 disarms it on those same
+adapters.
+The driver applies the setting from its periodic status poll, normally
+within a second, and again after any reset of the adapter.
+.El
+.Pp
The following variables tune the driver's own tracing:
.Bl -tag -width indent
.It Va debug
@@ -176,4 +194,5 @@
.Xr if_bridge 4 ,
.Xr lagg 4 ,
.Xr miibus 4 ,
+.Xr loader.conf 5 ,
.Xr ifconfig 8
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
@@ -46,6 +46,7 @@
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_thermal_arm(struct aq_hw *hw, bool enable);
static int aq2_fw_get_phy_hot_warning(struct aq_hw *hw, bool *hot);
static int aq2_fw_cable_diag(struct aq_hw *hw, struct aq_hw_cable_diag *cd);
@@ -556,6 +557,38 @@
return (0);
}
+/* interface-in thermal_shutdown.enable; the F/W boots with it set. */
+static int
+aq2_fw_thermal_arm(struct aq_hw *hw, bool enable)
+{
+ uint32_t v, want;
+ int err, limit_mc;
+
+ /* No threshold means an unpopulated word or a departed adapter. */
+ err = aq2_fw_get_thermal_limit(hw, &limit_mc);
+ if (err != 0)
+ return (err);
+
+ mtx_lock(&hw->fw_mtx);
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_REG);
+ if (enable)
+ want = v | AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_ENABLE;
+ else
+ want = v & ~AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_ENABLE;
+ if (want != v) {
+ AQ_WRITE_REG(hw, AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_REG,
+ want);
+ err = aq2_fw_wait_shared_ack(hw);
+ /* Unacked: put the word back so the next poll retries. */
+ if (err != 0)
+ AQ_WRITE_REG(hw,
+ AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_REG, v);
+ }
+ mtx_unlock(&hw->fw_mtx);
+
+ return (err);
+}
+
/* interface-in thermal_shutdown.shutdown_temperature, whole degC. */
static int
aq2_fw_get_thermal_limit(struct aq_hw *hw, int *limit_mc)
@@ -737,7 +770,7 @@
.get_phy_hot_warning = aq2_fw_get_phy_hot_warning,
.cable_diag = aq2_fw_cable_diag,
.phy_reset = NULL, /* A2 clears thermal shutdown on its own reset */
- .thermal_arm = NULL, /* A2 firmware ships thermal shutdown armed */
+ .thermal_arm = aq2_fw_thermal_arm,
.get_thermal_limit = aq2_fw_get_thermal_limit,
.led_control = NULL,
/* Unimplemented: an A2 fibre part reports no SFP module diagnostics. */
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
@@ -142,6 +142,8 @@
int thermal_retry_ticks; /* earliest tick to retry at */
int thermal_temp_mc; /* temp at the last shutdown/cool */
int thermal_recover_mc; /* recover once cooled to here */
+ bool thermal_shutdown_enabled; /* arm the shutdown */
+ int thermal_arm_err; /* last result returned */
bool init_failed; /* aq_hw_init() left the hw down */
int init_retries;
bool reset_pending; /* a re-init is already queued */
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
@@ -89,8 +89,8 @@
/* Resets the PHY (clears a latched thermal shutdown). */
int (*phy_reset)(struct aq_hw* hw);
- /* Arms the firmware autonomous thermal shutdown (A2 ships armed). */
- int (*thermal_arm)(struct aq_hw* hw);
+ /* Arms or disarms the firmware autonomous thermal shutdown. */
+ int (*thermal_arm)(struct aq_hw* hw, bool enable);
/* Reports the PHY high-temperature shutdown threshold (millidegrees C). */
int (*get_thermal_limit)(struct aq_hw* hw, int* limit_mc);
diff --git a/sys/dev/aq/aq_fw2x.c b/sys/dev/aq/aq_fw2x.c
--- a/sys/dev/aq/aq_fw2x.c
+++ b/sys/dev/aq/aq_fw2x.c
@@ -756,11 +756,11 @@
return (err);
}
-/* Arm autonomous thermal shutdown (1E.C478.A), cleared by any PHY reset. */
+/* Arm/disarm thermal shutdown, cleared by any PHY reset. */
static int
-aq_fw2x_thermal_arm(struct aq_hw* hw)
+aq_fw2x_thermal_arm(struct aq_hw* hw, bool enable)
{
- uint16_t ctrl;
+ uint16_t ctrl, want;
int err;
if ((hw->fw_caps & FW2X_CAP_TEMPERATURE) == 0)
@@ -770,11 +770,21 @@
aq_fw2x_phy_id_probe(hw);
err = aq_fw2x_phy_read(hw, AQ_PHY_MMD_GLOBAL, AQ_PHY_THERMAL_CTRL_REG,
&ctrl);
- if (err == 0 && ctrl == 0xffff)
+ if (err != 0)
+ goto out;
+ /* All ones is no PHY answering, not a control word. */
+ if (ctrl == 0xffff) {
err = ENXIO;
- if (err == 0 && (ctrl & AQ_PHY_THERMAL_SD_EN) == 0)
+ goto out;
+ }
+ if (enable)
+ want = ctrl | AQ_PHY_THERMAL_SD_EN;
+ else
+ want = ctrl & ~AQ_PHY_THERMAL_SD_EN;
+ if (want != ctrl)
err = aq_fw2x_phy_write(hw, AQ_PHY_MMD_GLOBAL,
- AQ_PHY_THERMAL_CTRL_REG, ctrl | AQ_PHY_THERMAL_SD_EN);
+ AQ_PHY_THERMAL_CTRL_REG, want);
+out:
mtx_unlock(&hw->fw_mtx);
return (err);
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
@@ -178,6 +178,35 @@
device_printf(aq_dev->dev, "PHY over-temperature warning\n");
}
+/* reconcile thermal arm with knob value */
+static void
+aq_thermal_apply(struct aq_dev *aq_dev)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ bool enable;
+ int err;
+
+ /* A queued re-init would undo the write; the poll after it applies. */
+ if (hw->fw_ops->thermal_arm == NULL || aq_dev->reset_pending)
+ return;
+
+ enable = aq_dev->thermal_shutdown_enabled;
+ err = hw->fw_ops->thermal_arm(hw, enable);
+ /* No sensor to arm against; the knob is absent on such an adapter. */
+ if (err == ENOTSUP)
+ return;
+ /* Print only on a change, so a lasting failure is reported once. */
+ if (err == aq_dev->thermal_arm_err)
+ return;
+ aq_dev->thermal_arm_err = err;
+ if (err != 0)
+ device_printf(aq_dev->dev, "could not %s PHY thermal shutdown, "
+ "error %d\n", enable ? "arm" : "disarm", err);
+ else
+ device_printf(aq_dev->dev, "PHY thermal shutdown %s\n",
+ enable ? "armed" : "disarmed");
+}
+
/* 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)
@@ -192,6 +221,7 @@
switch (aq_dev->thermal_state) {
case AQ_THERMAL_NORMAL:
+ aq_thermal_apply(aq_dev);
aq_thermal_report_hot(aq_dev);
if (aq_dev->linkup)
return;
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
@@ -394,6 +394,7 @@
hw->fc.fc_rx = 1;
hw->fc.fc_tx = 1;
softc->linkup = 0U;
+ softc->thermal_shutdown_enabled = true;
/* Set here, not in aq_if_init(): a recovery re-init must not reset it. */
softc->thermal_retry_ticks = ticks;
@@ -799,14 +800,6 @@
softc->init_failed = false;
softc->init_retries = 0;
- /* aq_hw_init reloads the PHY, resetting the thermal-shutdown arming. */
- if (hw->fw_ops->thermal_arm != NULL) {
- err = hw->fw_ops->thermal_arm(hw);
- if (err != 0 && err != ENOTSUP)
- device_printf(softc->dev,
- "could not arm PHY thermal shutdown\n");
- }
-
aq_if_media_status(ctx, &ifmr);
aq_update_vlan_filters(softc);
@@ -1715,7 +1708,7 @@
struct sysctl_oid *tree = device_get_sysctl_tree(dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
struct aq_stats *stats = &softc->curr_stats;
- struct sysctl_oid *stat_node, *queue_node;
+ struct sysctl_oid *stat_node, *queue_node, *thermal_node;
struct sysctl_oid_list *stat_list, *queue_list;
uint32_t link_up, link_down;
int temp_mc;
@@ -1737,10 +1730,21 @@
/* ENOTSUP means no sensor; other errors may just be a cold PHY. */
if (softc->hw.fw_ops != NULL && softc->hw.fw_ops->get_temp != NULL &&
- softc->hw.fw_ops->get_temp(&softc->hw, &temp_mc) != ENOTSUP)
+ softc->hw.fw_ops->get_temp(&softc->hw, &temp_mc) != ENOTSUP) {
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "temperature",
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, softc, 0,
aq_sysctl_temperature, "IK", "PHY temperature");
+ /* Without the sensor there is no shutdown to arm. */
+ if (softc->hw.fw_ops->thermal_arm != NULL) {
+ thermal_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
+ "thermal_shutdown", CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, "PHY thermal shutdown");
+ SYSCTL_ADD_BOOL(ctx, SYSCTL_CHILDREN(thermal_node),
+ OID_AUTO, "enabled", CTLFLAG_RWTUN,
+ &softc->thermal_shutdown_enabled, 0,
+ "Arm the PHY's autonomous thermal shutdown");
+ }
+ }
/* A cage has no twisted pairs to reflect off, whatever the F/W says. */
if (softc->media_type == AQ_MEDIA_TYPE_TP &&
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Sep 12, 8:57 PM (17 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38818697
Default Alt Text
D59593.diff (9 KB)
Attached To
Mode
D59593: aq(4): arm PHY thermal shutdown from the admin poll
Attached
Detach File
Event Timeline
Log In to Comment