support internal PHY temperature sensor

This commit is contained in:
ryo 2020-01-17 05:22:42 +00:00
parent d9566e9681
commit b03841d7c9
2 changed files with 148 additions and 17 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pci,v 1.420 2020/01/16 07:11:50 yamaguchi Exp $
# $NetBSD: files.pci,v 1.421 2020/01/17 05:22:42 ryo Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@ -168,7 +168,7 @@ attach mpii at pci
file dev/pci/mpii.c mpii
# Aquantia/Atlantic 10-Gigabit Ethernet
device aq: ether, ifnet, arp
device aq: ether, ifnet, arp, sysmon_envsys
attach aq at pci
file dev/pci/if_aq.c aq
defflag opt_if_aq.h AQ_EVENT_COUNTERS

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_aq.c,v 1.3 2020/01/17 05:16:33 ryo Exp $ */
/* $NetBSD: if_aq.c,v 1.4 2020/01/17 05:22:42 ryo Exp $ */
/**
* aQuantia Corporation Network Driver
@ -62,10 +62,11 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.3 2020/01/17 05:16:33 ryo Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.4 2020/01/17 05:22:42 ryo Exp $");
#ifdef _KERNEL_OPT
#include "opt_if_aq.h"
#include "sysmon_envsys.h"
#endif
#include <sys/param.h>
@ -87,6 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.3 2020/01/17 05:16:33 ryo Exp $");
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <dev/sysmon/sysmonvar.h>
/* driver configuration */
#define CONFIG_INTR_MODERATION_ENABLE true /* delayed interrupt */
@ -710,11 +712,14 @@ typedef struct fw2x_capabilities {
typedef struct fw2x_mailbox { /* struct fwHostInterface */
aq_mailbox_header_t header;
fw2x_msm_statistics_t msm; /* msmStatistics_t msm; */
uint16_t phy_h_bit;
uint16_t phy_fault_code;
int16_t phy_temperature;
uint8_t cable_len;
uint8_t reserved1;
uint32_t phy_info1;
#define PHYINFO1_FAULT_CODE __BITS(31,16)
#define PHYINFO1_PHY_H_BIT __BITS(0,15)
uint32_t phy_info2;
#define PHYINFO2_TEMPERATURE __BITS(15,0)
#define PHYINFO2_CABLE_LEN __BITS(23,16)
fw2x_phy_cable_diag_data_t diag_data;
uint32_t reserved[8];
@ -907,6 +912,9 @@ struct aq_firmware_ops {
int (*get_mode)(struct aq_softc *, aq_hw_fw_mpi_state_t *,
aq_link_speed_t *, aq_link_fc_t *, aq_link_eee_t *);
int (*get_stats)(struct aq_softc *, aq_hw_stats_s_t *);
#if NSYSMON_ENVSYS > 0
int (*get_temperature)(struct aq_softc *, uint32_t *);
#endif
};
#ifdef AQ_EVENT_COUNTERS
@ -933,6 +941,11 @@ struct aq_firmware_ops {
#define AQ_LOCK(sc) mutex_enter(&(sc)->sc_mutex);
#define AQ_UNLOCK(sc) mutex_exit(&(sc)->sc_mutex);
/* lock for FW2X_MPI_{CONTROL,STATE]_REG read-modify-write */
#define AQ_MPI_LOCK(sc) mutex_enter(&(sc)->sc_mpi_mutex);
#define AQ_MPI_UNLOCK(sc) mutex_exit(&(sc)->sc_mpi_mutex);
struct aq_softc {
device_t sc_dev;
@ -951,6 +964,11 @@ struct aq_softc {
bool sc_poll_linkstat;
bool sc_detect_linkstat;
#if NSYSMON_ENVSYS > 0
struct sysmon_envsys *sc_sme;
envsys_data_t sc_sensor_temp;
#endif
callout_t sc_tick_ch;
int sc_nintrs;
@ -965,6 +983,7 @@ struct aq_softc {
uint16_t sc_revision;
kmutex_t sc_mutex;
kmutex_t sc_mpi_mutex;
struct aq_firmware_ops *sc_fw_ops;
uint64_t sc_fw_caps;
@ -1063,6 +1082,9 @@ static void aq_tx_pcq_free(struct aq_softc *, struct aq_txring *);
static void aq_initmedia(struct aq_softc *);
static void aq_enable_intr(struct aq_softc *, bool, bool);
#if NSYSMON_ENVSYS > 0
static void aq_temp_refresh(struct sysmon_envsys *, envsys_data_t *);
#endif
static void aq_tick(void *);
static int aq_legacy_intr(void *);
static int aq_link_intr(void *);
@ -1099,19 +1121,28 @@ static int fw2x_set_mode(struct aq_softc *, aq_hw_fw_mpi_state_t,
static int fw2x_get_mode(struct aq_softc *, aq_hw_fw_mpi_state_t *,
aq_link_speed_t *, aq_link_fc_t *, aq_link_eee_t *);
static int fw2x_get_stats(struct aq_softc *, aq_hw_stats_s_t *);
#if NSYSMON_ENVSYS > 0
static int fw2x_get_temperature(struct aq_softc *, uint32_t *);
#endif
static struct aq_firmware_ops aq_fw1x_ops = {
.reset = fw1x_reset,
.set_mode = fw1x_set_mode,
.get_mode = fw1x_get_mode,
.get_stats = fw1x_get_stats
.get_stats = fw1x_get_stats,
#if NSYSMON_ENVSYS > 0
.get_temperature = NULL
#endif
};
static struct aq_firmware_ops aq_fw2x_ops = {
.reset = fw2x_reset,
.set_mode = fw2x_set_mode,
.get_mode = fw2x_get_mode,
.get_stats = fw2x_get_stats
.get_stats = fw2x_get_stats,
#if NSYSMON_ENVSYS > 0
.get_temperature = fw2x_get_temperature
#endif
};
CFATTACH_DECL3_NEW(aq, sizeof(struct aq_softc),
@ -1216,6 +1247,7 @@ aq_attach(device_t parent, device_t self, void *aux)
sc->sc_dev = self;
mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NET);
mutex_init(&sc->sc_mpi_mutex, MUTEX_DEFAULT, IPL_NET);
sc->sc_pc = pc = pa->pa_pc;
sc->sc_pcitag = tag = pa->pa_tag;
@ -1433,6 +1465,31 @@ aq_attach(device_t parent, device_t self, void *aux)
/* update media */
aq_ifmedia_change(ifp);
#if NSYSMON_ENVSYS > 0
/* temperature monitoring */
if (sc->sc_fw_ops != NULL && sc->sc_fw_ops->get_temperature != NULL &&
(sc->sc_fw_caps & FW2X_CTRL_TEMPERATURE) != 0) {
sc->sc_sme = sysmon_envsys_create();
sc->sc_sme->sme_name = device_xname(self);
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_flags = 0;
sc->sc_sme->sme_refresh = aq_temp_refresh;
sc->sc_sensor_temp.units = ENVSYS_STEMP;
sc->sc_sensor_temp.state = ENVSYS_SINVALID;
snprintf(sc->sc_sensor_temp.desc, ENVSYS_DESCLEN, "PHY");
sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor_temp);
sysmon_envsys_register(sc->sc_sme);
/*
* for unknown reasons, the first call of fw2x_get_temperature()
* will always fail (firmware matter?), so run once now.
*/
aq_temp_refresh(sc->sc_sme, &sc->sc_sensor_temp);
}
#endif
#ifdef AQ_EVENT_COUNTERS
/* get starting statistics values */
if (sc->sc_fw_ops != NULL && sc->sc_fw_ops->get_stats != NULL &&
@ -1507,6 +1564,14 @@ aq_detach(device_t self, int flags __unused)
callout_stop(&sc->sc_tick_ch);
#if NSYSMON_ENVSYS > 0
if (sc->sc_sme != NULL) {
/* all sensors associated with this will also be detached */
sysmon_envsys_unregister(sc->sc_sme);
sc->sc_sme = NULL;
}
#endif
#ifdef AQ_EVENT_COUNTERS
AQ_EVCNT_DETACH(sc, uprc);
AQ_EVCNT_DETACH(sc, mprc);
@ -1528,6 +1593,7 @@ aq_detach(device_t self, int flags __unused)
AQ_EVCNT_DETACH(sc, cprc);
#endif
mutex_destroy(&sc->sc_mpi_mutex);
mutex_destroy(&sc->sc_mutex);
return 0;
@ -2216,7 +2282,12 @@ static int
fw2x_set_mode(struct aq_softc *sc, aq_hw_fw_mpi_state_t mode,
aq_link_speed_t speed, aq_link_fc_t fc, aq_link_eee_t eee)
{
uint64_t mpi_ctrl = AQ_READ64_REG(sc, FW2X_MPI_CONTROL_REG);
uint64_t mpi_ctrl;
int error = 0;
AQ_MPI_LOCK(sc);
mpi_ctrl = AQ_READ64_REG(sc, FW2X_MPI_CONTROL_REG);
switch (mode) {
case MPI_INIT:
@ -2250,11 +2321,14 @@ fw2x_set_mode(struct aq_softc *sc, aq_hw_fw_mpi_state_t mode,
break;
default:
device_printf(sc->sc_dev, "fw2x> unknown MPI state %d\n", mode);
return EINVAL;
error = EINVAL;
goto failure;
}
AQ_WRITE64_REG(sc, FW2X_MPI_CONTROL_REG, mpi_ctrl);
return 0;
failure:
AQ_MPI_UNLOCK(sc);
return error;
}
static int
@ -2344,12 +2418,13 @@ fw2x_get_stats(struct aq_softc *sc, aq_hw_stats_s_t *stats)
{
int error;
AQ_MPI_LOCK(sc);
/* Say to F/W to update the statistics */
error = toggle_mpi_ctrl_and_wait(sc, FW2X_CTRL_STATISTICS, 1, 25);
if (error != 0) {
device_printf(sc->sc_dev,
"fw2x> statistics update error %d\n", error);
return error;
goto failure;
}
CTASSERT(sizeof(fw2x_msm_statistics_t) <= sizeof(struct aq_hw_stats_s));
@ -2359,13 +2434,49 @@ fw2x_get_stats(struct aq_softc *sc, aq_hw_stats_s_t *stats)
if (error != 0) {
device_printf(sc->sc_dev,
"fw2x> download statistics data FAILED, error %d", error);
return error;
goto failure;
}
stats->dpc = AQ_READ_REG(sc, RX_DMA_DROP_PKT_CNT_REG);
stats->cprc = AQ_READ_REG(sc, RX_DMA_COALESCED_PKT_CNT_REG);
failure:
AQ_MPI_UNLOCK(sc);
return error;
}
#if NSYSMON_ENVSYS > 0
static int
fw2x_get_temperature(struct aq_softc *sc, uint32_t *temp)
{
int error;
uint32_t value, celsius;
AQ_MPI_LOCK(sc);
/* Say to F/W to update the temperature */
error = toggle_mpi_ctrl_and_wait(sc, FW2X_CTRL_TEMPERATURE, 1, 25);
if (error != 0)
goto failure;
error = aq_fw_downld_dwords(sc,
sc->sc_mbox_addr + offsetof(fw2x_mailbox_t, phy_info2),
&value, sizeof(value) / sizeof(uint32_t));
if (error != 0)
goto failure;
/* 1/256 decrees C to microkelvin */
celsius = __SHIFTOUT(value, PHYINFO2_TEMPERATURE);
if (celsius == 0) {
error = EIO;
goto failure;
}
*temp = celsius * (1000000 / 256) + 273150000;
failure:
AQ_MPI_UNLOCK(sc);
return 0;
}
#endif
static int
aq_fw_downld_dwords(struct aq_softc *sc, uint32_t addr, uint32_t *p,
@ -3644,6 +3755,26 @@ aq_tx_pcq_free(struct aq_softc *sc, struct aq_txring *txring)
}
}
#if NSYSMON_ENVSYS > 0
static void
aq_temp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct aq_softc *sc;
uint32_t temp;
int error;
sc = sme->sme_cookie;
error = sc->sc_fw_ops->get_temperature(sc, &temp);
if (error == 0) {
edata->value_cur = temp;
edata->state = ENVSYS_SVALID;
} else {
edata->state = ENVSYS_SINVALID;
}
}
#endif
static void
aq_tick(void *arg)
{