Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164767814
D58435.id182619.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D58435.id182619.diff
View Options
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
@@ -42,6 +42,7 @@
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_temp(struct aq_hw *hw, int *temp_mc);
+static int aq2_fw_get_thermal_limit(struct aq_hw *hw, int *limit_mc);
/* Coherent OUT-window read, bracketed by the transaction id. */
static int
@@ -487,7 +488,7 @@
return (ENXIO);
}
- /* F/W reports whole degrees Celsius. */
+ /* F/W reports whole degrees Celsius, signed. */
*temp_mc = (int)(int8_t)((raw &
AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE) >>
AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE_S) * 1000;
@@ -495,6 +496,50 @@
return (0);
}
+/* interface-in thermal_shutdown.shutdown_temperature, whole degC. */
+static int
+aq2_fw_get_thermal_limit(struct aq_hw *hw, int *limit_mc)
+{
+ uint32_t v;
+ int temp_c;
+
+ v = AQ_READ_REG(hw, AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_REG);
+ temp_c = (v & AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_TEMP) >>
+ AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_TEMP_S;
+ if (temp_c == 0 || temp_c == 0xff)
+ return (ENXIO);
+ *limit_mc = temp_c * 1000;
+
+ return (0);
+}
+
+static int
+aq2_fw_get_phy_fault(struct aq_hw *hw, uint16_t *fault)
+{
+ uint32_t health, code;
+ 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_FAULT) == 0) {
+ *fault = 0;
+ return (0);
+ }
+
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_PHY_FAULT_CODE_REG, &code, sizeof(code));
+ if (err != 0)
+ return (err);
+
+ *fault = (uint16_t)(code & AQ2_FW_INTERFACE_OUT_PHY_FAULT_CODE);
+
+ return (0);
+}
+
const struct aq_firmware_ops aq2_fw_ops = {
.reset = aq2_fw_reset,
.set_mode = aq2_fw_set_mode,
@@ -502,5 +547,9 @@
.get_mac_addr = aq2_fw_get_mac_addr,
.get_stats = aq2_fw_get_stats,
.get_temp = aq2_fw_get_temp,
+ .get_phy_fault = aq2_fw_get_phy_fault,
+ .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,
.led_control = NULL,
};
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
@@ -194,6 +194,11 @@
#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_RENEGOTIATE (1 << 1)
#define AQ2_FW_INTERFACE_IN_LINK_OPTIONS_LINK_UP (1 << 0)
+#define AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_REG 0x12020
+#define AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_ENABLE (1 << 0)
+#define AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_TEMP 0x0000ff00 /* whole degC */
+#define AQ2_FW_INTERFACE_IN_THERMAL_SHUTDOWN_TEMP_S 8
+
#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_REG 0x12a58
#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_QUEUE_OR_TC 0x00800000
#define AQ2_FW_INTERFACE_IN_REQUEST_POLICY_MCAST_RX_QUEUE_TC_INDEX 0x007c0000
@@ -231,9 +236,13 @@
#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_TEMPERATURE 0x0000ff00
#define AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE_S 8
+#define AQ2_FW_INTERFACE_OUT_PHY_FAULT_CODE_REG 0x13624
+#define AQ2_FW_INTERFACE_OUT_PHY_FAULT_CODE 0x0000ffff
+
#define AQ2_FW_INTERFACE_OUT_STATS_REG 0x13700
#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_REG 0x13014
@@ -260,6 +269,9 @@
#define AQ2_RPF_ACT_ART_REQ_MASK_REG(i) (0x14004 + (i) * 0x10)
#define AQ2_RPF_ACT_ART_REQ_ACTION_REG(i) (0x14008 + (i) * 0x10)
+/* Action-resolver table depth: 16 enable sections of 8 rows. */
+#define AQ2_ART_TABLE_SIZE 128
+
/*
* L2 unicast filter MSW register (shared with Atlantic 1). Atlantic 2 sets
* the TAG field so unicast frames are classified into the resolver table.
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
@@ -139,6 +139,15 @@
uint32_t tx_rings_count;
uint32_t rx_rings_count;
bool linkup;
+ bool phy_fault_seen;
+ enum aq_thermal_state {
+ AQ_THERMAL_NORMAL = 0, /* no thermal shutdown pending */
+ AQ_THERMAL_COOLING, /* shut down; waiting to cool */
+ AQ_THERMAL_SETTLING, /* PHY reset; waiting to re-init */
+ } thermal_state;
+ int thermal_settle;
+ int thermal_temp_mc; /* temp at the last shutdown/cool */
+ int thermal_recover_mc; /* recover once cooled to here */
int media_active;
struct aq_hw_stats last_stats;
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
@@ -71,9 +71,24 @@
/* 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);
+
+ /* 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);
+
+ /* Reports the PHY high-temperature shutdown threshold (millidegrees C). */
+ int (*get_thermal_limit)(struct aq_hw* hw, int* limit_mc);
+
int (*led_control)(struct aq_hw* hw, uint32_t mode);
};
+/* PHY global fault codes, register 1E.C850. */
+#define AQ_PHY_FAULT_THERMAL_SHUTDOWN 0x8007
+
/* aq_fw1x/aq_fw2x: Atlantic 1 firmware ABIs; aq2_fw: Atlantic 2 (AQC11x). */
extern const struct aq_firmware_ops aq_fw1x_ops;
extern const struct aq_firmware_ops aq_fw2x_ops;
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
@@ -499,6 +499,171 @@
return (0);
}
+static int
+aq_fw2x_get_phy_fault(struct aq_hw* hw, uint16_t* fault)
+{
+ uint32_t raw;
+ int err;
+
+ mtx_lock(&hw->fw_mtx);
+ err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr +
+ offsetof(struct aq_fw2x_mailbox, phy_h_bit), &raw, 1);
+ mtx_unlock(&hw->fw_mtx);
+
+ if (err != 0)
+ return (err);
+
+ *fault = (uint16_t)(raw >> 16);
+
+ return (0);
+}
+
+/* PHY MDIO access: MMD register read/write via the MAC's MDIO controller. */
+#define AQ_MDIO_IFACE(n) (0x280 + (((n) - 1) * 4))
+#define AQ_MDIO_BUSY 0x80000000u /* iface2 bit 31 */
+#define AQ_MDIO_EXECUTE 0x00008000u /* iface2 bit 15 */
+#define AQ_MDIO_OP_S 12 /* iface2 bits 13:12 */
+#define AQ_MDIO_OP_ADDR 3
+#define AQ_MDIO_OP_READ 1
+#define AQ_MDIO_OP_WRITE 2
+#define AQ_MDIO_PHYADDR_MSK 0x3ffu
+#define AQ_FW_SM_MDIO 0 /* cpu semaphore index */
+
+#define AQ_PHY_ID_MAX 32 /* MDIO port addresses to scan */
+#define AQ_MDIO_MMD_PMAPMD 0x01 /* PMA/PMD MMD */
+#define AQ_PHY_ID2_REG 0x0003 /* PMA/PMD Device Identifier 2 */
+
+#define AQ_PHY_MMD_GLOBAL 0x1e
+#define AQ_PHY_RESET_REG 0x2681 /* 1E.2681.0 = PHY hard reset */
+#define AQ_PHY_RESET 0x0001
+#define AQ_PHY_THERMAL_CTRL_REG 0xc478 /* 1E.C478 thermal control */
+#define AQ_PHY_THERMAL_SD_EN 0x0400 /* .A thermalShutdownEnable */
+
+static uint16_t
+aq_fw2x_mdio_op(struct aq_hw* hw, uint16_t mmd, uint16_t addr, int write,
+ uint16_t data)
+{
+ uint32_t pa = (((uint32_t)hw->phy_id & 0x1f) << 5) | (mmd & 0x1f);
+
+ AQ_WRITE_REG(hw, AQ_MDIO_IFACE(4), addr);
+ AQ_WRITE_REG(hw, AQ_MDIO_IFACE(2),
+ AQ_MDIO_EXECUTE | (AQ_MDIO_OP_ADDR << AQ_MDIO_OP_S) | pa);
+ AQ_HW_WAIT_FOR((AQ_READ_REG(hw, AQ_MDIO_IFACE(2)) & AQ_MDIO_BUSY) == 0,
+ 10, 10000);
+ if (write) {
+ AQ_WRITE_REG(hw, AQ_MDIO_IFACE(3), data);
+ AQ_WRITE_REG(hw, AQ_MDIO_IFACE(2),
+ AQ_MDIO_EXECUTE | (AQ_MDIO_OP_WRITE << AQ_MDIO_OP_S) | pa);
+ } else {
+ AQ_WRITE_REG(hw, AQ_MDIO_IFACE(2),
+ AQ_MDIO_EXECUTE | (AQ_MDIO_OP_READ << AQ_MDIO_OP_S) | pa);
+ }
+ AQ_HW_WAIT_FOR((AQ_READ_REG(hw, AQ_MDIO_IFACE(2)) & AQ_MDIO_BUSY) == 0,
+ 10, 10000);
+ return ((uint16_t)AQ_READ_REG(hw, AQ_MDIO_IFACE(5)));
+}
+
+/* MDIO is serialized against the F/W by cpu semaphore 0. */
+static void
+aq_fw2x_phy_write(struct aq_hw* hw, uint16_t mmd, uint16_t addr, uint16_t data)
+{
+ if (AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(hw, AQ_FW_SM_MDIO) == 1U,
+ 10, 10000) != 0)
+ return;
+ aq_fw2x_mdio_op(hw, mmd, addr, 1, data);
+ reg_glb_cpu_sem_set(hw, 1U, AQ_FW_SM_MDIO);
+}
+
+static int
+aq_fw2x_phy_read(struct aq_hw* hw, uint16_t mmd, uint16_t addr, uint16_t* val)
+{
+ if (AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(hw, AQ_FW_SM_MDIO) == 1U,
+ 10, 10000) != 0)
+ return (ETIMEDOUT);
+ *val = aq_fw2x_mdio_op(hw, mmd, addr, 0, 0);
+ reg_glb_cpu_sem_set(hw, 1U, AQ_FW_SM_MDIO);
+
+ return (0);
+}
+
+/*
+ * Discover the PHY's MDIO port address (Clause-45 PRTAD) by scanning, as the
+ * reference driver does; the address is strap-selectable and not fixed at 0.
+ */
+static bool
+aq_fw2x_init_phy_id(struct aq_hw* hw)
+{
+ uint16_t val;
+ uint8_t id;
+
+ for (id = 0; id < AQ_PHY_ID_MAX; id++) {
+ hw->phy_id = id;
+ if (aq_fw2x_phy_read(hw, AQ_MDIO_MMD_PMAPMD, AQ_PHY_ID2_REG,
+ &val) == 0 && val != 0xffff)
+ return (true);
+ }
+ hw->phy_id = 0;
+ return (false);
+}
+
+/*
+ * A thermal shutdown latches inside the discrete PHY's own firmware
+ * (1E.C850 == 0x8007) and a MAC reset alone cannot clear it. A PHY hard reset
+ * (1E.2681.0, "equivalent to an external reset") returns the PHY to its boot
+ * state; done while the MAC firmware is running, the MAC then reloads the PHY
+ * firmware from flash and a subsequent interface cycle re-establishes the link.
+ */
+static int
+aq_fw2x_phy_reset(struct aq_hw* hw)
+{
+ mtx_lock(&hw->fw_mtx);
+ aq_fw2x_phy_write(hw, AQ_PHY_MMD_GLOBAL, AQ_PHY_RESET_REG, AQ_PHY_RESET);
+ mtx_unlock(&hw->fw_mtx);
+
+ return (0);
+}
+
+/*
+ * The discrete PHY ships with autonomous thermal shutdown disabled
+ * (1E.C478.A == 0); a PHY reset returns it to that default, so this is
+ * re-run on every interface init.
+ */
+static int
+aq_fw2x_thermal_arm(struct aq_hw* hw)
+{
+ uint16_t ctrl;
+
+ mtx_lock(&hw->fw_mtx);
+ if (!hw->phy_id_valid && aq_fw2x_init_phy_id(hw))
+ hw->phy_id_valid = true;
+ if (aq_fw2x_phy_read(hw, AQ_PHY_MMD_GLOBAL, AQ_PHY_THERMAL_CTRL_REG,
+ &ctrl) == 0 && ctrl != 0xffff && (ctrl & AQ_PHY_THERMAL_SD_EN) == 0)
+ aq_fw2x_phy_write(hw, AQ_PHY_MMD_GLOBAL,
+ AQ_PHY_THERMAL_CTRL_REG, ctrl | AQ_PHY_THERMAL_SD_EN);
+ mtx_unlock(&hw->fw_mtx);
+
+ return (0);
+}
+
+/* 1E.C421 high-temp shutdown threshold, degrees C in Q8.8 fixed point. */
+#define AQ_PHY_THERMAL_HIGH_REG 0xc421
+static int
+aq_fw2x_get_thermal_limit(struct aq_hw* hw, int* limit_mc)
+{
+ uint16_t raw;
+ int err;
+
+ mtx_lock(&hw->fw_mtx);
+ err = aq_fw2x_phy_read(hw, AQ_PHY_MMD_GLOBAL, AQ_PHY_THERMAL_HIGH_REG,
+ &raw);
+ mtx_unlock(&hw->fw_mtx);
+ if (err != 0 || raw == 0 || raw == 0xffff)
+ return (ENXIO);
+ *limit_mc = (int)(int16_t)raw * 1000 / 256;
+
+ return (0);
+}
+
static int
aq_fw2x_led_control(struct aq_hw* hw, uint32_t onoff)
{
@@ -526,6 +691,10 @@
.get_mac_addr = aq_fw2x_get_mac_addr,
.get_stats = aq_fw2x_get_stats,
.get_temp = aq_fw2x_get_temp,
+ .get_phy_fault = aq_fw2x_get_phy_fault,
+ .phy_reset = aq_fw2x_phy_reset,
+ .thermal_arm = aq_fw2x_thermal_arm,
+ .get_thermal_limit = aq_fw2x_get_thermal_limit,
.led_control = aq_fw2x_led_control,
};
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
@@ -195,6 +195,10 @@
uint32_t chip_features;
uint64_t fw_caps;
+ /* Atlantic 1: MDIO port address of the PHY, discovered once. */
+ uint8_t phy_id;
+ bool phy_id_valid;
+
bool lro_enabled;
uint32_t mbox_addr;
diff --git a/sys/dev/aq/aq_hw.c b/sys/dev/aq/aq_hw.c
--- a/sys/dev/aq/aq_hw.c
+++ b/sys/dev/aq/aq_hw.c
@@ -598,13 +598,20 @@
aq2_art_filter_set(struct aq_hw *hw, uint32_t idx, uint32_t tag,
uint32_t mask, uint32_t action)
{
+ idx += hw->art_filter_base_index;
+ if (idx >= AQ2_ART_TABLE_SIZE) {
+ device_printf(hw->dev,
+ "ART index %u out of range (firmware base %u)\n", idx,
+ hw->art_filter_base_index);
+ return (EINVAL);
+ }
+
if (AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(hw, AQ2_ART_SEM_INDEX) == 1U,
10U, 1000U) != 0) {
device_printf(hw->dev, "ART semaphore timeout, idx %u\n", idx);
return (EBUSY);
}
- idx += hw->art_filter_base_index;
AQ_WRITE_REG(hw, AQ2_RPF_ACT_ART_REQ_TAG_REG(idx), tag);
AQ_WRITE_REG(hw, AQ2_RPF_ACT_ART_REQ_MASK_REG(idx), mask);
AQ_WRITE_REG(hw, AQ2_RPF_ACT_ART_REQ_ACTION_REG(idx), action);
@@ -739,6 +746,10 @@
err = EINVAL;
goto err_exit;
}
+ if (index >= AQ_HW_MAC_MAX) {
+ err = EINVAL;
+ goto err_exit;
+ }
h = (mac_addr[0] << 8) | (mac_addr[1]);
l = (mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) |
mac_addr[5];
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
@@ -51,6 +51,7 @@
#include "aq_dbg.h"
#include "aq_hw.h"
#include "aq_hw_llh.h"
+#include "aq_fw.h"
int
aq_update_hw_stats(struct aq_dev *aq_dev)
@@ -63,9 +64,7 @@
return (0);
#define AQ_SDELTA(_N_) do { \
- int32_t _d = (int32_t)(stats._N_ - aq_dev->last_stats._N_); \
- if (_d > 0) \
- aq_dev->curr_stats._N_ += _d; \
+ aq_dev->curr_stats._N_ += stats._N_ - aq_dev->last_stats._N_; \
} while (0)
if (aq_dev->linkup) {
AQ_SDELTA(uprc);
@@ -115,6 +114,100 @@
}
+#define AQ_THERMAL_HYSTERESIS_MC 18000 /* recover this far below the limit */
+#define AQ_THERMAL_RECOVER_MC 90000 /* fallback when the limit is unreadable */
+#define AQ_THERMAL_SETTLE_POLLS 5 /* ~5 s for the PHY reset to settle */
+
+/*
+ * The PHY is already dropping to low power by the time the fault is read, so
+ * this temperature is post-trip; report it next to the configured limit.
+ */
+static void
+aq_thermal_report_shutdown(struct aq_dev *aq_dev)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ int temp_mc, limit_mc;
+ bool have_temp, have_limit;
+
+ have_temp = hw->fw_ops->get_temp(hw, &temp_mc) == 0;
+ have_limit = hw->fw_ops->get_thermal_limit(hw, &limit_mc) == 0;
+ if (have_temp)
+ aq_dev->thermal_temp_mc = temp_mc;
+ /* The F/W also exposes a cold_temperature hysteresis point. */
+ aq_dev->thermal_recover_mc = have_limit ?
+ limit_mc - AQ_THERMAL_HYSTERESIS_MC : AQ_THERMAL_RECOVER_MC;
+
+ if (have_temp && have_limit)
+ device_printf(aq_dev->dev, "atlantic: PHY thermal shutdown; "
+ "limit %d C, temp %d C; holding link down until it cools\n",
+ limit_mc / 1000, temp_mc / 1000);
+ else if (have_temp)
+ device_printf(aq_dev->dev, "atlantic: PHY thermal shutdown; "
+ "temp %d C; holding link down until it cools\n",
+ temp_mc / 1000);
+ else
+ device_printf(aq_dev->dev, "atlantic: PHY thermal shutdown; "
+ "holding link down until it cools\n");
+}
+
+/*
+ * Firmware autonomous thermal shutdown latches the PHY (fault 0x8007) and drops
+ * the link. Recovery is held off until the PHY has cooled: A1 then needs a PHY
+ * reset (while the MAC firmware runs) followed by a full re-init to reload the
+ * PHY firmware; A2 recovers on the re-init alone. iflib_request_reset() drives
+ * that stop/init cycle on the next admin pass.
+ */
+static void
+aq_thermal_poll(struct aq_dev *aq_dev)
+{
+ struct aq_hw *hw = &aq_dev->hw;
+ uint16_t fault;
+ int temp_mc;
+
+ switch (aq_dev->thermal_state) {
+ case AQ_THERMAL_NORMAL:
+ if (aq_dev->linkup || aq_dev->phy_fault_seen)
+ return;
+ /* The F/W raises the fault a poll after it drops the link. */
+ if (hw->fw_ops->get_phy_fault(hw, &fault) != 0 || fault == 0)
+ return;
+ aq_dev->phy_fault_seen = true;
+ if (fault != AQ_PHY_FAULT_THERMAL_SHUTDOWN) {
+ device_printf(aq_dev->dev,
+ "atlantic: PHY fault 0x%04x\n", fault);
+ return;
+ }
+ aq_thermal_report_shutdown(aq_dev);
+ aq_dev->thermal_state = AQ_THERMAL_COOLING;
+ return;
+
+ case AQ_THERMAL_COOLING:
+ if (hw->fw_ops->get_temp(hw, &temp_mc) != 0 ||
+ temp_mc > aq_dev->thermal_recover_mc)
+ return;
+ aq_dev->thermal_temp_mc = temp_mc;
+ if (hw->fw_ops->phy_reset != NULL) {
+ hw->fw_ops->phy_reset(hw);
+ aq_dev->thermal_settle = 0;
+ aq_dev->thermal_state = AQ_THERMAL_SETTLING;
+ return;
+ }
+ /* No PHY reset needed (A2): re-init below restores the link. */
+ break;
+
+ case AQ_THERMAL_SETTLING:
+ if (++aq_dev->thermal_settle < AQ_THERMAL_SETTLE_POLLS)
+ return;
+ break;
+ }
+
+ device_printf(aq_dev->dev, "atlantic: PHY cooled to %d C; restoring "
+ "link\n", aq_dev->thermal_temp_mc / 1000);
+ aq_dev->thermal_state = AQ_THERMAL_NORMAL;
+ iflib_request_reset(aq_dev->ctx);
+ iflib_admin_intr_deferred(aq_dev->ctx);
+}
+
void
aq_if_update_admin_status(if_ctx_t ctx)
{
@@ -129,6 +222,7 @@
device_printf(aq_dev->dev, "atlantic: link UP: speed=%d\n", link_speed);
aq_dev->linkup = 1;
+ aq_dev->phy_fault_seen = false;
/* turn on/off RX Pause in RPB */
rpb_rx_xoff_en_per_tc_set(hw, fc_neg.fc_rx, 0);
@@ -151,6 +245,9 @@
aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
}
+ if (hw->fw_ops->get_phy_fault != NULL)
+ aq_thermal_poll(aq_dev);
+
aq_update_hw_stats(aq_dev);
}
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
@@ -338,6 +338,8 @@
softc = iflib_get_softc(ctx);
rc = 0;
+ sysctl_ctx_init(&softc->aq_sysctl_ctx);
+
softc->ctx = ctx;
softc->dev = iflib_get_dev(ctx);
softc->media = iflib_get_media(ctx);
@@ -518,10 +520,6 @@
AQ_DBG_ENTER();
softc = iflib_get_softc(ctx);
- /*
- * Remove the driver's sysctls (and drain in-flight readers) before
- * tearing down the state they reference; a no-op if never registered.
- */
sysctl_ctx_free(&softc->aq_sysctl_ctx);
aq_hw_deinit(&softc->hw);
@@ -749,6 +747,8 @@
atomic_store_rel_long(&hw->flags, 0);
+ softc->phy_fault_seen = false;
+ softc->thermal_state = AQ_THERMAL_NORMAL;
hw->tx_rings_count = softc->tx_rings_count;
err = aq_hw_init(&softc->hw, softc->hw.mac_addr, softc->msix,
@@ -759,6 +759,10 @@
return;
}
+ /* aq_hw_init reloads the PHY, resetting the thermal-shutdown arming. */
+ if (hw->fw_ops->thermal_arm != NULL)
+ hw->fw_ops->thermal_arm(hw);
+
aq_if_media_status(ctx, &ifmr);
aq_update_vlan_filters(softc);
@@ -868,7 +872,7 @@
struct aq_hw *hw = &softc->hw;
uint8_t *mac_addr = NULL;
- if (count == AQ_HW_MAC_MAX)
+ if (count >= AQ_HW_MAC_MAX - 1)
return (0);
mac_addr = LLADDR(dl);
@@ -1424,8 +1428,6 @@
#define QUEUE_NAME_LEN 32
char namebuf[QUEUE_NAME_LEN];
- /* Own these oids so aq_if_detach can drain and free them in order. */
- sysctl_ctx_init(ctx);
/* RSS configuration */
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config",
CTLTYPE_STRING | CTLFLAG_RD, softc, 0,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Aug 4, 8:37 PM (1 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35971826
Default Alt Text
D58435.id182619.diff (18 KB)
Attached To
Mode
D58435: aq(4): PHY thermal-shutdown handling and correctness fixes
Attached
Detach File
Event Timeline
Log In to Comment