xref: /dflybsd-src/sys/dev/misc/dimm/dimm.c (revision e30371b49539109267c23a480b6c765f029200db)
1881f7bffSSepherosa Ziehau /*
2881f7bffSSepherosa Ziehau  * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
3881f7bffSSepherosa Ziehau  *
4881f7bffSSepherosa Ziehau  * This code is derived from software contributed to The DragonFly Project
5881f7bffSSepherosa Ziehau  * by Sepherosa Ziehau <sepherosa@gmail.com>
6881f7bffSSepherosa Ziehau  *
7881f7bffSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
8881f7bffSSepherosa Ziehau  * modification, are permitted provided that the following conditions
9881f7bffSSepherosa Ziehau  * are met:
10881f7bffSSepherosa Ziehau  *
11881f7bffSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
12881f7bffSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
13881f7bffSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
14881f7bffSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in
15881f7bffSSepherosa Ziehau  *    the documentation and/or other materials provided with the
16881f7bffSSepherosa Ziehau  *    distribution.
17881f7bffSSepherosa Ziehau  * 3. Neither the name of The DragonFly Project nor the names of its
18881f7bffSSepherosa Ziehau  *    contributors may be used to endorse or promote products derived
19881f7bffSSepherosa Ziehau  *    from this software without specific, prior written permission.
20881f7bffSSepherosa Ziehau  *
21881f7bffSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22881f7bffSSepherosa Ziehau  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23881f7bffSSepherosa Ziehau  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24881f7bffSSepherosa Ziehau  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25881f7bffSSepherosa Ziehau  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26881f7bffSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27881f7bffSSepherosa Ziehau  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28881f7bffSSepherosa Ziehau  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29881f7bffSSepherosa Ziehau  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30881f7bffSSepherosa Ziehau  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31881f7bffSSepherosa Ziehau  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32881f7bffSSepherosa Ziehau  * SUCH DAMAGE.
33881f7bffSSepherosa Ziehau  */
34881f7bffSSepherosa Ziehau 
35881f7bffSSepherosa Ziehau #include <sys/param.h>
36881f7bffSSepherosa Ziehau #include <sys/bus.h>
37881f7bffSSepherosa Ziehau #include <sys/kernel.h>
38881f7bffSSepherosa Ziehau #include <sys/lock.h>
39881f7bffSSepherosa Ziehau #include <sys/malloc.h>
40881f7bffSSepherosa Ziehau #include <sys/module.h>
41881f7bffSSepherosa Ziehau #include <sys/sensors.h>
42881f7bffSSepherosa Ziehau #include <sys/sysctl.h>
43881f7bffSSepherosa Ziehau #include <sys/systm.h>
44881f7bffSSepherosa Ziehau 
45881f7bffSSepherosa Ziehau #include <dev/misc/dimm/dimm.h>
46881f7bffSSepherosa Ziehau 
47881f7bffSSepherosa Ziehau #define DIMM_TEMP_HIWAT_DEFAULT	85
48881f7bffSSepherosa Ziehau #define DIMM_TEMP_LOWAT_DEFAULT	75
49881f7bffSSepherosa Ziehau 
507ee0de79SSepherosa Ziehau #define DIMM_ECC_THRESH_DEFAULT	5
517ee0de79SSepherosa Ziehau 
52881f7bffSSepherosa Ziehau struct dimm_softc {
53881f7bffSSepherosa Ziehau 	TAILQ_ENTRY(dimm_softc) dimm_link;
54881f7bffSSepherosa Ziehau 	int			dimm_node;
55881f7bffSSepherosa Ziehau 	int			dimm_chan;
56881f7bffSSepherosa Ziehau 	int			dimm_slot;
57881f7bffSSepherosa Ziehau 	int			dimm_temp_hiwat;
58881f7bffSSepherosa Ziehau 	int			dimm_temp_lowat;
59881f7bffSSepherosa Ziehau 	int			dimm_id;
60881f7bffSSepherosa Ziehau 	int			dimm_ref;
6123832f75SSepherosa Ziehau 	int			dimm_ecc_cnt;
627ee0de79SSepherosa Ziehau 	int			dimm_ecc_thresh;
63881f7bffSSepherosa Ziehau 
64881f7bffSSepherosa Ziehau 	struct ksensordev	dimm_sensdev;
65881f7bffSSepherosa Ziehau 	uint32_t		dimm_sens_taskflags;	/* DIMM_SENS_TF_ */
66881f7bffSSepherosa Ziehau 
67881f7bffSSepherosa Ziehau 	struct sysctl_ctx_list	dimm_sysctl_ctx;
68881f7bffSSepherosa Ziehau 	struct sysctl_oid	*dimm_sysctl_tree;
69881f7bffSSepherosa Ziehau };
70881f7bffSSepherosa Ziehau TAILQ_HEAD(dimm_softc_list, dimm_softc);
71881f7bffSSepherosa Ziehau 
72881f7bffSSepherosa Ziehau #define DIMM_SENS_TF_TEMP_CRIT		0x1
7323832f75SSepherosa Ziehau #define DIMM_SENS_TF_ECC_CRIT		0x2
74881f7bffSSepherosa Ziehau 
75881f7bffSSepherosa Ziehau static void	dimm_mod_unload(void);
76*e30371b4SSepherosa Ziehau static void	dimm_sensor_ecc(struct dimm_softc *, struct ksensor *,
77*e30371b4SSepherosa Ziehau 		    boolean_t);
78881f7bffSSepherosa Ziehau 
79881f7bffSSepherosa Ziehau /* In the ascending order of dimm_softc.dimm_id */
80881f7bffSSepherosa Ziehau static struct dimm_softc_list	dimm_softc_list;
81881f7bffSSepherosa Ziehau 
82881f7bffSSepherosa Ziehau static SYSCTL_NODE(_hw, OID_AUTO, dimminfo, CTLFLAG_RD, NULL,
83881f7bffSSepherosa Ziehau     "DIMM information");
84881f7bffSSepherosa Ziehau 
85881f7bffSSepherosa Ziehau struct dimm_softc *
dimm_create(int node,int chan,int slot)86881f7bffSSepherosa Ziehau dimm_create(int node, int chan, int slot)
87881f7bffSSepherosa Ziehau {
88881f7bffSSepherosa Ziehau 	struct dimm_softc *sc, *after = NULL;
89881f7bffSSepherosa Ziehau 	int dimm_id = 0;
90881f7bffSSepherosa Ziehau 
91881f7bffSSepherosa Ziehau 	SYSCTL_XLOCK();
92881f7bffSSepherosa Ziehau 
93881f7bffSSepherosa Ziehau 	TAILQ_FOREACH(sc, &dimm_softc_list, dimm_link) {
94881f7bffSSepherosa Ziehau 		/*
95881f7bffSSepherosa Ziehau 		 * Already exists; done.
96881f7bffSSepherosa Ziehau 		 */
97881f7bffSSepherosa Ziehau 		if (sc->dimm_node == node && sc->dimm_chan == chan &&
98881f7bffSSepherosa Ziehau 		    sc->dimm_slot == slot) {
99881f7bffSSepherosa Ziehau 			KASSERT(sc->dimm_ref > 0, ("invalid dimm reference %d",
100881f7bffSSepherosa Ziehau 			    sc->dimm_ref));
101881f7bffSSepherosa Ziehau 			sc->dimm_ref++;
102881f7bffSSepherosa Ziehau 			SYSCTL_XUNLOCK();
103881f7bffSSepherosa Ziehau 			return sc;
104881f7bffSSepherosa Ziehau 		}
105881f7bffSSepherosa Ziehau 
106881f7bffSSepherosa Ziehau 		/*
107881f7bffSSepherosa Ziehau 		 * Find the lowest usable id.
108881f7bffSSepherosa Ziehau 		 */
109881f7bffSSepherosa Ziehau 		if (sc->dimm_id == dimm_id) {
110881f7bffSSepherosa Ziehau 			++dimm_id;
111881f7bffSSepherosa Ziehau 			after = sc;
112881f7bffSSepherosa Ziehau 		}
113881f7bffSSepherosa Ziehau 	}
114881f7bffSSepherosa Ziehau 
115881f7bffSSepherosa Ziehau 	sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
116881f7bffSSepherosa Ziehau 	sc->dimm_node = node;
117881f7bffSSepherosa Ziehau 	sc->dimm_chan = chan;
118881f7bffSSepherosa Ziehau 	sc->dimm_slot = slot;
119881f7bffSSepherosa Ziehau 	sc->dimm_id = dimm_id;
120881f7bffSSepherosa Ziehau 	sc->dimm_ref = 1;
121881f7bffSSepherosa Ziehau 	sc->dimm_temp_hiwat = DIMM_TEMP_HIWAT_DEFAULT;
122881f7bffSSepherosa Ziehau 	sc->dimm_temp_lowat = DIMM_TEMP_LOWAT_DEFAULT;
1237ee0de79SSepherosa Ziehau 	sc->dimm_ecc_thresh = DIMM_ECC_THRESH_DEFAULT;
124881f7bffSSepherosa Ziehau 
125881f7bffSSepherosa Ziehau 	ksnprintf(sc->dimm_sensdev.xname, sizeof(sc->dimm_sensdev.xname),
126881f7bffSSepherosa Ziehau 	    "dimm%d", sc->dimm_id);
127881f7bffSSepherosa Ziehau 
128881f7bffSSepherosa Ziehau 	/*
129881f7bffSSepherosa Ziehau 	 * Create sysctl tree for the location information.  Use
130881f7bffSSepherosa Ziehau 	 * same name as the sensor device.
131881f7bffSSepherosa Ziehau 	 */
132881f7bffSSepherosa Ziehau 	sysctl_ctx_init(&sc->dimm_sysctl_ctx);
133881f7bffSSepherosa Ziehau 	sc->dimm_sysctl_tree = SYSCTL_ADD_NODE(&sc->dimm_sysctl_ctx,
134881f7bffSSepherosa Ziehau 	    SYSCTL_STATIC_CHILDREN(_hw_dimminfo), OID_AUTO,
135881f7bffSSepherosa Ziehau 	    sc->dimm_sensdev.xname, CTLFLAG_RD, 0, "");
136881f7bffSSepherosa Ziehau 	if (sc->dimm_sysctl_tree != NULL) {
137881f7bffSSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
138881f7bffSSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
139881f7bffSSepherosa Ziehau 		    "node", CTLFLAG_RD, &sc->dimm_node, 0,
140881f7bffSSepherosa Ziehau 		    "CPU node of this DIMM");
141881f7bffSSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
142881f7bffSSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
143881f7bffSSepherosa Ziehau 		    "chan", CTLFLAG_RD, &sc->dimm_chan, 0,
144881f7bffSSepherosa Ziehau 		    "channel of this DIMM");
145881f7bffSSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
146881f7bffSSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
147881f7bffSSepherosa Ziehau 		    "slot", CTLFLAG_RD, &sc->dimm_slot, 0,
148881f7bffSSepherosa Ziehau 		    "slot of this DIMM");
149881f7bffSSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
150881f7bffSSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
151881f7bffSSepherosa Ziehau 		    "temp_hiwat", CTLFLAG_RW, &sc->dimm_temp_hiwat, 0,
152881f7bffSSepherosa Ziehau 		    "Raise alarm once DIMM temperature is above this value "
153881f7bffSSepherosa Ziehau 		    "(unit: C)");
154881f7bffSSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
155881f7bffSSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
156881f7bffSSepherosa Ziehau 		    "temp_lowat", CTLFLAG_RW, &sc->dimm_temp_lowat, 0,
157881f7bffSSepherosa Ziehau 		    "Cancel alarm once DIMM temperature is below this value "
158881f7bffSSepherosa Ziehau 		    "(unit: C)");
1597ee0de79SSepherosa Ziehau 		SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx,
1607ee0de79SSepherosa Ziehau 		    SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO,
1617ee0de79SSepherosa Ziehau 		    "ecc_thresh", CTLFLAG_RW, &sc->dimm_ecc_thresh, 0,
1627ee0de79SSepherosa Ziehau 		    "Raise alarm once number ECC errors go above this value");
163881f7bffSSepherosa Ziehau 	}
164881f7bffSSepherosa Ziehau 
165881f7bffSSepherosa Ziehau 	if (after == NULL) {
166881f7bffSSepherosa Ziehau 		KKASSERT(sc->dimm_id == 0);
167881f7bffSSepherosa Ziehau 		TAILQ_INSERT_HEAD(&dimm_softc_list, sc, dimm_link);
168881f7bffSSepherosa Ziehau 	} else {
169881f7bffSSepherosa Ziehau 		TAILQ_INSERT_AFTER(&dimm_softc_list, after, sc, dimm_link);
170881f7bffSSepherosa Ziehau 	}
171881f7bffSSepherosa Ziehau 
172881f7bffSSepherosa Ziehau 	sensordev_install(&sc->dimm_sensdev);
173881f7bffSSepherosa Ziehau 
174881f7bffSSepherosa Ziehau 	SYSCTL_XUNLOCK();
175881f7bffSSepherosa Ziehau 	return sc;
176881f7bffSSepherosa Ziehau }
177881f7bffSSepherosa Ziehau 
178881f7bffSSepherosa Ziehau int
dimm_destroy(struct dimm_softc * sc)179881f7bffSSepherosa Ziehau dimm_destroy(struct dimm_softc *sc)
180881f7bffSSepherosa Ziehau {
181881f7bffSSepherosa Ziehau 	SYSCTL_XLOCK();
182881f7bffSSepherosa Ziehau 
183881f7bffSSepherosa Ziehau 	KASSERT(sc->dimm_ref > 0, ("invalid dimm reference %d", sc->dimm_ref));
184881f7bffSSepherosa Ziehau 	sc->dimm_ref--;
185881f7bffSSepherosa Ziehau 	if (sc->dimm_ref > 0) {
186881f7bffSSepherosa Ziehau 		SYSCTL_XUNLOCK();
187881f7bffSSepherosa Ziehau 		return EAGAIN;
188881f7bffSSepherosa Ziehau 	}
189881f7bffSSepherosa Ziehau 
190881f7bffSSepherosa Ziehau 	sensordev_deinstall(&sc->dimm_sensdev);
191881f7bffSSepherosa Ziehau 
192881f7bffSSepherosa Ziehau 	TAILQ_REMOVE(&dimm_softc_list, sc, dimm_link);
193881f7bffSSepherosa Ziehau 	if (sc->dimm_sysctl_tree != NULL)
194881f7bffSSepherosa Ziehau 		sysctl_ctx_free(&sc->dimm_sysctl_ctx);
195881f7bffSSepherosa Ziehau 	kfree(sc, M_DEVBUF);
196881f7bffSSepherosa Ziehau 
197881f7bffSSepherosa Ziehau 	SYSCTL_XUNLOCK();
198881f7bffSSepherosa Ziehau 	return 0;
199881f7bffSSepherosa Ziehau }
200881f7bffSSepherosa Ziehau 
201881f7bffSSepherosa Ziehau void
dimm_sensor_attach(struct dimm_softc * sc,struct ksensor * sens)202881f7bffSSepherosa Ziehau dimm_sensor_attach(struct dimm_softc *sc, struct ksensor *sens)
203881f7bffSSepherosa Ziehau {
204881f7bffSSepherosa Ziehau 	sensor_attach(&sc->dimm_sensdev, sens);
205881f7bffSSepherosa Ziehau }
206881f7bffSSepherosa Ziehau 
207881f7bffSSepherosa Ziehau void
dimm_sensor_detach(struct dimm_softc * sc,struct ksensor * sens)208881f7bffSSepherosa Ziehau dimm_sensor_detach(struct dimm_softc *sc, struct ksensor *sens)
209881f7bffSSepherosa Ziehau {
210881f7bffSSepherosa Ziehau 	sensor_detach(&sc->dimm_sensdev, sens);
211881f7bffSSepherosa Ziehau }
212881f7bffSSepherosa Ziehau 
213881f7bffSSepherosa Ziehau void
dimm_set_temp_thresh(struct dimm_softc * sc,int hiwat,int lowat)214881f7bffSSepherosa Ziehau dimm_set_temp_thresh(struct dimm_softc *sc, int hiwat, int lowat)
215881f7bffSSepherosa Ziehau {
216881f7bffSSepherosa Ziehau 	sc->dimm_temp_hiwat = hiwat;
217881f7bffSSepherosa Ziehau 	sc->dimm_temp_lowat = lowat;
218881f7bffSSepherosa Ziehau }
219881f7bffSSepherosa Ziehau 
220881f7bffSSepherosa Ziehau void
dimm_set_ecc_thresh(struct dimm_softc * sc,int thresh)2217ee0de79SSepherosa Ziehau dimm_set_ecc_thresh(struct dimm_softc *sc, int thresh)
2227ee0de79SSepherosa Ziehau {
2237ee0de79SSepherosa Ziehau 	sc->dimm_ecc_thresh = thresh;
2247ee0de79SSepherosa Ziehau }
2257ee0de79SSepherosa Ziehau 
2267ee0de79SSepherosa Ziehau void
dimm_sensor_temp(struct dimm_softc * sc,struct ksensor * sens,int temp)227881f7bffSSepherosa Ziehau dimm_sensor_temp(struct dimm_softc *sc, struct ksensor *sens, int temp)
228881f7bffSSepherosa Ziehau {
2297273d7b8SSepherosa Ziehau 	enum sensor_status status;
2307273d7b8SSepherosa Ziehau 
231881f7bffSSepherosa Ziehau 	if (temp >= sc->dimm_temp_hiwat &&
232881f7bffSSepherosa Ziehau 	    (sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT) == 0) {
233881f7bffSSepherosa Ziehau 		char temp_str[16], data[64];
234881f7bffSSepherosa Ziehau 
235881f7bffSSepherosa Ziehau 		ksnprintf(temp_str, sizeof(temp_str), "%d", temp);
236881f7bffSSepherosa Ziehau 		ksnprintf(data, sizeof(data), "node=%d channel=%d dimm=%d",
237881f7bffSSepherosa Ziehau 		    sc->dimm_node, sc->dimm_chan, sc->dimm_slot);
238881f7bffSSepherosa Ziehau 		devctl_notify("memtemp", "Thermal", temp_str, data);
239881f7bffSSepherosa Ziehau 
240881f7bffSSepherosa Ziehau 		kprintf("dimm%d: node%d channel%d DIMM%d "
241881f7bffSSepherosa Ziehau 		    "temperature (%dC) is too high (>= %dC)\n",
242881f7bffSSepherosa Ziehau 		    sc->dimm_id, sc->dimm_node, sc->dimm_chan, sc->dimm_slot,
243881f7bffSSepherosa Ziehau 		    temp, sc->dimm_temp_hiwat);
244881f7bffSSepherosa Ziehau 
245881f7bffSSepherosa Ziehau 		sc->dimm_sens_taskflags |= DIMM_SENS_TF_TEMP_CRIT;
246881f7bffSSepherosa Ziehau 	} else if ((sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT) &&
247881f7bffSSepherosa Ziehau 	     temp < sc->dimm_temp_lowat) {
248881f7bffSSepherosa Ziehau 		sc->dimm_sens_taskflags &= ~DIMM_SENS_TF_TEMP_CRIT;
249881f7bffSSepherosa Ziehau 	}
250881f7bffSSepherosa Ziehau 
251881f7bffSSepherosa Ziehau 	if (sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT)
2527273d7b8SSepherosa Ziehau 		status = SENSOR_S_CRIT;
253881f7bffSSepherosa Ziehau 	else
2547273d7b8SSepherosa Ziehau 		status = SENSOR_S_OK;
2557273d7b8SSepherosa Ziehau 	sensor_set_temp_degc(sens, temp, status);
256881f7bffSSepherosa Ziehau }
257881f7bffSSepherosa Ziehau 
25823832f75SSepherosa Ziehau void
dimm_sensor_ecc_set(struct dimm_softc * sc,struct ksensor * sens,int ecc_cnt,boolean_t crit)25923832f75SSepherosa Ziehau dimm_sensor_ecc_set(struct dimm_softc *sc, struct ksensor *sens,
26023832f75SSepherosa Ziehau     int ecc_cnt, boolean_t crit)
26123832f75SSepherosa Ziehau {
2627273d7b8SSepherosa Ziehau 	sc->dimm_ecc_cnt = ecc_cnt;
263*e30371b4SSepherosa Ziehau 	dimm_sensor_ecc(sc, sens, crit);
264*e30371b4SSepherosa Ziehau }
265*e30371b4SSepherosa Ziehau 
266*e30371b4SSepherosa Ziehau void
dimm_sensor_ecc_add(struct dimm_softc * sc,struct ksensor * sens,int ecc_cnt,boolean_t crit)267*e30371b4SSepherosa Ziehau dimm_sensor_ecc_add(struct dimm_softc *sc, struct ksensor *sens,
268*e30371b4SSepherosa Ziehau     int ecc_cnt, boolean_t crit)
269*e30371b4SSepherosa Ziehau {
270*e30371b4SSepherosa Ziehau 	sc->dimm_ecc_cnt += ecc_cnt;
271*e30371b4SSepherosa Ziehau 	dimm_sensor_ecc(sc, sens, crit);
272*e30371b4SSepherosa Ziehau }
273*e30371b4SSepherosa Ziehau 
274*e30371b4SSepherosa Ziehau static void
dimm_sensor_ecc(struct dimm_softc * sc,struct ksensor * sens,boolean_t crit)275*e30371b4SSepherosa Ziehau dimm_sensor_ecc(struct dimm_softc *sc, struct ksensor *sens, boolean_t crit)
276*e30371b4SSepherosa Ziehau {
277*e30371b4SSepherosa Ziehau 	enum sensor_status status;
2787ee0de79SSepherosa Ziehau 
2797ee0de79SSepherosa Ziehau 	if (!crit && sc->dimm_ecc_cnt >= sc->dimm_ecc_thresh)
2807ee0de79SSepherosa Ziehau 		crit = TRUE;
2817ee0de79SSepherosa Ziehau 
28223832f75SSepherosa Ziehau 	if (crit && (sc->dimm_sens_taskflags & DIMM_SENS_TF_ECC_CRIT) == 0) {
283ca981007SSepherosa Ziehau 		char ecc_str[16], data[64];
284ca981007SSepherosa Ziehau 
285ca981007SSepherosa Ziehau 		ksnprintf(ecc_str, sizeof(ecc_str), "%d", sc->dimm_ecc_cnt);
286ca981007SSepherosa Ziehau 		ksnprintf(data, sizeof(data), "node=%d channel=%d dimm=%d",
287ca981007SSepherosa Ziehau 		    sc->dimm_node, sc->dimm_chan, sc->dimm_slot);
288ca981007SSepherosa Ziehau 		devctl_notify("ecc", "ECC", ecc_str, data);
289ca981007SSepherosa Ziehau 
290ca981007SSepherosa Ziehau 		kprintf("dimm%d: node%d channel%d DIMM%d "
291ca981007SSepherosa Ziehau 		    "too many ECC errors %d\n",
292ca981007SSepherosa Ziehau 		    sc->dimm_id, sc->dimm_node, sc->dimm_chan, sc->dimm_slot,
293ca981007SSepherosa Ziehau 		    sc->dimm_ecc_cnt);
294ca981007SSepherosa Ziehau 
29523832f75SSepherosa Ziehau 		sc->dimm_sens_taskflags |= DIMM_SENS_TF_ECC_CRIT;
29623832f75SSepherosa Ziehau 	}
29723832f75SSepherosa Ziehau 
29823832f75SSepherosa Ziehau 	if (sc->dimm_sens_taskflags & DIMM_SENS_TF_ECC_CRIT)
2997273d7b8SSepherosa Ziehau 		status = SENSOR_S_CRIT;
30023832f75SSepherosa Ziehau 	else
3017273d7b8SSepherosa Ziehau 		status = SENSOR_S_OK;
3027273d7b8SSepherosa Ziehau 	sensor_set(sens, sc->dimm_ecc_cnt, status);
30323832f75SSepherosa Ziehau }
30423832f75SSepherosa Ziehau 
305881f7bffSSepherosa Ziehau static void
dimm_mod_unload(void)306881f7bffSSepherosa Ziehau dimm_mod_unload(void)
307881f7bffSSepherosa Ziehau {
308881f7bffSSepherosa Ziehau 	struct dimm_softc *sc;
309881f7bffSSepherosa Ziehau 
310881f7bffSSepherosa Ziehau 	SYSCTL_XLOCK();
311881f7bffSSepherosa Ziehau 
312881f7bffSSepherosa Ziehau 	while ((sc = TAILQ_FIRST(&dimm_softc_list)) != NULL) {
313881f7bffSSepherosa Ziehau 		int error;
314881f7bffSSepherosa Ziehau 
315881f7bffSSepherosa Ziehau 		error = dimm_destroy(sc);
316881f7bffSSepherosa Ziehau 		KASSERT(!error, ("dimm%d is still referenced, ref %d",
317881f7bffSSepherosa Ziehau 		    sc->dimm_id, sc->dimm_ref));
318881f7bffSSepherosa Ziehau 	}
319881f7bffSSepherosa Ziehau 
320881f7bffSSepherosa Ziehau 	SYSCTL_XUNLOCK();
321881f7bffSSepherosa Ziehau }
322881f7bffSSepherosa Ziehau 
323881f7bffSSepherosa Ziehau static int
dimm_mod_event(module_t mod,int type,void * unused)324881f7bffSSepherosa Ziehau dimm_mod_event(module_t mod, int type, void *unused)
325881f7bffSSepherosa Ziehau {
326881f7bffSSepherosa Ziehau 	switch (type) {
327881f7bffSSepherosa Ziehau 	case MOD_LOAD:
328881f7bffSSepherosa Ziehau 		TAILQ_INIT(&dimm_softc_list);
329881f7bffSSepherosa Ziehau 		return 0;
330881f7bffSSepherosa Ziehau 
331881f7bffSSepherosa Ziehau 	case MOD_UNLOAD:
332881f7bffSSepherosa Ziehau 		dimm_mod_unload();
333881f7bffSSepherosa Ziehau 		return 0;
334881f7bffSSepherosa Ziehau 
335881f7bffSSepherosa Ziehau 	default:
336881f7bffSSepherosa Ziehau 		return 0;
337881f7bffSSepherosa Ziehau 	}
338881f7bffSSepherosa Ziehau }
339881f7bffSSepherosa Ziehau 
340881f7bffSSepherosa Ziehau static moduledata_t dimm_mod = {
341881f7bffSSepherosa Ziehau 	"dimm",
342881f7bffSSepherosa Ziehau 	dimm_mod_event,
343881f7bffSSepherosa Ziehau 	0
344881f7bffSSepherosa Ziehau };
345881f7bffSSepherosa Ziehau DECLARE_MODULE(dimm, dimm_mod, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY);
346881f7bffSSepherosa Ziehau MODULE_VERSION(dimm, 1);
347