1*1718c316SRobert Mustacchi /*
2*1718c316SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*1718c316SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*1718c316SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*1718c316SRobert Mustacchi  * 1.0 of the CDDL.
6*1718c316SRobert Mustacchi  *
7*1718c316SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*1718c316SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*1718c316SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*1718c316SRobert Mustacchi  */
11*1718c316SRobert Mustacchi 
12*1718c316SRobert Mustacchi /*
13*1718c316SRobert Mustacchi  * Copyright 2020 Oxide Computer Company
14*1718c316SRobert Mustacchi  */
15*1718c316SRobert Mustacchi 
16*1718c316SRobert Mustacchi #include <mlxcx.h>
17*1718c316SRobert Mustacchi #include <sys/sensors.h>
18*1718c316SRobert Mustacchi 
19*1718c316SRobert Mustacchi /*
20*1718c316SRobert Mustacchi  * The PRM indicates that the temperature is measured in 1/8th degrees.
21*1718c316SRobert Mustacchi  */
22*1718c316SRobert Mustacchi #define	MLXCX_TEMP_GRAN	8
23*1718c316SRobert Mustacchi 
24*1718c316SRobert Mustacchi /*
25*1718c316SRobert Mustacchi  * Read a single temperature sensor entry. The ksensor framework guarantees that
26*1718c316SRobert Mustacchi  * it will only call this once for a given sensor at any time, though multiple
27*1718c316SRobert Mustacchi  * sensors can be in parallel.
28*1718c316SRobert Mustacchi  */
29*1718c316SRobert Mustacchi static int
mlxcx_temperature_read(void * arg,sensor_ioctl_scalar_t * scalar)30*1718c316SRobert Mustacchi mlxcx_temperature_read(void *arg, sensor_ioctl_scalar_t *scalar)
31*1718c316SRobert Mustacchi {
32*1718c316SRobert Mustacchi 	boolean_t ok;
33*1718c316SRobert Mustacchi 	uint16_t tmp;
34*1718c316SRobert Mustacchi 	mlxcx_register_data_t data;
35*1718c316SRobert Mustacchi 	mlxcx_temp_sensor_t *sensor = arg;
36*1718c316SRobert Mustacchi 	mlxcx_t *mlxp = sensor->mlts_mlx;
37*1718c316SRobert Mustacchi 
38*1718c316SRobert Mustacchi 	bzero(&data, sizeof (data));
39*1718c316SRobert Mustacchi 	data.mlrd_mtmp.mlrd_mtmp_sensor_index = to_be16(sensor->mlts_index);
40*1718c316SRobert Mustacchi 	ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
41*1718c316SRobert Mustacchi 	    MLXCX_REG_MTMP, &data);
42*1718c316SRobert Mustacchi 	if (!ok) {
43*1718c316SRobert Mustacchi 		return (EIO);
44*1718c316SRobert Mustacchi 	}
45*1718c316SRobert Mustacchi 
46*1718c316SRobert Mustacchi 	tmp = from_be16(data.mlrd_mtmp.mlrd_mtmp_temperature);
47*1718c316SRobert Mustacchi 	sensor->mlts_value = (int16_t)tmp;
48*1718c316SRobert Mustacchi 	tmp = from_be16(data.mlrd_mtmp.mlrd_mtmp_max_temperature);
49*1718c316SRobert Mustacchi 	sensor->mlts_max_value = (int16_t)tmp;
50*1718c316SRobert Mustacchi 	bcopy(data.mlrd_mtmp.mlrd_mtmp_name, sensor->mlts_name,
51*1718c316SRobert Mustacchi 	    sizeof (sensor->mlts_name));
52*1718c316SRobert Mustacchi 
53*1718c316SRobert Mustacchi 	scalar->sis_unit = SENSOR_UNIT_CELSIUS;
54*1718c316SRobert Mustacchi 	scalar->sis_gran = MLXCX_TEMP_GRAN;
55*1718c316SRobert Mustacchi 	scalar->sis_prec = 0;
56*1718c316SRobert Mustacchi 	scalar->sis_value = (int64_t)sensor->mlts_value;
57*1718c316SRobert Mustacchi 
58*1718c316SRobert Mustacchi 	return (0);
59*1718c316SRobert Mustacchi }
60*1718c316SRobert Mustacchi 
61*1718c316SRobert Mustacchi static const ksensor_ops_t mlxcx_temp_ops = {
62*1718c316SRobert Mustacchi 	.kso_kind = ksensor_kind_temperature,
63*1718c316SRobert Mustacchi 	.kso_scalar = mlxcx_temperature_read
64*1718c316SRobert Mustacchi };
65*1718c316SRobert Mustacchi 
66*1718c316SRobert Mustacchi void
mlxcx_teardown_sensors(mlxcx_t * mlxp)67*1718c316SRobert Mustacchi mlxcx_teardown_sensors(mlxcx_t *mlxp)
68*1718c316SRobert Mustacchi {
69*1718c316SRobert Mustacchi 	if (mlxp->mlx_temp_nsensors == 0)
70*1718c316SRobert Mustacchi 		return;
71*1718c316SRobert Mustacchi 	(void) ksensor_remove(mlxp->mlx_dip, KSENSOR_ALL_IDS);
72*1718c316SRobert Mustacchi 	kmem_free(mlxp->mlx_temp_sensors, sizeof (mlxcx_temp_sensor_t) *
73*1718c316SRobert Mustacchi 	    mlxp->mlx_temp_nsensors);
74*1718c316SRobert Mustacchi }
75*1718c316SRobert Mustacchi 
76*1718c316SRobert Mustacchi boolean_t
mlxcx_setup_sensors(mlxcx_t * mlxp)77*1718c316SRobert Mustacchi mlxcx_setup_sensors(mlxcx_t *mlxp)
78*1718c316SRobert Mustacchi {
79*1718c316SRobert Mustacchi 	mlxcx_register_data_t data;
80*1718c316SRobert Mustacchi 	boolean_t ok;
81*1718c316SRobert Mustacchi 
82*1718c316SRobert Mustacchi 	mlxp->mlx_temp_nsensors = 0;
83*1718c316SRobert Mustacchi 	bzero(&data, sizeof (data));
84*1718c316SRobert Mustacchi 	ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
85*1718c316SRobert Mustacchi 	    MLXCX_REG_MTCAP, &data);
86*1718c316SRobert Mustacchi 	if (!ok) {
87*1718c316SRobert Mustacchi 		return (B_FALSE);
88*1718c316SRobert Mustacchi 	}
89*1718c316SRobert Mustacchi 
90*1718c316SRobert Mustacchi 	if (data.mlrd_mtcap.mlrd_mtcap_sensor_count == 0) {
91*1718c316SRobert Mustacchi 		return (B_TRUE);
92*1718c316SRobert Mustacchi 	}
93*1718c316SRobert Mustacchi 
94*1718c316SRobert Mustacchi 	mlxp->mlx_temp_nsensors = data.mlrd_mtcap.mlrd_mtcap_sensor_count;
95*1718c316SRobert Mustacchi 	mlxp->mlx_temp_sensors = kmem_zalloc(sizeof (mlxcx_temp_sensor_t) *
96*1718c316SRobert Mustacchi 	    mlxp->mlx_temp_nsensors, KM_SLEEP);
97*1718c316SRobert Mustacchi 
98*1718c316SRobert Mustacchi 	for (uint8_t i = 0; i < mlxp->mlx_temp_nsensors; i++) {
99*1718c316SRobert Mustacchi 		char buf[32];
100*1718c316SRobert Mustacchi 		int ret;
101*1718c316SRobert Mustacchi 
102*1718c316SRobert Mustacchi 		if (snprintf(buf, sizeof (buf), "temp%u", i) >= sizeof (buf)) {
103*1718c316SRobert Mustacchi 			mlxcx_warn(mlxp, "sensor name %u would overflow "
104*1718c316SRobert Mustacchi 			    "internal buffer");
105*1718c316SRobert Mustacchi 			goto err;
106*1718c316SRobert Mustacchi 		}
107*1718c316SRobert Mustacchi 
108*1718c316SRobert Mustacchi 		mlxp->mlx_temp_sensors[i].mlts_mlx = mlxp;
109*1718c316SRobert Mustacchi 		mlxp->mlx_temp_sensors[i].mlts_index = i;
110*1718c316SRobert Mustacchi 
111*1718c316SRobert Mustacchi 		ret = ksensor_create_scalar_pcidev(mlxp->mlx_dip,
112*1718c316SRobert Mustacchi 		    SENSOR_KIND_TEMPERATURE, &mlxcx_temp_ops,
113*1718c316SRobert Mustacchi 		    &mlxp->mlx_temp_sensors[i], buf,
114*1718c316SRobert Mustacchi 		    &mlxp->mlx_temp_sensors[i].mlts_ksensor);
115*1718c316SRobert Mustacchi 		if (ret != 0) {
116*1718c316SRobert Mustacchi 			mlxcx_warn(mlxp, "failed to create temp sensor %s: %d",
117*1718c316SRobert Mustacchi 			    buf, ret);
118*1718c316SRobert Mustacchi 			goto err;
119*1718c316SRobert Mustacchi 		}
120*1718c316SRobert Mustacchi 	}
121*1718c316SRobert Mustacchi 
122*1718c316SRobert Mustacchi 	return (B_TRUE);
123*1718c316SRobert Mustacchi err:
124*1718c316SRobert Mustacchi 	mlxcx_teardown_sensors(mlxp);
125*1718c316SRobert Mustacchi 	return (B_FALSE);
126*1718c316SRobert Mustacchi }
127