Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163544621
D58353.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
D58353.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
@@ -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
Details
Attached
Mime Type
text/plain
Expires
Sat, Jul 25, 8:05 AM (14 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35385938
Default Alt Text
D58353.diff (9 KB)
Attached To
Mode
D58353: aq(4): expose the PHY temperature sensor as a sysctl
Attached
Detach File
Event Timeline
Log In to Comment