diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index ac8ba8f66013..48413c80d3ec 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -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 diff --git a/sys/dev/pci/if_aq.c b/sys/dev/pci/if_aq.c index 5edb443d5d71..8264ad95536e 100644 --- a/sys/dev/pci/if_aq.c +++ b/sys/dev/pci/if_aq.c @@ -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 -__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 @@ -87,6 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.3 2020/01/17 05:16:33 ryo Exp $"); #include #include #include +#include /* 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) {