#include "igb_sw.h"
#include <sys/sensors.h>
#include <sys/bitmap.h>
#define E1000_THMJT_TEMP(x) BITX(x, 8, 0)
#define E1000_THMJT_VALID(x) BITX(x, 31, 31)
#define E1000_THMJT_RESOLUTION 1
#define E1000_THMJT_PRECISION 5
#define IGB_NVM_ETS_CFG 0x3e
#define IGB_NVM_ETS_CFG_NSENSORS(x) BITX(x, 2, 0)
#define IGB_NVM_ETS_CFG_TYPE(x) BITX(x, 5, 3)
#define IGB_NVM_ETS_CFG_TYPE_EMC1413 0
#define IGB_NVM_ETS_SENSOR_LOC(x) BITX(x, 13, 10)
#define IGB_NVM_ETS_SENSOR_INDEX(x) BITX(x, 9, 8)
#define IGB_NVM_ETS_SENSOR_THRESH(x) BITX(x, 7, 0)
#define IGB_ETS_I2C_ADDRESS 0xf8
#define EMC1413_REG_CFG 0x03
#define EMC1413_REG_CFG_RANGE (1 << 2)
#define EMC1413_RANGE_ADJ (-64)
#define EMC1413_REG_INT_DIODE_HI 0x00
#define EMC1413_REG_INT_DIODE_LO 0x29
#define EMC1413_REG_EXT1_DIODE_HI 0x01
#define EMC1413_REG_EXT1_DIODE_LO 0x10
#define EMC1413_REG_EXT2_DIODE_HI 0x23
#define EMC1413_REG_EXT2_DIODE_LO 0x24
#define EMC1413_REG_EXT3_DIODE_HI 0x2a
#define EMC1413_REG_EXT3_DIODE_LO 0x2b
static int
igb_sensor_reg_temperature(void *arg, sensor_ioctl_scalar_t *scalar)
{
igb_t *igb = arg;
uint32_t reg;
if (igb->hw.mac.ops.acquire_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM) !=
E1000_SUCCESS) {
return (EIO);
}
reg = E1000_READ_REG(&igb->hw, E1000_THMJT);
igb->hw.mac.ops.release_swfw_sync(&igb->hw, E1000_SWFW_PWRTS_SM);
if (E1000_THMJT_VALID(reg) == 0) {
return (EIO);
}
scalar->sis_unit = SENSOR_UNIT_CELSIUS;
scalar->sis_gran = E1000_THMJT_RESOLUTION;
scalar->sis_prec = E1000_THMJT_PRECISION;
scalar->sis_value = E1000_THMJT_TEMP(reg);
return (0);
}
static const ksensor_ops_t igb_sensor_reg_ops = {
.kso_kind = ksensor_kind_temperature,
.kso_scalar = igb_sensor_reg_temperature
};
static boolean_t
igb_sensors_create_minors(igb_t *igb)
{
int ret;
igb_sensors_t *sp = &igb->igb_sensors;
if ((ret = ksensor_create_scalar_pcidev(igb->dip,
SENSOR_KIND_TEMPERATURE, &igb_sensor_reg_ops, igb, "builtin",
&sp->isn_reg_ksensor)) != 0) {
igb_log(igb, IGB_LOG_ERROR, "failed to create main sensor: %d",
ret);
return (B_FALSE);
}
return (B_TRUE);
}
static boolean_t
igb_sensors_init_ets(igb_t *igb, uint_t ets_off, uint_t index)
{
uint16_t val;
int ret;
igb_sensors_t *sensors = &igb->igb_sensors;
igb_ets_t *etsp = &sensors->isn_ets[sensors->isn_nents];
igb_ets_loc_t loc;
if ((ret = e1000_read_nvm(&igb->hw, ets_off, 1, &val)) !=
E1000_SUCCESS) {
igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
"at offset 0x%x: error %d", ets_off, ret);
return (B_FALSE);
}
loc = IGB_NVM_ETS_SENSOR_LOC(val);
if (loc == IGB_ETS_LOC_NA) {
return (B_TRUE);
}
etsp->iet_loc = loc;
etsp->iet_index = IGB_NVM_ETS_SENSOR_INDEX(val);
etsp->iet_thresh = IGB_NVM_ETS_SENSOR_THRESH(val);
sensors->isn_nents++;
return (B_TRUE);
}
void
igb_init_sensors(igb_t *igb)
{
struct e1000_hw *hw = &igb->hw;
uint16_t ets_off;
hw = &igb->hw;
if (hw->mac.type != e1000_i350 || hw->bus.func != 0) {
return;
}
ets_off = 0xffff;
(void) e1000_read_nvm(hw, IGB_NVM_ETS_CFG, 1, &ets_off);
if (ets_off != 0 && ets_off != 0xffff) {
int ret;
uint_t nents, i;
uint16_t val;
if ((ret = e1000_read_nvm(hw, ets_off, 1, &val)) !=
E1000_SUCCESS) {
igb_log(igb, IGB_LOG_ERROR, "failed to read ETS word "
"at offset 0x%x: error %d", ets_off, ret);
return;
}
if (IGB_NVM_ETS_CFG_TYPE(val) != IGB_NVM_ETS_CFG_TYPE_EMC1413) {
return;
}
nents = IGB_NVM_ETS_CFG_NSENSORS(val);
if (nents > IGB_ETS_MAX) {
igb_log(igb, IGB_LOG_ERROR, "firmware NVM ETS "
"configuration has more entries (%d) than allowed",
nents);
nents = IGB_ETS_MAX;
}
for (i = 0; i < nents; i++) {
if (!igb_sensors_init_ets(igb, ets_off, i)) {
return;
}
}
}
if (!igb_sensors_create_minors(igb)) {
(void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
return;
}
igb->igb_sensors.isn_valid = B_TRUE;
}
void
igb_fini_sensors(igb_t *igb)
{
if (igb->igb_sensors.isn_valid) {
(void) ksensor_remove(igb->dip, KSENSOR_ALL_IDS);
igb->igb_sensors.isn_valid = B_FALSE;
}
}