Page MenuHomeFreeBSD

D58353.diff
No OneTemporary

D58353.diff

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
@@ -40,6 +40,7 @@
enum aq_fw_link_speed *speed, enum aq_fw_link_fc *fc);
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);
/* Coherent OUT-window read, bracketed by the transaction id. */
static int
@@ -228,6 +229,10 @@
return (0);
}
+/*
+ * No fw_mtx here: the IN window is read-modified only from iflib-serialised
+ * paths, and the sysctl-reachable reads touch the OUT window instead.
+ */
static int
aq2_fw_set_mode(struct aq_hw *hw, enum aq_hw_fw_mpi_state mode,
enum aq_fw_link_speed speed)
@@ -439,11 +444,35 @@
return (0);
}
+static int
+aq2_fw_get_temp(struct aq_hw *hw, int *temp_mc)
+{
+ uint32_t raw;
+ int err;
+
+ err = aq2_fw_interface_buffer_read(hw,
+ AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_REG, &raw, sizeof(raw));
+ if (err != 0)
+ return (err);
+
+ /* The F/W zeroes the block until the PHY reports in. */
+ if ((raw & AQ2_FW_INTERFACE_OUT_PHY_HEALTH_MONITOR_READY) == 0)
+ return (ENXIO);
+
+ /* F/W reports whole degrees Celsius. */
+ *temp_mc = (int)(int8_t)((raw &
+ AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE) >>
+ AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE_S) * 1000;
+
+ 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_mac_addr = aq2_fw_get_mac_addr,
.get_stats = aq2_fw_get_stats,
+ .get_temp = aq2_fw_get_temp,
.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
@@ -229,6 +229,11 @@
#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_A0 0
#define AQ2_FW_INTERFACE_OUT_VERSION_IFACE_VER_B0 1
+#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_TEMPERATURE 0x0000ff00
+#define AQ2_FW_INTERFACE_OUT_PHY_TEMPERATURE_S 8
+
#define AQ2_FW_INTERFACE_OUT_STATS_REG 0x13700
#define AQ2_FW_INTERFACE_OUT_LINK_STATUS_REG 0x13014
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
@@ -68,6 +68,9 @@
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 millidegrees Celsius. */
+ int (*get_temp)(struct aq_hw* hw, int* temp_mc);
+
int (*led_control)(struct aq_hw* hw, uint32_t mode);
};
diff --git a/sys/dev/aq/aq_fw1x.c b/sys/dev/aq/aq_fw1x.c
--- a/sys/dev/aq/aq_fw1x.c
+++ b/sys/dev/aq/aq_fw1x.c
@@ -198,6 +198,7 @@
return (EBUSY);
}
+/* No fw_mtx here: the control register is written whole, never modified. */
static int
aq_fw1x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state mode,
enum aq_fw_link_speed speed)
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
@@ -177,6 +177,7 @@
// MSM Statistics
#define FW2X_CAP_STATISTICS (1ull << (32 + CAPS_HI_STATISTICS))
+#define FW2X_CAP_TEMPERATURE (1ull << (32 + CAPS_HI_TEMPERATURE))
#define FW2X_RATE_MASK (FW2X_RATE_100M | FW2X_RATE_1G | FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G)
@@ -292,9 +293,12 @@
aq_fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state mode,
enum aq_fw_link_speed speed)
{
- uint64_t mpi_ctrl = get_mpi_ctrl(hw);
+ uint64_t mpi_ctrl;
AQ_DBG_ENTERA("speed=%d", speed);
+
+ mtx_lock(&hw->fw_mtx);
+ mpi_ctrl = get_mpi_ctrl(hw);
switch (mode) {
case MPI_INIT:
mpi_ctrl &= ~FW2X_RATE_MASK;
@@ -316,11 +320,14 @@
break;
default:
+ mtx_unlock(&hw->fw_mtx);
trace_error(hw, dbg_init, "fw2x> unknown MPI state %d", mode);
return (EINVAL);
}
set_mpi_ctrl(hw, mpi_ctrl);
+ mtx_unlock(&hw->fw_mtx);
+
AQ_DBG_EXIT(0);
return (0);
}
@@ -329,10 +336,11 @@
aq_fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state* mode,
enum aq_fw_link_speed* link_speed, enum aq_fw_link_fc* fc)
{
- uint64_t mpi_state = get_mpi_state(hw);
- uint32_t rates = mpi_state & FW2X_RATE_MASK;
-
+ uint64_t mpi_state;
+ uint32_t rates;
+ mtx_lock(&hw->fw_mtx);
+ mpi_state = get_mpi_state(hw);
if (mode) {
uint64_t mpi_ctrl = get_mpi_ctrl(hw);
if (mpi_ctrl & FW2X_RATE_MASK)
@@ -340,6 +348,9 @@
else
*mode = MPI_DEINIT;
}
+ mtx_unlock(&hw->fw_mtx);
+
+ rates = mpi_state & FW2X_RATE_MASK;
enum aq_fw_link_speed speed = aq_fw_none;
@@ -433,21 +444,59 @@
}
/* Kick-and-read: take the F/W's previous snapshot, request the next. */
+ mtx_lock(&hw->fw_mtx);
err = aq_hw_fw_downld_dwords(hw,
hw->mbox_addr + offsetof(struct aq_fw2x_mailbox, msm),
(uint32_t*)&aq_fw2x_stats, sizeof aq_fw2x_stats/sizeof(uint32_t));
+ mpi_ctrl = get_mpi_ctrl(hw);
+ mpi_ctrl ^= FW2X_CAP_STATISTICS;
+ set_mpi_ctrl(hw, mpi_ctrl);
+ mtx_unlock(&hw->fw_mtx);
+
aq_fw2x_stats_to_fw_stats(stats, &aq_fw2x_stats);
if (err != 0)
trace_error(hw, dbg_fw,
"fw2x> download statistics data FAILED, error %d", err);
+ return (err);
+}
+
+static int
+aq_fw2x_get_temp(struct aq_hw* hw, int* temp_mc)
+{
+ uint64_t mpi_ctrl, req_bit;
+ uint32_t raw;
+ int err;
+
+ if ((hw->fw_caps & FW2X_CAP_TEMPERATURE) == 0)
+ return (ENOTSUP);
+
+ /* Toggle the request bit and wait for the F/W to echo it back. */
+ mtx_lock(&hw->fw_mtx);
mpi_ctrl = get_mpi_ctrl(hw);
- mpi_ctrl ^= FW2X_CAP_STATISTICS;
- set_mpi_ctrl(hw, mpi_ctrl);
+ req_bit = mpi_ctrl & FW2X_CAP_TEMPERATURE;
+ set_mpi_ctrl(hw, mpi_ctrl ^ FW2X_CAP_TEMPERATURE);
- return (err);
+ err = AQ_HW_WAIT_FOR((get_mpi_state(hw) & FW2X_CAP_TEMPERATURE) !=
+ req_bit, 1, 10000);
+ if (err == 0)
+ err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr +
+ offsetof(struct aq_fw2x_mailbox, phy_temperature),
+ &raw, 1);
+ mtx_unlock(&hw->fw_mtx);
+
+ if (err != 0) {
+ trace_error(hw, dbg_fw,
+ "fw2x> temperature read FAILED, error %d", err);
+ return (err);
+ }
+
+ /* F/W reports 1/256 degree Celsius. */
+ *temp_mc = (int)(int16_t)(raw & 0xffff) * 1000 / 256;
+
+ return (0);
}
static int
@@ -476,6 +525,7 @@
.get_mac_addr = aq_fw2x_get_mac_addr,
.get_stats = aq_fw2x_get_stats,
+ .get_temp = aq_fw2x_get_temp,
.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
@@ -38,6 +38,8 @@
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/atomic.h>
#include <machine/cpufunc.h>
#include <machine/bus.h>
@@ -207,6 +209,9 @@
/* Atlantic 2: firmware statistics interface version (A0/B0). */
uint32_t aq2_iface;
+
+ /* Serialises the F/W MPI control register and mailbox. */
+ struct mtx fw_mtx;
};
#define AQ_HW_MAC 0U
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
@@ -345,6 +345,9 @@
softc->sctx = iflib_get_sctx(ctx);
scctx = softc->scctx;
+ mtx_init(&softc->hw.fw_mtx, device_get_nameunit(softc->dev),
+ "aq firmware", MTX_DEF);
+
softc->mmio_rid = PCIR_BAR(0);
softc->mmio_res = bus_alloc_resource_any(softc->dev, SYS_RES_MEMORY,
&softc->mmio_rid, RF_ACTIVE|RF_SHAREABLE);
@@ -448,6 +451,8 @@
if (softc->mmio_res != NULL)
bus_release_resource(softc->dev, SYS_RES_MEMORY,
softc->mmio_rid, softc->mmio_res);
+ /* iflib skips ifdi_detach when ifdi_attach_pre fails. */
+ mtx_destroy(&softc->hw.fw_mtx);
AQ_DBG_EXIT(rc);
return (rc);
@@ -526,6 +531,8 @@
free(softc->vlan_tags, M_AQ);
+ mtx_destroy(&softc->hw.fw_mtx);
+
AQ_DBG_EXIT(0);
return (0);
}
@@ -1377,6 +1384,25 @@
return (0);
}
+static int
+aq_sysctl_temperature(SYSCTL_HANDLER_ARGS)
+{
+ struct aq_dev *softc = arg1;
+ int error, temp_mc, val;
+
+ if (softc->hw.fw_ops == NULL || softc->hw.fw_ops->get_temp == NULL)
+ return (ENOTSUP);
+
+ error = softc->hw.fw_ops->get_temp(&softc->hw, &temp_mc);
+ if (error != 0)
+ return (error);
+
+ /* millidegrees Celsius -> decikelvin */
+ val = temp_mc / 100 + 2732;
+
+ return (sysctl_handle_int(oidp, &val, 0, req));
+}
+
static void
aq_add_stats_sysctls(struct aq_dev *softc)
{
@@ -1387,6 +1413,7 @@
struct aq_stats *stats = &softc->curr_stats;
struct sysctl_oid *stat_node, *queue_node;
struct sysctl_oid_list *stat_list, *queue_list;
+ int temp_mc;
#define QUEUE_NAME_LEN 32
char namebuf[QUEUE_NAME_LEN];
@@ -1403,6 +1430,13 @@
CTLFLAG_RW, &softc->dbg_categories, 0,
"Trace category mask: init=1 config=2 tx=4 rx=8 intr=16 fw=32");
+ /* 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)
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "temperature",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, softc, 0,
+ aq_sysctl_temperature, "IK", "PHY temperature");
+
/* Driver Statistics */
for (int i = 0; i < softc->tx_rings_count; i++) {
struct aq_ring *ring = softc->tx_rings[i];

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 24, 9:53 PM (11 m, 44 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35385938
Default Alt Text
D58353.diff (9 KB)

Event Timeline