diff options
Diffstat (limited to 'usr/src/uts/common/io/mlxcx')
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx.c | 15 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx.h | 23 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx_cmd.c | 13 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx_gld.c | 27 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx_intr.c | 101 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx_reg.h | 28 | ||||
-rw-r--r-- | usr/src/uts/common/io/mlxcx/mlxcx_sensor.c | 126 |
7 files changed, 320 insertions, 13 deletions
diff --git a/usr/src/uts/common/io/mlxcx/mlxcx.c b/usr/src/uts/common/io/mlxcx/mlxcx.c index dbad9be958..90964d2fd1 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx.c +++ b/usr/src/uts/common/io/mlxcx/mlxcx.c @@ -1066,6 +1066,11 @@ mlxcx_teardown(mlxcx_t *mlxp) mlxcx_intr_disable(mlxp); } + if (mlxp->mlx_attach & MLXCX_ATTACH_SENSORS) { + mlxcx_teardown_sensors(mlxp); + mlxp->mlx_attach &= ~MLXCX_ATTACH_SENSORS; + } + if (mlxp->mlx_attach & MLXCX_ATTACH_CHKTIMERS) { mlxcx_teardown_checktimers(mlxp); mlxp->mlx_attach &= ~MLXCX_ATTACH_CHKTIMERS; @@ -1800,7 +1805,7 @@ mlxcx_setup_ports(mlxcx_t *mlxp) p->mlx_port_event.mla_mlx = mlxp; p->mlx_port_event.mla_port = p; mutex_init(&p->mlx_port_event.mla_mtx, NULL, - MUTEX_DRIVER, DDI_INTR_PRI(mlxp->mlx_intr_pri)); + MUTEX_DRIVER, DDI_INTR_PRI(mlxp->mlx_async_intr_pri)); p->mlp_init |= MLXCX_PORT_INIT; mutex_init(&p->mlp_mtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(mlxp->mlx_intr_pri)); @@ -2716,7 +2721,7 @@ mlxcx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) for (i = 0; i <= MLXCX_FUNC_ID_MAX; i++) { mlxp->mlx_npages_req[i].mla_mlx = mlxp; mutex_init(&mlxp->mlx_npages_req[i].mla_mtx, NULL, - MUTEX_DRIVER, DDI_INTR_PRI(mlxp->mlx_intr_pri)); + MUTEX_DRIVER, DDI_INTR_PRI(mlxp->mlx_async_intr_pri)); } mlxp->mlx_attach |= MLXCX_ATTACH_ASYNC_TQ; @@ -2869,6 +2874,11 @@ mlxcx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) } mlxp->mlx_attach |= MLXCX_ATTACH_CHKTIMERS; + if (!mlxcx_setup_sensors(mlxp)) { + goto err; + } + mlxp->mlx_attach |= MLXCX_ATTACH_SENSORS; + /* * Finally, tell MAC that we exist! */ @@ -2913,7 +2923,6 @@ static struct dev_ops mlxcx_dev_ops = { .devo_attach = mlxcx_attach, .devo_detach = mlxcx_detach, .devo_reset = nodev, - .devo_power = ddi_power, .devo_quiesce = ddi_quiesce_not_supported, .devo_cb_ops = &mlxcx_cb_ops }; diff --git a/usr/src/uts/common/io/mlxcx/mlxcx.h b/usr/src/uts/common/io/mlxcx/mlxcx.h index 77d36447c6..e28fe89806 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx.h +++ b/usr/src/uts/common/io/mlxcx/mlxcx.h @@ -1009,6 +1009,15 @@ typedef struct { uint64_t mldp_wq_check_interval_sec; } mlxcx_drv_props_t; +typedef struct { + mlxcx_t *mlts_mlx; + uint8_t mlts_index; + id_t mlts_ksensor; + int16_t mlts_value; + int16_t mlts_max_value; + uint8_t mlts_name[MLXCX_MTMP_NAMELEN]; +} mlxcx_temp_sensor_t; + typedef enum { MLXCX_ATTACH_FM = 1 << 0, MLXCX_ATTACH_PCI_CONFIG = 1 << 1, @@ -1028,6 +1037,7 @@ typedef enum { MLXCX_ATTACH_CAPS = 1 << 15, MLXCX_ATTACH_CHKTIMERS = 1 << 16, MLXCX_ATTACH_ASYNC_TQ = 1 << 17, + MLXCX_ATTACH_SENSORS = 1 << 18 } mlxcx_attach_progress_t; struct mlxcx { @@ -1082,6 +1092,7 @@ struct mlxcx { * Interrupts */ uint_t mlx_intr_pri; + uint_t mlx_async_intr_pri; uint_t mlx_intr_type; /* always MSI-X */ int mlx_intr_count; size_t mlx_intr_size; /* allocation size */ @@ -1171,6 +1182,12 @@ struct mlxcx { ddi_periodic_t mlx_eq_checktimer; ddi_periodic_t mlx_cq_checktimer; ddi_periodic_t mlx_wq_checktimer; + + /* + * Sensors + */ + uint8_t mlx_temp_nsensors; + mlxcx_temp_sensor_t *mlx_temp_sensors; }; /* @@ -1446,6 +1463,12 @@ extern const char *mlxcx_port_status_string(mlxcx_port_status_t); extern const char *mlxcx_event_name(mlxcx_event_t); +/* + * Sensor Functions + */ +extern boolean_t mlxcx_setup_sensors(mlxcx_t *); +extern void mlxcx_teardown_sensors(mlxcx_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_cmd.c b/usr/src/uts/common/io/mlxcx/mlxcx_cmd.c index c8eb1335ea..32c40ec3ea 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx_cmd.c +++ b/usr/src/uts/common/io/mlxcx/mlxcx_cmd.c @@ -667,7 +667,8 @@ static void mlxcx_cmd_init(mlxcx_t *mlxp, mlxcx_cmd_t *cmd) { bzero(cmd, sizeof (*cmd)); - mutex_init(&cmd->mlcmd_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&cmd->mlcmd_lock, NULL, MUTEX_DRIVER, + DDI_INTR_PRI(mlxp->mlx_async_intr_pri)); cv_init(&cmd->mlcmd_cv, NULL, CV_DRIVER, NULL); cmd->mlcmd_token = id_alloc(mlxp->mlx_cmd.mcmd_tokens); cmd->mlcmd_poll = mlxp->mlx_cmd.mcmd_polled; @@ -1687,6 +1688,10 @@ mlxcx_reg_name(mlxcx_register_id_t rid) return ("PPCNT"); case MLXCX_REG_PPLM: return ("PPLM"); + case MLXCX_REG_MTCAP: + return ("MTCAP"); + case MLXCX_REG_MTMP: + return ("MTMP"); default: return ("???"); } @@ -1736,6 +1741,12 @@ mlxcx_cmd_access_register(mlxcx_t *mlxp, mlxcx_cmd_reg_opmod_t opmod, case MLXCX_REG_PPLM: dsize = sizeof (mlxcx_reg_pplm_t); break; + case MLXCX_REG_MTCAP: + dsize = sizeof (mlxcx_reg_mtcap_t); + break; + case MLXCX_REG_MTMP: + dsize = sizeof (mlxcx_reg_mtmp_t); + break; default: dsize = 0; VERIFY(0); diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_gld.c b/usr/src/uts/common/io/mlxcx/mlxcx_gld.c index 89645bb2b1..941eb0f9e7 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx_gld.c +++ b/usr/src/uts/common/io/mlxcx/mlxcx_gld.c @@ -809,19 +809,32 @@ mlxcx_mac_ring_stop(mac_ring_driver_t rh) if (wq->mlwq_state & MLXCX_WQ_BUFFERS) { + list_t cq_buffers; + + /* + * Take the buffers away from the CQ. If the CQ is being + * processed and the WQ has been stopped, a completion + * which does not match to a buffer will be ignored. + */ + list_create(&cq_buffers, sizeof (mlxcx_buffer_t), + offsetof(mlxcx_buffer_t, mlb_cq_entry)); + + list_move_tail(&cq_buffers, &cq->mlcq_buffers); + + mutex_enter(&cq->mlcq_bufbmtx); + list_move_tail(&cq_buffers, &cq->mlcq_buffers_b); + mutex_exit(&cq->mlcq_bufbmtx); + + cq->mlcq_bufcnt = 0; + mutex_exit(&wq->mlwq_mtx); mutex_exit(&cq->mlcq_mtx); /* Return any outstanding buffers to the free pool. */ - while ((buf = list_remove_head(&cq->mlcq_buffers)) != NULL) { + while ((buf = list_remove_head(&cq_buffers)) != NULL) { mlxcx_buf_return_chain(mlxp, buf, B_FALSE); } - mutex_enter(&cq->mlcq_bufbmtx); - while ((buf = list_remove_head(&cq->mlcq_buffers_b)) != NULL) { - mlxcx_buf_return_chain(mlxp, buf, B_FALSE); - } - mutex_exit(&cq->mlcq_bufbmtx); - cq->mlcq_bufcnt = 0; + list_destroy(&cq_buffers); s = wq->mlwq_bufs; mutex_enter(&s->mlbs_mtx); diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_intr.c b/usr/src/uts/common/io/mlxcx/mlxcx_intr.c index f79c148d20..53ea4d683e 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx_intr.c +++ b/usr/src/uts/common/io/mlxcx/mlxcx_intr.c @@ -12,6 +12,7 @@ /* * Copyright (c) 2020, the University of Queensland * Copyright 2020 RackTop Systems, Inc. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* @@ -922,6 +923,20 @@ lookagain: if (added) goto lookagain; + /* + * This check could go just after the lookagain + * label, but it is a hot code path so we don't + * want to unnecessarily grab a lock and check + * a flag for a relatively rare event (the ring + * being stopped). + */ + mutex_enter(&wq->mlwq_mtx); + if ((wq->mlwq_state & MLXCX_WQ_STARTED) == 0) { + mutex_exit(&wq->mlwq_mtx); + goto nextcq; + } + mutex_exit(&wq->mlwq_mtx); + buf = list_head(&mlcq->mlcq_buffers); mlxcx_warn(mlxp, "got completion on CQ %x but " "no buffer matching wqe found: %x (first " @@ -1165,6 +1180,7 @@ mlxcx_intr_setup(mlxcx_t *mlxp) ret = ddi_intr_get_supported_types(dip, &types); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to get supported interrupt types"); return (B_FALSE); } @@ -1176,15 +1192,21 @@ mlxcx_intr_setup(mlxcx_t *mlxp) ret = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_MSIX, &nintrs); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to get number of interrupts"); return (B_FALSE); } if (nintrs < 2) { - mlxcx_warn(mlxp, "%d MSI-X interrupts available, but mlxcx " + mlxcx_warn(mlxp, "%d MSI-X interrupts supported, but mlxcx " "requires 2", nintrs); return (B_FALSE); } ret = ddi_intr_get_navail(dip, DDI_INTR_TYPE_MSIX, &navail); + if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, + "Failed to get number of available interrupts"); + return (B_FALSE); + } if (navail < 2) { mlxcx_warn(mlxp, "%d MSI-X interrupts available, but mlxcx " "requires 2", navail); @@ -1203,10 +1225,14 @@ mlxcx_intr_setup(mlxcx_t *mlxp) ret = ddi_intr_alloc(dip, mlxp->mlx_intr_handles, DDI_INTR_TYPE_MSIX, 0, navail, &mlxp->mlx_intr_count, DDI_INTR_ALLOC_NORMAL); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to allocate %d interrupts", navail); mlxcx_intr_teardown(mlxp); return (B_FALSE); } if (mlxp->mlx_intr_count < mlxp->mlx_intr_cq0 + 1) { + mlxcx_warn(mlxp, "%d MSI-X interrupts allocated, but mlxcx " + "requires %d", mlxp->mlx_intr_count, + mlxp->mlx_intr_cq0 + 1); mlxcx_intr_teardown(mlxp); return (B_FALSE); } @@ -1214,10 +1240,29 @@ mlxcx_intr_setup(mlxcx_t *mlxp) ret = ddi_intr_get_pri(mlxp->mlx_intr_handles[0], &mlxp->mlx_intr_pri); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to get interrupt priority"); mlxcx_intr_teardown(mlxp); return (B_FALSE); } + /* + * Set the interrupt priority for the asynchronous handler higher + * than the ring handlers. Some operations which issue commands, + * and thus rely on the async interrupt handler for posting + * completion, do so with a CQ mutex held. The CQ mutex is also + * acquired during ring processing, so if the ring processing vector + * happens to be assigned to the same CPU as the async vector + * it can hold off the async interrupt thread and lead to a deadlock. + * By assigning a higher priority to the async vector, it will + * always be dispatched. + */ + mlxp->mlx_async_intr_pri = mlxp->mlx_intr_pri; + if (mlxp->mlx_async_intr_pri < LOCK_LEVEL) { + mlxp->mlx_async_intr_pri++; + } else { + mlxp->mlx_intr_pri--; + } + mlxp->mlx_eqs_size = mlxp->mlx_intr_count * sizeof (mlxcx_event_queue_t); mlxp->mlx_eqs = kmem_zalloc(mlxp->mlx_eqs_size, KM_SLEEP); @@ -1227,8 +1272,11 @@ mlxcx_intr_setup(mlxcx_t *mlxp) * mutex and avl tree to be init'ed - so do it now. */ for (i = 0; i < mlxp->mlx_intr_count; ++i) { + uint_t pri = (i == 0) ? mlxp->mlx_async_intr_pri : + mlxp->mlx_intr_pri; + mutex_init(&mlxp->mlx_eqs[i].mleq_mtx, NULL, MUTEX_DRIVER, - DDI_INTR_PRI(mlxp->mlx_intr_pri)); + DDI_INTR_PRI(pri)); cv_init(&mlxp->mlx_eqs[i].mleq_cv, NULL, CV_DRIVER, NULL); if (i < mlxp->mlx_intr_cq0) @@ -1239,9 +1287,38 @@ mlxcx_intr_setup(mlxcx_t *mlxp) offsetof(mlxcx_completion_queue_t, mlcq_eq_entry)); } + while (mlxp->mlx_async_intr_pri > DDI_INTR_PRI_MIN) { + ret = ddi_intr_set_pri(mlxp->mlx_intr_handles[0], + mlxp->mlx_async_intr_pri); + if (ret == DDI_SUCCESS) + break; + mlxcx_note(mlxp, + "!Failed to set interrupt priority to %u for " + "async interrupt vector", mlxp->mlx_async_intr_pri); + /* + * If it was not possible to set the IPL for the async + * interrupt to the desired value, then try a lower priority. + * Some PSMs can only accommodate a limited number of vectors + * at eatch priority level (or group of priority levels). Since + * the async priority must be set higher than the ring + * handlers, lower both. The ring handler priority is set + * below. + */ + mlxp->mlx_async_intr_pri--; + mlxp->mlx_intr_pri--; + } + + if (mlxp->mlx_async_intr_pri == DDI_INTR_PRI_MIN) { + mlxcx_warn(mlxp, "Failed to find an interrupt priority for " + "async interrupt vector"); + mlxcx_intr_teardown(mlxp); + return (B_FALSE); + } + ret = ddi_intr_add_handler(mlxp->mlx_intr_handles[0], mlxcx_intr_async, (caddr_t)mlxp, (caddr_t)&mlxp->mlx_eqs[0]); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to add async interrupt handler"); mlxcx_intr_teardown(mlxp); return (B_FALSE); } @@ -1268,9 +1345,29 @@ mlxcx_intr_setup(mlxcx_t *mlxp) eqt = MLXCX_EQ_TYPE_RX; } + while (mlxp->mlx_intr_pri >= DDI_INTR_PRI_MIN) { + ret = ddi_intr_set_pri(mlxp->mlx_intr_handles[i], + mlxp->mlx_intr_pri); + if (ret == DDI_SUCCESS) + break; + mlxcx_note(mlxp, "!Failed to set interrupt priority to " + "%u for interrupt vector %d", + mlxp->mlx_intr_pri, i); + mlxp->mlx_intr_pri--; + } + if (mlxp->mlx_intr_pri < DDI_INTR_PRI_MIN) { + mlxcx_warn(mlxp, + "Failed to find an interrupt priority for " + "interrupt vector %d", i); + mlxcx_intr_teardown(mlxp); + return (B_FALSE); + } + ret = ddi_intr_add_handler(mlxp->mlx_intr_handles[i], mlxcx_intr_n, (caddr_t)mlxp, (caddr_t)&mlxp->mlx_eqs[i]); if (ret != DDI_SUCCESS) { + mlxcx_warn(mlxp, "Failed to add interrupt handler %d", + i); mlxcx_intr_teardown(mlxp); return (B_FALSE); } diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_reg.h b/usr/src/uts/common/io/mlxcx/mlxcx_reg.h index 1987ae06ea..4b92de92b8 100644 --- a/usr/src/uts/common/io/mlxcx/mlxcx_reg.h +++ b/usr/src/uts/common/io/mlxcx/mlxcx_reg.h @@ -2530,6 +2530,30 @@ typedef struct { uint16be_t mlrd_pplm_fec_override_admin_fdr10; } mlxcx_reg_pplm_t; +typedef struct { + uint8_t mlrd_mtcap_rsvd[3]; + uint8_t mlrd_mtcap_sensor_count; + uint8_t mlrd_mtcap_rsvd1[4]; + uint64be_t mlrd_mtcap_sensor_map; +} mlxcx_reg_mtcap_t; + +#define MLXCX_MTMP_NAMELEN 8 + +typedef struct { + uint8_t mlrd_mtmp_rsvd[2]; + uint16be_t mlrd_mtmp_sensor_index; + uint8_t mlrd_mtmp_rsvd1[2]; + uint16be_t mlrd_mtmp_temperature; + bits16_t mlrd_mtmp_max_flags; + uint16be_t mlrd_mtmp_max_temperature; + bits16_t mlrd_mtmp_tee; + uint16be_t mlrd_mtmp_temp_thresh_hi; + uint8_t mlrd_mtmp_rsvd2[2]; + uint16be_t mlrd_mtmp_temp_thresh_lo; + uint8_t mlrd_mtmp_rsvd3[4]; + uint8_t mlrd_mtmp_name[MLXCX_MTMP_NAMELEN]; +} mlxcx_reg_mtmp_t; + typedef enum { MLXCX_REG_PMTU = 0x5003, MLXCX_REG_PTYS = 0x5004, @@ -2540,6 +2564,8 @@ typedef enum { MLXCX_REG_MCIA = 0x9014, MLXCX_REG_PPCNT = 0x5008, MLXCX_REG_PPLM = 0x5023, + MLXCX_REG_MTCAP = 0x9009, + MLXCX_REG_MTMP = 0x900A } mlxcx_register_id_t; typedef union { @@ -2551,6 +2577,8 @@ typedef union { mlxcx_reg_mcia_t mlrd_mcia; mlxcx_reg_ppcnt_t mlrd_ppcnt; mlxcx_reg_pplm_t mlrd_pplm; + mlxcx_reg_mtcap_t mlrd_mtcap; + mlxcx_reg_mtmp_t mlrd_mtmp; } mlxcx_register_data_t; typedef enum { diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_sensor.c b/usr/src/uts/common/io/mlxcx/mlxcx_sensor.c new file mode 100644 index 0000000000..6d2c7d0778 --- /dev/null +++ b/usr/src/uts/common/io/mlxcx/mlxcx_sensor.c @@ -0,0 +1,126 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +#include <mlxcx.h> +#include <sys/sensors.h> + +/* + * The PRM indicates that the temperature is measured in 1/8th degrees. + */ +#define MLXCX_TEMP_GRAN 8 + +/* + * Read a single temperature sensor entry. The ksensor framework guarantees that + * it will only call this once for a given sensor at any time, though multiple + * sensors can be in parallel. + */ +static int +mlxcx_temperature_read(void *arg, sensor_ioctl_scalar_t *scalar) +{ + boolean_t ok; + uint16_t tmp; + mlxcx_register_data_t data; + mlxcx_temp_sensor_t *sensor = arg; + mlxcx_t *mlxp = sensor->mlts_mlx; + + bzero(&data, sizeof (data)); + data.mlrd_mtmp.mlrd_mtmp_sensor_index = to_be16(sensor->mlts_index); + ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ, + MLXCX_REG_MTMP, &data); + if (!ok) { + return (EIO); + } + + tmp = from_be16(data.mlrd_mtmp.mlrd_mtmp_temperature); + sensor->mlts_value = (int16_t)tmp; + tmp = from_be16(data.mlrd_mtmp.mlrd_mtmp_max_temperature); + sensor->mlts_max_value = (int16_t)tmp; + bcopy(data.mlrd_mtmp.mlrd_mtmp_name, sensor->mlts_name, + sizeof (sensor->mlts_name)); + + scalar->sis_unit = SENSOR_UNIT_CELSIUS; + scalar->sis_gran = MLXCX_TEMP_GRAN; + scalar->sis_prec = 0; + scalar->sis_value = (int64_t)sensor->mlts_value; + + return (0); +} + +static const ksensor_ops_t mlxcx_temp_ops = { + .kso_kind = ksensor_kind_temperature, + .kso_scalar = mlxcx_temperature_read +}; + +void +mlxcx_teardown_sensors(mlxcx_t *mlxp) +{ + if (mlxp->mlx_temp_nsensors == 0) + return; + (void) ksensor_remove(mlxp->mlx_dip, KSENSOR_ALL_IDS); + kmem_free(mlxp->mlx_temp_sensors, sizeof (mlxcx_temp_sensor_t) * + mlxp->mlx_temp_nsensors); +} + +boolean_t +mlxcx_setup_sensors(mlxcx_t *mlxp) +{ + mlxcx_register_data_t data; + boolean_t ok; + + mlxp->mlx_temp_nsensors = 0; + bzero(&data, sizeof (data)); + ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ, + MLXCX_REG_MTCAP, &data); + if (!ok) { + return (B_FALSE); + } + + if (data.mlrd_mtcap.mlrd_mtcap_sensor_count == 0) { + return (B_TRUE); + } + + mlxp->mlx_temp_nsensors = data.mlrd_mtcap.mlrd_mtcap_sensor_count; + mlxp->mlx_temp_sensors = kmem_zalloc(sizeof (mlxcx_temp_sensor_t) * + mlxp->mlx_temp_nsensors, KM_SLEEP); + + for (uint8_t i = 0; i < mlxp->mlx_temp_nsensors; i++) { + char buf[32]; + int ret; + + if (snprintf(buf, sizeof (buf), "temp%u", i) >= sizeof (buf)) { + mlxcx_warn(mlxp, "sensor name %u would overflow " + "internal buffer"); + goto err; + } + + mlxp->mlx_temp_sensors[i].mlts_mlx = mlxp; + mlxp->mlx_temp_sensors[i].mlts_index = i; + + ret = ksensor_create_scalar_pcidev(mlxp->mlx_dip, + SENSOR_KIND_TEMPERATURE, &mlxcx_temp_ops, + &mlxp->mlx_temp_sensors[i], buf, + &mlxp->mlx_temp_sensors[i].mlts_ksensor); + if (ret != 0) { + mlxcx_warn(mlxp, "failed to create temp sensor %s: %d", + buf, ret); + goto err; + } + } + + return (B_TRUE); +err: + mlxcx_teardown_sensors(mlxp); + return (B_FALSE); +} |