| @@ -1,723 +1,737 @@ | | | @@ -1,723 +1,737 @@ |
1 | /* $NetBSD: spdmem.c,v 1.2 2010/06/29 04:42:30 pgoyette Exp $ */ | | 1 | /* $NetBSD: spdmem.c,v 1.3 2011/08/01 03:49:52 pgoyette Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2007 Nicolas Joly | | 4 | * Copyright (c) 2007 Nicolas Joly |
5 | * Copyright (c) 2007 Paul Goyette | | 5 | * Copyright (c) 2007 Paul Goyette |
6 | * Copyright (c) 2007 Tobias Nygren | | 6 | * Copyright (c) 2007 Tobias Nygren |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. The name of the author may not be used to endorse or promote products | | 17 | * 3. The name of the author may not be used to endorse or promote products |
18 | * derived from this software without specific prior written permission. | | 18 | * derived from this software without specific prior written permission. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Serial Presence Detect (SPD) memory identification | | 34 | * Serial Presence Detect (SPD) memory identification |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.2 2010/06/29 04:42:30 pgoyette Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: spdmem.c,v 1.3 2011/08/01 03:49:52 pgoyette Exp $"); |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/device.h> | | 41 | #include <sys/device.h> |
42 | #include <sys/endian.h> | | 42 | #include <sys/endian.h> |
43 | #include <sys/sysctl.h> | | 43 | #include <sys/sysctl.h> |
44 | #include <machine/bswap.h> | | 44 | #include <machine/bswap.h> |
45 | | | 45 | |
46 | #include <dev/i2c/i2cvar.h> | | 46 | #include <dev/i2c/i2cvar.h> |
47 | #include <dev/ic/spdmemreg.h> | | 47 | #include <dev/ic/spdmemreg.h> |
48 | #include <dev/ic/spdmemvar.h> | | 48 | #include <dev/ic/spdmemvar.h> |
49 | | | 49 | |
50 | SYSCTL_SETUP_PROTO(sysctl_spdmem_setup); | | 50 | SYSCTL_SETUP_PROTO(sysctl_spdmem_setup); |
51 | | | 51 | |
52 | /* Routines for decoding spd data */ | | 52 | /* Routines for decoding spd data */ |
53 | static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *); | | 53 | static void decode_edofpm(const struct sysctlnode *, device_t, struct spdmem *); |
54 | static void decode_rom(const struct sysctlnode *, device_t, struct spdmem *); | | 54 | static void decode_rom(const struct sysctlnode *, device_t, struct spdmem *); |
55 | static void decode_sdram(const struct sysctlnode *, device_t, struct spdmem *, | | 55 | static void decode_sdram(const struct sysctlnode *, device_t, struct spdmem *, |
56 | int); | | 56 | int); |
57 | static void decode_ddr(const struct sysctlnode *, device_t, struct spdmem *); | | 57 | static void decode_ddr(const struct sysctlnode *, device_t, struct spdmem *); |
58 | static void decode_ddr2(const struct sysctlnode *, device_t, struct spdmem *); | | 58 | static void decode_ddr2(const struct sysctlnode *, device_t, struct spdmem *); |
59 | static void decode_ddr3(const struct sysctlnode *, device_t, struct spdmem *); | | 59 | static void decode_ddr3(const struct sysctlnode *, device_t, struct spdmem *); |
60 | static void decode_fbdimm(const struct sysctlnode *, device_t, struct spdmem *); | | 60 | static void decode_fbdimm(const struct sysctlnode *, device_t, struct spdmem *); |
61 | | | 61 | |
62 | static void decode_size_speed(const struct sysctlnode *, int, int, int, int, | | 62 | static void decode_size_speed(device_t, const struct sysctlnode *, |
63 | bool, const char *, int); | | 63 | int, int, int, int, bool, const char *, int); |
64 | static void decode_voltage_refresh(device_t, struct spdmem *); | | 64 | static void decode_voltage_refresh(device_t, struct spdmem *); |
65 | | | 65 | |
66 | #define IS_RAMBUS_TYPE (s->sm_len < 4) | | 66 | #define IS_RAMBUS_TYPE (s->sm_len < 4) |
67 | | | 67 | |
68 | static const char* spdmem_basic_types[] = { | | 68 | static const char* spdmem_basic_types[] = { |
69 | "unknown", | | 69 | "unknown", |
70 | "FPM", | | 70 | "FPM", |
71 | "EDO", | | 71 | "EDO", |
72 | "Pipelined Nibble", | | 72 | "Pipelined Nibble", |
73 | "SDRAM", | | 73 | "SDRAM", |
74 | "ROM", | | 74 | "ROM", |
75 | "DDR SGRAM", | | 75 | "DDR SGRAM", |
76 | "DDR SDRAM", | | 76 | "DDR SDRAM", |
77 | "DDR2 SDRAM", | | 77 | "DDR2 SDRAM", |
78 | "DDR2 SDRAM FB", | | 78 | "DDR2 SDRAM FB", |
79 | "DDR2 SDRAM FB Probe", | | 79 | "DDR2 SDRAM FB Probe", |
80 | "DDR3 SDRAM" | | 80 | "DDR3 SDRAM" |
81 | }; | | 81 | }; |
82 | | | 82 | |
83 | static const char* spdmem_superset_types[] = { | | 83 | static const char* spdmem_superset_types[] = { |
84 | "unknown", | | 84 | "unknown", |
85 | "ESDRAM", | | 85 | "ESDRAM", |
86 | "DDR ESDRAM", | | 86 | "DDR ESDRAM", |
87 | "PEM EDO", | | 87 | "PEM EDO", |
88 | "PEM SDRAM" | | 88 | "PEM SDRAM" |
89 | }; | | 89 | }; |
90 | | | 90 | |
91 | static const char* spdmem_voltage_types[] = { | | 91 | static const char* spdmem_voltage_types[] = { |
92 | "TTL (5V tolerant)", | | 92 | "TTL (5V tolerant)", |
93 | "LvTTL (not 5V tolerant)", | | 93 | "LvTTL (not 5V tolerant)", |
94 | "HSTL 1.5V", | | 94 | "HSTL 1.5V", |
95 | "SSTL 3.3V", | | 95 | "SSTL 3.3V", |
96 | "SSTL 2.5V", | | 96 | "SSTL 2.5V", |
97 | "SSTL 1.8V" | | 97 | "SSTL 1.8V" |
98 | }; | | 98 | }; |
99 | | | 99 | |
100 | static const char* spdmem_refresh_types[] = { | | 100 | static const char* spdmem_refresh_types[] = { |
101 | "15.625us", | | 101 | "15.625us", |
102 | "3.9us", | | 102 | "3.9us", |
103 | "7.8us", | | 103 | "7.8us", |
104 | "31.3us", | | 104 | "31.3us", |
105 | "62.5us", | | 105 | "62.5us", |
106 | "125us" | | 106 | "125us" |
107 | }; | | 107 | }; |
108 | | | 108 | |
109 | static const char* spdmem_parity_types[] = { | | 109 | static const char* spdmem_parity_types[] = { |
110 | "no parity or ECC", | | 110 | "no parity or ECC", |
111 | "data parity", | | 111 | "data parity", |
112 | "data ECC", | | 112 | "data ECC", |
113 | "data parity and ECC", | | 113 | "data parity and ECC", |
114 | "cmd/addr parity", | | 114 | "cmd/addr parity", |
115 | "cmd/addr/data parity", | | 115 | "cmd/addr/data parity", |
116 | "cmd/addr parity, data ECC", | | 116 | "cmd/addr parity, data ECC", |
117 | "cmd/addr/data parity, data ECC" | | 117 | "cmd/addr/data parity, data ECC" |
118 | }; | | 118 | }; |
119 | | | 119 | |
120 | /* Cycle time fractional values (units of .001 ns) for DDR2 SDRAM */ | | 120 | /* Cycle time fractional values (units of .001 ns) for DDR2 SDRAM */ |
121 | static const uint16_t spdmem_cycle_frac[] = { | | 121 | static const uint16_t spdmem_cycle_frac[] = { |
122 | 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, | | 122 | 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, |
123 | 250, 333, 667, 750, 999, 999 | | 123 | 250, 333, 667, 750, 999, 999 |
124 | }; | | 124 | }; |
125 | | | 125 | |
126 | /* Format string for timing info */ | | 126 | /* Format string for timing info */ |
127 | static const char* latency="tAA-tRCD-tRP-tRAS: %d-%d-%d-%d\n"; | | 127 | static const char* latency="tAA-tRCD-tRP-tRAS: %d-%d-%d-%d\n"; |
128 | | | 128 | |
129 | /* sysctl stuff */ | | 129 | /* sysctl stuff */ |
130 | static int hw_node = CTL_EOL; | | 130 | static int hw_node = CTL_EOL; |
131 | | | 131 | |
132 | /* CRC functions used for certain memory types */ | | 132 | /* CRC functions used for certain memory types */ |
133 | | | 133 | |
134 | static uint16_t spdcrc16 (struct spdmem_softc *sc, int count) | | 134 | static uint16_t spdcrc16 (struct spdmem_softc *sc, int count) |
135 | { | | 135 | { |
136 | uint16_t crc; | | 136 | uint16_t crc; |
137 | int i, j; | | 137 | int i, j; |
138 | uint8_t val; | | 138 | uint8_t val; |
139 | crc = 0; | | 139 | crc = 0; |
140 | for (j = 0; j <= count; j++) { | | 140 | for (j = 0; j <= count; j++) { |
141 | val = (sc->sc_read)(sc, j); | | 141 | val = (sc->sc_read)(sc, j); |
142 | crc = crc ^ val << 8; | | 142 | crc = crc ^ val << 8; |
143 | for (i = 0; i < 8; ++i) | | 143 | for (i = 0; i < 8; ++i) |
144 | if (crc & 0x8000) | | 144 | if (crc & 0x8000) |
145 | crc = crc << 1 ^ 0x1021; | | 145 | crc = crc << 1 ^ 0x1021; |
146 | else | | 146 | else |
147 | crc = crc << 1; | | 147 | crc = crc << 1; |
148 | } | | 148 | } |
149 | return (crc & 0xFFFF); | | 149 | return (crc & 0xFFFF); |
150 | } | | 150 | } |
151 | | | 151 | |
152 | int | | 152 | int |
153 | spdmem_common_probe(struct spdmem_softc *sc) | | 153 | spdmem_common_probe(struct spdmem_softc *sc) |
154 | { | | 154 | { |
155 | int cksum = 0; | | 155 | int cksum = 0; |
156 | uint8_t i, val, spd_type; | | 156 | uint8_t i, val, spd_type; |
157 | int spd_len, spd_crc_cover; | | 157 | int spd_len, spd_crc_cover; |
158 | uint16_t crc_calc, crc_spd; | | 158 | uint16_t crc_calc, crc_spd; |
159 | | | 159 | |
160 | spd_type = (sc->sc_read)(sc, 2); | | 160 | spd_type = (sc->sc_read)(sc, 2); |
161 | | | 161 | |
162 | /* For older memory types, validate the checksum over 1st 63 bytes */ | | 162 | /* For older memory types, validate the checksum over 1st 63 bytes */ |
163 | if (spd_type <= SPDMEM_MEMTYPE_DDR2SDRAM) { | | 163 | if (spd_type <= SPDMEM_MEMTYPE_DDR2SDRAM) { |
164 | for (i = 0; i < 63; i++) | | 164 | for (i = 0; i < 63; i++) |
165 | cksum += (sc->sc_read)(sc, i); | | 165 | cksum += (sc->sc_read)(sc, i); |
166 | | | 166 | |
167 | val = (sc->sc_read)(sc, 63); | | 167 | val = (sc->sc_read)(sc, 63); |
168 | | | 168 | |
169 | if (cksum == 0 || (cksum & 0xff) != val) { | | 169 | if (cksum == 0 || (cksum & 0xff) != val) { |
170 | aprint_debug("spd checksum failed, calc = 0x%02x, " | | 170 | aprint_debug("spd checksum failed, calc = 0x%02x, " |
171 | "spd = 0x%02x\n", cksum, val); | | 171 | "spd = 0x%02x\n", cksum, val); |
172 | return 0; | | 172 | return 0; |
173 | } else | | 173 | } else |
174 | return 1; | | 174 | return 1; |
175 | } | | 175 | } |
176 | | | 176 | |
177 | /* For DDR3 and FBDIMM, verify the CRC */ | | 177 | /* For DDR3 and FBDIMM, verify the CRC */ |
178 | else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) { | | 178 | else if (spd_type <= SPDMEM_MEMTYPE_DDR3SDRAM) { |
179 | spd_len = (sc->sc_read)(sc, 0); | | 179 | spd_len = (sc->sc_read)(sc, 0); |
180 | if (spd_len & SPDMEM_SPDCRC_116) | | 180 | if (spd_len & SPDMEM_SPDCRC_116) |
181 | spd_crc_cover = 116; | | 181 | spd_crc_cover = 116; |
182 | else | | 182 | else |
183 | spd_crc_cover = 125; | | 183 | spd_crc_cover = 125; |
184 | switch (spd_len & SPDMEM_SPDLEN_MASK) { | | 184 | switch (spd_len & SPDMEM_SPDLEN_MASK) { |
185 | case SPDMEM_SPDLEN_128: | | 185 | case SPDMEM_SPDLEN_128: |
186 | spd_len = 128; | | 186 | spd_len = 128; |
187 | break; | | 187 | break; |
188 | case SPDMEM_SPDLEN_176: | | 188 | case SPDMEM_SPDLEN_176: |
189 | spd_len = 176; | | 189 | spd_len = 176; |
190 | break; | | 190 | break; |
191 | case SPDMEM_SPDLEN_256: | | 191 | case SPDMEM_SPDLEN_256: |
192 | spd_len = 256; | | 192 | spd_len = 256; |
193 | break; | | 193 | break; |
194 | default: | | 194 | default: |
195 | return 0; | | 195 | return 0; |
196 | } | | 196 | } |
197 | if (spd_crc_cover > spd_len) | | 197 | if (spd_crc_cover > spd_len) |
198 | return 0; | | 198 | return 0; |
199 | crc_calc = spdcrc16(sc, spd_crc_cover); | | 199 | crc_calc = spdcrc16(sc, spd_crc_cover); |
200 | crc_spd = (sc->sc_read)(sc, 127) << 8; | | 200 | crc_spd = (sc->sc_read)(sc, 127) << 8; |
201 | crc_spd |= (sc->sc_read)(sc, 126); | | 201 | crc_spd |= (sc->sc_read)(sc, 126); |
202 | if (crc_calc != crc_spd) { | | 202 | if (crc_calc != crc_spd) { |
203 | aprint_debug("crc16 failed, covers %d bytes, " | | 203 | aprint_debug("crc16 failed, covers %d bytes, " |
204 | "calc = 0x%04x, spd = 0x%04x\n", | | 204 | "calc = 0x%04x, spd = 0x%04x\n", |
205 | spd_crc_cover, crc_calc, crc_spd); | | 205 | spd_crc_cover, crc_calc, crc_spd); |
206 | return 0; | | 206 | return 0; |
207 | } | | 207 | } |
208 | return 1; | | 208 | return 1; |
209 | } | | 209 | } |
210 | | | 210 | |
211 | /* For unrecognized memory types, don't match at all */ | | 211 | /* For unrecognized memory types, don't match at all */ |
212 | return 0; | | 212 | return 0; |
213 | } | | 213 | } |
214 | | | 214 | |
215 | void | | 215 | void |
216 | spdmem_common_attach(struct spdmem_softc *sc, device_t self) | | 216 | spdmem_common_attach(struct spdmem_softc *sc, device_t self) |
217 | { | | 217 | { |
218 | struct spdmem *s = &(sc->sc_spd_data); | | 218 | struct spdmem *s = &(sc->sc_spd_data); |
219 | const char *type; | | 219 | const char *type; |
220 | const char *rambus_rev = "Reserved"; | | 220 | const char *rambus_rev = "Reserved"; |
221 | int dimm_size; | | 221 | int dimm_size; |
222 | int i; | | 222 | unsigned int i, spd_len, spd_size; |
223 | unsigned int spd_len, spd_size; | | | |
224 | const struct sysctlnode *node = NULL; | | 223 | const struct sysctlnode *node = NULL; |
225 | | | 224 | |
226 | /* | | 225 | /* |
227 | * FBDIMM and DDR3 (and probably all newer) have a different | | 226 | * FBDIMM and DDR3 (and probably all newer) have a different |
228 | * encoding of the SPD EEPROM used/total sizes | | 227 | * encoding of the SPD EEPROM used/total sizes |
229 | */ | | 228 | */ |
230 | s->sm_len = (sc->sc_read)(sc, 0); | | 229 | s->sm_len = (sc->sc_read)(sc, 0); |
231 | s->sm_size = (sc->sc_read)(sc, 1); | | 230 | s->sm_size = (sc->sc_read)(sc, 1); |
232 | s->sm_type = (sc->sc_read)(sc, 2); | | 231 | s->sm_type = (sc->sc_read)(sc, 2); |
233 | | | 232 | |
234 | if (s->sm_type >= SPDMEM_MEMTYPE_FBDIMM) { | | 233 | if (s->sm_type >= SPDMEM_MEMTYPE_FBDIMM) { |
235 | spd_size = 64 << (s->sm_len & SPDMEM_SPDSIZE_MASK); | | 234 | spd_size = 64 << (s->sm_len & SPDMEM_SPDSIZE_MASK); |
236 | switch (s->sm_len & SPDMEM_SPDLEN_MASK) { | | 235 | switch (s->sm_len & SPDMEM_SPDLEN_MASK) { |
237 | case SPDMEM_SPDLEN_128: | | 236 | case SPDMEM_SPDLEN_128: |
238 | spd_len = 128; | | 237 | spd_len = 128; |
239 | break; | | 238 | break; |
240 | case SPDMEM_SPDLEN_176: | | 239 | case SPDMEM_SPDLEN_176: |
241 | spd_len = 176; | | 240 | spd_len = 176; |
242 | break; | | 241 | break; |
243 | case SPDMEM_SPDLEN_256: | | 242 | case SPDMEM_SPDLEN_256: |
244 | spd_len = 256; | | 243 | spd_len = 256; |
245 | break; | | 244 | break; |
246 | default: | | 245 | default: |
247 | spd_len = 64; | | 246 | spd_len = 64; |
248 | break; | | 247 | break; |
249 | } | | 248 | } |
250 | } else { | | 249 | } else { |
251 | spd_size = 1 << s->sm_size; | | 250 | spd_size = 1 << s->sm_size; |
252 | spd_len = s->sm_len; | | 251 | spd_len = s->sm_len; |
253 | if (spd_len < 64) | | 252 | if (spd_len < 64) |
254 | spd_len = 64; | | 253 | spd_len = 64; |
255 | } | | 254 | } |
256 | if (spd_len > spd_size) | | 255 | if (spd_len > spd_size) |
257 | spd_len = spd_size; | | 256 | spd_len = spd_size; |
258 | if (spd_len > sizeof(struct spdmem)) | | 257 | if (spd_len > sizeof(struct spdmem)) |
259 | spd_len = sizeof(struct spdmem); | | 258 | spd_len = sizeof(struct spdmem); |
260 | for (i = 3; i < spd_len; i++) | | 259 | for (i = 3; i < spd_len; i++) |
261 | ((uint8_t *)s)[i] = (sc->sc_read)(sc, i); | | 260 | ((uint8_t *)s)[i] = (sc->sc_read)(sc, i); |
262 | | | 261 | |
263 | #ifdef DEBUG | | 262 | #ifdef DEBUG |
264 | for (i = 0; i < spd_len; i += 16) { | | 263 | for (i = 0; i < spd_len; i += 16) { |
265 | int j, k; | | 264 | unsigned int j, k; |
266 | aprint_debug("\n"); | | 265 | aprint_debug("\n"); |
267 | aprint_debug_dev(self, "0x%02x:", i); | | 266 | aprint_debug_dev(self, "0x%02x:", i); |
268 | k = (spd_len > i + 16) ? spd_len : i + 16; | | 267 | k = (spd_len > i + 16) ? spd_len : i + 16; |
269 | for (j = i; j < k; j++) | | 268 | for (j = i; j < k; j++) |
270 | aprint_debug(" %02x", ((uint8_t *)s)[j]); | | 269 | aprint_debug(" %02x", ((uint8_t *)s)[j]); |
271 | } | | 270 | } |
272 | aprint_debug("\n"); | | 271 | aprint_debug("\n"); |
273 | aprint_debug_dev(self, ""); | | 272 | aprint_debug_dev(self, ""); |
274 | #endif | | 273 | #endif |
275 | | | 274 | |
276 | /* | | 275 | /* |
277 | * Setup our sysctl subtree, hw.spdmemN | | 276 | * Setup our sysctl subtree, hw.spdmemN |
278 | */ | | 277 | */ |
| | | 278 | sc->sc_sysctl_log = NULL; |
| | | 279 | #ifdef _MODULE |
| | | 280 | sysctl_spdmem_setup(&sc->sc_sysctl_log); |
| | | 281 | #endif |
279 | if (hw_node != CTL_EOL) | | 282 | if (hw_node != CTL_EOL) |
280 | sysctl_createv(NULL, 0, NULL, &node, | | 283 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &node, |
281 | 0, CTLTYPE_NODE, | | 284 | 0, CTLTYPE_NODE, |
282 | device_xname(self), NULL, NULL, 0, NULL, 0, | | 285 | device_xname(self), NULL, NULL, 0, NULL, 0, |
283 | CTL_HW, CTL_CREATE, CTL_EOL); | | 286 | CTL_HW, CTL_CREATE, CTL_EOL); |
284 | if (node != NULL && spd_len != 0) | | 287 | if (node != NULL && spd_len != 0) |
285 | sysctl_createv(NULL, 0, NULL, NULL, | | 288 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
286 | 0, | | 289 | 0, |
287 | CTLTYPE_STRUCT, "spd_data", | | 290 | CTLTYPE_STRUCT, "spd_data", |
288 | SYSCTL_DESCR("raw spd data"), NULL, | | 291 | SYSCTL_DESCR("raw spd data"), NULL, |
289 | 0, s, spd_len, | | 292 | 0, s, spd_len, |
290 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 293 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
291 | | | 294 | |
292 | /* | | 295 | /* |
293 | * Decode and print key SPD contents | | 296 | * Decode and print key SPD contents |
294 | */ | | 297 | */ |
295 | if (IS_RAMBUS_TYPE) { | | 298 | if (IS_RAMBUS_TYPE) { |
296 | if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS) | | 299 | if (s->sm_type == SPDMEM_MEMTYPE_RAMBUS) |
297 | type = "Rambus"; | | 300 | type = "Rambus"; |
298 | else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS) | | 301 | else if (s->sm_type == SPDMEM_MEMTYPE_DIRECTRAMBUS) |
299 | type = "Direct Rambus"; | | 302 | type = "Direct Rambus"; |
300 | else | | 303 | else |
301 | type = "Rambus (unknown)"; | | 304 | type = "Rambus (unknown)"; |
302 | | | 305 | |
303 | switch (s->sm_len) { | | 306 | switch (s->sm_len) { |
304 | case 0: | | 307 | case 0: |
305 | rambus_rev = "Invalid"; | | 308 | rambus_rev = "Invalid"; |
306 | break; | | 309 | break; |
307 | case 1: | | 310 | case 1: |
308 | rambus_rev = "0.7"; | | 311 | rambus_rev = "0.7"; |
309 | break; | | 312 | break; |
310 | case 2: | | 313 | case 2: |
311 | rambus_rev = "1.0"; | | 314 | rambus_rev = "1.0"; |
312 | break; | | 315 | break; |
313 | default: | | 316 | default: |
314 | rambus_rev = "Reserved"; | | 317 | rambus_rev = "Reserved"; |
315 | break; | | 318 | break; |
316 | } | | 319 | } |
317 | } else { | | 320 | } else { |
318 | if (s->sm_type < __arraycount(spdmem_basic_types)) | | 321 | if (s->sm_type < __arraycount(spdmem_basic_types)) |
319 | type = spdmem_basic_types[s->sm_type]; | | 322 | type = spdmem_basic_types[s->sm_type]; |
320 | else | | 323 | else |
321 | type = "unknown memory type"; | | 324 | type = "unknown memory type"; |
322 | | | 325 | |
323 | if (s->sm_type == SPDMEM_MEMTYPE_EDO && | | 326 | if (s->sm_type == SPDMEM_MEMTYPE_EDO && |
324 | s->sm_fpm.fpm_superset == SPDMEM_SUPERSET_EDO_PEM) | | 327 | s->sm_fpm.fpm_superset == SPDMEM_SUPERSET_EDO_PEM) |
325 | type = spdmem_superset_types[SPDMEM_SUPERSET_EDO_PEM]; | | 328 | type = spdmem_superset_types[SPDMEM_SUPERSET_EDO_PEM]; |
326 | if (s->sm_type == SPDMEM_MEMTYPE_SDRAM && | | 329 | if (s->sm_type == SPDMEM_MEMTYPE_SDRAM && |
327 | s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_SDRAM_PEM) | | 330 | s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_SDRAM_PEM) |
328 | type = spdmem_superset_types[SPDMEM_SUPERSET_SDRAM_PEM]; | | 331 | type = spdmem_superset_types[SPDMEM_SUPERSET_SDRAM_PEM]; |
329 | if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM && | | 332 | if (s->sm_type == SPDMEM_MEMTYPE_DDRSDRAM && |
330 | s->sm_ddr.ddr_superset == SPDMEM_SUPERSET_DDR_ESDRAM) | | 333 | s->sm_ddr.ddr_superset == SPDMEM_SUPERSET_DDR_ESDRAM) |
331 | type = | | 334 | type = |
332 | spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM]; | | 335 | spdmem_superset_types[SPDMEM_SUPERSET_DDR_ESDRAM]; |
333 | if (s->sm_type == SPDMEM_MEMTYPE_SDRAM && | | 336 | if (s->sm_type == SPDMEM_MEMTYPE_SDRAM && |
334 | s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_ESDRAM) { | | 337 | s->sm_sdr.sdr_superset == SPDMEM_SUPERSET_ESDRAM) { |
335 | type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM]; | | 338 | type = spdmem_superset_types[SPDMEM_SUPERSET_ESDRAM]; |
336 | } | | 339 | } |
337 | } | | 340 | } |
338 | | | 341 | |
339 | aprint_naive("\n"); | | 342 | aprint_naive("\n"); |
340 | aprint_normal("\n"); | | 343 | aprint_normal("\n"); |
341 | aprint_normal_dev(self, "%s", type); | | 344 | aprint_normal_dev(self, "%s", type); |
342 | strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN); | | 345 | strlcpy(sc->sc_type, type, SPDMEM_TYPE_MAXLEN); |
343 | if (node != NULL) | | 346 | if (node != NULL) |
344 | sysctl_createv(NULL, 0, NULL, NULL, | | 347 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
345 | 0, | | 348 | 0, |
346 | CTLTYPE_STRING, "mem_type", | | 349 | CTLTYPE_STRING, "mem_type", |
347 | SYSCTL_DESCR("memory module type"), NULL, | | 350 | SYSCTL_DESCR("memory module type"), NULL, |
348 | 0, sc->sc_type, 0, | | 351 | 0, sc->sc_type, 0, |
349 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 352 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
350 | | | 353 | |
351 | if (IS_RAMBUS_TYPE) { | | 354 | if (IS_RAMBUS_TYPE) { |
352 | aprint_normal(", SPD Revision %s", rambus_rev); | | 355 | aprint_normal(", SPD Revision %s", rambus_rev); |
353 | dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13); | | 356 | dimm_size = 1 << (s->sm_rdr.rdr_rows + s->sm_rdr.rdr_cols - 13); |
354 | if (dimm_size >= 1024) | | 357 | if (dimm_size >= 1024) |
355 | aprint_normal(", %dGB\n", dimm_size / 1024); | | 358 | aprint_normal(", %dGB\n", dimm_size / 1024); |
356 | else | | 359 | else |
357 | aprint_normal(", %dMB\n", dimm_size); | | 360 | aprint_normal(", %dMB\n", dimm_size); |
358 | | | 361 | |
359 | /* No further decode for RAMBUS memory */ | | 362 | /* No further decode for RAMBUS memory */ |
360 | return; | | 363 | return; |
361 | } | | 364 | } |
362 | switch (s->sm_type) { | | 365 | switch (s->sm_type) { |
363 | case SPDMEM_MEMTYPE_EDO: | | 366 | case SPDMEM_MEMTYPE_EDO: |
364 | case SPDMEM_MEMTYPE_FPM: | | 367 | case SPDMEM_MEMTYPE_FPM: |
365 | decode_edofpm(node, self, s); | | 368 | decode_edofpm(node, self, s); |
366 | break; | | 369 | break; |
367 | case SPDMEM_MEMTYPE_ROM: | | 370 | case SPDMEM_MEMTYPE_ROM: |
368 | decode_rom(node, self, s); | | 371 | decode_rom(node, self, s); |
369 | break; | | 372 | break; |
370 | case SPDMEM_MEMTYPE_SDRAM: | | 373 | case SPDMEM_MEMTYPE_SDRAM: |
371 | decode_sdram(node, self, s, spd_len); | | 374 | decode_sdram(node, self, s, spd_len); |
372 | break; | | 375 | break; |
373 | case SPDMEM_MEMTYPE_DDRSDRAM: | | 376 | case SPDMEM_MEMTYPE_DDRSDRAM: |
374 | decode_ddr(node, self, s); | | 377 | decode_ddr(node, self, s); |
375 | break; | | 378 | break; |
376 | case SPDMEM_MEMTYPE_DDR2SDRAM: | | 379 | case SPDMEM_MEMTYPE_DDR2SDRAM: |
377 | decode_ddr2(node, self, s); | | 380 | decode_ddr2(node, self, s); |
378 | break; | | 381 | break; |
379 | case SPDMEM_MEMTYPE_DDR3SDRAM: | | 382 | case SPDMEM_MEMTYPE_DDR3SDRAM: |
380 | decode_ddr3(node, self, s); | | 383 | decode_ddr3(node, self, s); |
381 | break; | | 384 | break; |
382 | case SPDMEM_MEMTYPE_FBDIMM: | | 385 | case SPDMEM_MEMTYPE_FBDIMM: |
383 | case SPDMEM_MEMTYPE_FBDIMM_PROBE: | | 386 | case SPDMEM_MEMTYPE_FBDIMM_PROBE: |
384 | decode_fbdimm(node, self, s); | | 387 | decode_fbdimm(node, self, s); |
385 | break; | | 388 | break; |
386 | } | | 389 | } |
387 | } | | 390 | } |
388 | | | 391 | |
| | | 392 | int |
| | | 393 | spdmem_common_detach(struct spdmem_softc *sc, device_t self) |
| | | 394 | { |
| | | 395 | sysctl_teardown(&sc->sc_sysctl_log); |
| | | 396 | |
| | | 397 | return 0; |
| | | 398 | } |
| | | 399 | |
389 | SYSCTL_SETUP(sysctl_spdmem_setup, "sysctl hw.spdmem subtree setup") | | 400 | SYSCTL_SETUP(sysctl_spdmem_setup, "sysctl hw.spdmem subtree setup") |
390 | { | | 401 | { |
391 | const struct sysctlnode *node; | | 402 | const struct sysctlnode *node; |
392 | | | 403 | |
393 | if (sysctl_createv(clog, 0, NULL, &node, | | 404 | if (sysctl_createv(clog, 0, NULL, &node, CTLFLAG_PERMANENT, |
394 | CTLFLAG_PERMANENT, | | 405 | CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, |
395 | CTLTYPE_NODE, "hw", NULL, | | 406 | CTL_HW, CTL_EOL) != 0) |
396 | NULL, 0, NULL, 0, | | | |
397 | CTL_HW, CTL_EOL) != 0) | | | |
398 | return; | | 407 | return; |
399 | | | 408 | |
400 | hw_node = node->sysctl_num; | | 409 | hw_node = node->sysctl_num; |
401 | } | | 410 | } |
402 | | | 411 | |
403 | static void | | 412 | static void |
404 | decode_size_speed(const struct sysctlnode *node, int dimm_size, int cycle_time, | | 413 | decode_size_speed(device_t self, const struct sysctlnode *node, |
405 | int d_clk, int bits, bool round, const char *ddr_type_string, | | 414 | int dimm_size, int cycle_time, int d_clk, int bits, |
406 | int speed) | | 415 | bool round, const char *ddr_type_string, int speed) |
407 | { | | 416 | { |
408 | int p_clk; | | 417 | int p_clk; |
| | | 418 | struct spdmem_softc *sc = (struct spdmem_softc *)device_private(self); |
409 | | | 419 | |
410 | if (dimm_size < 1024) | | 420 | if (dimm_size < 1024) |
411 | aprint_normal("%dMB", dimm_size); | | 421 | aprint_normal("%dMB", dimm_size); |
412 | else | | 422 | else |
413 | aprint_normal("%dGB", dimm_size / 1024); | | 423 | aprint_normal("%dGB", dimm_size / 1024); |
414 | if (node != NULL) | | 424 | if (node != NULL) |
415 | sysctl_createv(NULL, 0, NULL, NULL, | | 425 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
416 | CTLFLAG_IMMEDIATE, | | 426 | CTLFLAG_IMMEDIATE, |
417 | CTLTYPE_INT, "size", | | 427 | CTLTYPE_INT, "size", |
418 | SYSCTL_DESCR("module size in MB"), NULL, | | 428 | SYSCTL_DESCR("module size in MB"), NULL, |
419 | dimm_size, NULL, 0, | | 429 | dimm_size, NULL, 0, |
420 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 430 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
421 | | | 431 | |
422 | if (cycle_time == 0) { | | 432 | if (cycle_time == 0) { |
423 | aprint_normal("\n"); | | 433 | aprint_normal("\n"); |
424 | return; | | 434 | return; |
425 | } | | 435 | } |
426 | | | 436 | |
427 | /* | | 437 | /* |
428 | * Calculate p_clk first, since for DDR3 we need maximum significance. | | 438 | * Calculate p_clk first, since for DDR3 we need maximum significance. |
429 | * DDR3 rating is not rounded to a multiple of 100. This results in | | 439 | * DDR3 rating is not rounded to a multiple of 100. This results in |
430 | * cycle_time of 1.5ns displayed as PC3-10666. | | 440 | * cycle_time of 1.5ns displayed as PC3-10666. |
431 | * | | 441 | * |
432 | * For SDRAM, the speed is provided by the caller so we use it. | | 442 | * For SDRAM, the speed is provided by the caller so we use it. |
433 | */ | | 443 | */ |
434 | d_clk *= 1000 * 1000; | | 444 | d_clk *= 1000 * 1000; |
435 | if (speed) | | 445 | if (speed) |
436 | p_clk = speed; | | 446 | p_clk = speed; |
437 | else | | 447 | else |
438 | p_clk = (d_clk * bits) / 8 / cycle_time; | | 448 | p_clk = (d_clk * bits) / 8 / cycle_time; |
439 | d_clk = ((d_clk + cycle_time / 2) ) / cycle_time; | | 449 | d_clk = ((d_clk + cycle_time / 2) ) / cycle_time; |
440 | if (round) { | | 450 | if (round) { |
441 | if ((p_clk % 100) >= 50) | | 451 | if ((p_clk % 100) >= 50) |
442 | p_clk += 50; | | 452 | p_clk += 50; |
443 | p_clk -= p_clk % 100; | | 453 | p_clk -= p_clk % 100; |
444 | } | | 454 | } |
445 | aprint_normal(", %dMHz (%s-%d)\n", | | 455 | aprint_normal(", %dMHz (%s-%d)\n", |
446 | d_clk, ddr_type_string, p_clk); | | 456 | d_clk, ddr_type_string, p_clk); |
447 | if (node != NULL) | | 457 | if (node != NULL) |
448 | sysctl_createv(NULL, 0, NULL, NULL, | | 458 | sysctl_createv(&sc->sc_sysctl_log, 0, NULL, NULL, |
449 | CTLFLAG_IMMEDIATE, | | 459 | CTLFLAG_IMMEDIATE, |
450 | CTLTYPE_INT, "speed", | | 460 | CTLTYPE_INT, "speed", |
451 | SYSCTL_DESCR("memory speed in MHz"), | | 461 | SYSCTL_DESCR("memory speed in MHz"), |
452 | NULL, d_clk, NULL, 0, | | 462 | NULL, d_clk, NULL, 0, |
453 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 463 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
454 | } | | 464 | } |
455 | | | 465 | |
456 | static void | | 466 | static void |
457 | decode_voltage_refresh(device_t self, struct spdmem *s) | | 467 | decode_voltage_refresh(device_t self, struct spdmem *s) |
458 | { | | 468 | { |
459 | const char *voltage, *refresh; | | 469 | const char *voltage, *refresh; |
460 | | | 470 | |
461 | if (s->sm_voltage < __arraycount(spdmem_voltage_types)) | | 471 | if (s->sm_voltage < __arraycount(spdmem_voltage_types)) |
462 | voltage = spdmem_voltage_types[s->sm_voltage]; | | 472 | voltage = spdmem_voltage_types[s->sm_voltage]; |
463 | else | | 473 | else |
464 | voltage = "unknown"; | | 474 | voltage = "unknown"; |
465 | | | 475 | |
466 | if (s->sm_refresh < __arraycount(spdmem_refresh_types)) | | 476 | if (s->sm_refresh < __arraycount(spdmem_refresh_types)) |
467 | refresh = spdmem_refresh_types[s->sm_refresh]; | | 477 | refresh = spdmem_refresh_types[s->sm_refresh]; |
468 | else | | 478 | else |
469 | refresh = "unknown"; | | 479 | refresh = "unknown"; |
470 | | | 480 | |
471 | aprint_verbose_dev(self, "voltage %s, refresh time %s%s\n", | | 481 | aprint_verbose_dev(self, "voltage %s, refresh time %s%s\n", |
472 | voltage, refresh, | | 482 | voltage, refresh, |
473 | s->sm_selfrefresh?" (self-refreshing)":""); | | 483 | s->sm_selfrefresh?" (self-refreshing)":""); |
474 | } | | 484 | } |
475 | | | 485 | |
476 | static void | | 486 | static void |
477 | decode_edofpm(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 487 | decode_edofpm(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
478 | aprint_normal("\n"); | | 488 | aprint_normal("\n"); |
479 | aprint_verbose_dev(self, | | 489 | aprint_verbose_dev(self, |
480 | "%d rows, %d cols, %d banks, %dns tRAC, %dns tCAC\n", | | 490 | "%d rows, %d cols, %d banks, %dns tRAC, %dns tCAC\n", |
481 | s->sm_fpm.fpm_rows, s->sm_fpm.fpm_cols, s->sm_fpm.fpm_banks, | | 491 | s->sm_fpm.fpm_rows, s->sm_fpm.fpm_cols, s->sm_fpm.fpm_banks, |
482 | s->sm_fpm.fpm_tRAC, s->sm_fpm.fpm_tCAC); | | 492 | s->sm_fpm.fpm_tRAC, s->sm_fpm.fpm_tCAC); |
483 | } | | 493 | } |
484 | | | 494 | |
485 | static void | | 495 | static void |
486 | decode_rom(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 496 | decode_rom(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
487 | aprint_normal("\n"); | | 497 | aprint_normal("\n"); |
488 | aprint_verbose_dev(self, "%d rows, %d cols, %d banks\n", | | 498 | aprint_verbose_dev(self, "%d rows, %d cols, %d banks\n", |
489 | s->sm_rom.rom_rows, s->sm_rom.rom_cols, s->sm_rom.rom_banks); | | 499 | s->sm_rom.rom_rows, s->sm_rom.rom_cols, s->sm_rom.rom_banks); |
490 | } | | 500 | } |
491 | | | 501 | |
492 | static void | | 502 | static void |
493 | decode_sdram(const struct sysctlnode *node, device_t self, struct spdmem *s, | | 503 | decode_sdram(const struct sysctlnode *node, device_t self, struct spdmem *s, |
494 | int spd_len) { | | 504 | int spd_len) { |
495 | int dimm_size, cycle_time, bits, tAA, i, speed, freq; | | 505 | int dimm_size, cycle_time, bits, tAA, i, speed, freq; |
496 | | | 506 | |
497 | aprint_normal("%s, %s, ", | | 507 | aprint_normal("%s, %s, ", |
498 | (s->sm_sdr.sdr_mod_attrs & SPDMEM_SDR_MASK_REG)? | | 508 | (s->sm_sdr.sdr_mod_attrs & SPDMEM_SDR_MASK_REG)? |
499 | " (registered)":"", | | 509 | " (registered)":"", |
500 | (s->sm_config < __arraycount(spdmem_parity_types))? | | 510 | (s->sm_config < __arraycount(spdmem_parity_types))? |
501 | spdmem_parity_types[s->sm_config]:"invalid parity"); | | 511 | spdmem_parity_types[s->sm_config]:"invalid parity"); |
502 | | | 512 | |
503 | dimm_size = 1 << (s->sm_sdr.sdr_rows + s->sm_sdr.sdr_cols - 17); | | 513 | dimm_size = 1 << (s->sm_sdr.sdr_rows + s->sm_sdr.sdr_cols - 17); |
504 | dimm_size *= s->sm_sdr.sdr_banks * s->sm_sdr.sdr_banks_per_chip; | | 514 | dimm_size *= s->sm_sdr.sdr_banks * s->sm_sdr.sdr_banks_per_chip; |
505 | | | 515 | |
506 | cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 + | | 516 | cycle_time = s->sm_sdr.sdr_cycle_whole * 1000 + |
507 | s->sm_sdr.sdr_cycle_tenths * 100; | | 517 | s->sm_sdr.sdr_cycle_tenths * 100; |
508 | bits = le16toh(s->sm_sdr.sdr_datawidth); | | 518 | bits = le16toh(s->sm_sdr.sdr_datawidth); |
509 | if (s->sm_config == 1 || s->sm_config == 2) | | 519 | if (s->sm_config == 1 || s->sm_config == 2) |
510 | bits -= 8; | | 520 | bits -= 8; |
511 | | | 521 | |
512 | /* Calculate speed here - from OpenBSD */ | | 522 | /* Calculate speed here - from OpenBSD */ |
513 | if (spd_len >= 128) | | 523 | if (spd_len >= 128) |
514 | freq = ((uint8_t *)s)[126]; | | 524 | freq = ((uint8_t *)s)[126]; |
515 | else | | 525 | else |
516 | freq = 0; | | 526 | freq = 0; |
517 | switch (freq) { | | 527 | switch (freq) { |
518 | /* | | 528 | /* |
519 | * Must check cycle time since some PC-133 DIMMs | | 529 | * Must check cycle time since some PC-133 DIMMs |
520 | * actually report PC-100 | | 530 | * actually report PC-100 |
521 | */ | | 531 | */ |
522 | case 100: | | 532 | case 100: |
523 | case 133: | | 533 | case 133: |
524 | if (cycle_time < 8000) | | 534 | if (cycle_time < 8000) |
525 | speed = 133; | | 535 | speed = 133; |
526 | else | | 536 | else |
527 | speed = 100; | | 537 | speed = 100; |
528 | break; | | 538 | break; |
529 | case 0x66: /* Legacy DIMMs use _hex_ 66! */ | | 539 | case 0x66: /* Legacy DIMMs use _hex_ 66! */ |
530 | default: | | 540 | default: |
531 | speed = 66; | | 541 | speed = 66; |
532 | } | | 542 | } |
533 | decode_size_speed(node, dimm_size, cycle_time, 1, bits, FALSE, "PC", | | 543 | decode_size_speed(self, node, dimm_size, cycle_time, 1, bits, FALSE, |
534 | speed); | | 544 | "PC", speed); |
535 | | | 545 | |
536 | aprint_verbose_dev(self, | | 546 | aprint_verbose_dev(self, |
537 | "%d rows, %d cols, %d banks, %d banks/chip, %d.%dns cycle time\n", | | 547 | "%d rows, %d cols, %d banks, %d banks/chip, %d.%dns cycle time\n", |
538 | s->sm_sdr.sdr_rows, s->sm_sdr.sdr_cols, s->sm_sdr.sdr_banks, | | 548 | s->sm_sdr.sdr_rows, s->sm_sdr.sdr_cols, s->sm_sdr.sdr_banks, |
539 | s->sm_sdr.sdr_banks_per_chip, cycle_time/1000, | | 549 | s->sm_sdr.sdr_banks_per_chip, cycle_time/1000, |
540 | (cycle_time % 1000) / 100); | | 550 | (cycle_time % 1000) / 100); |
541 | | | 551 | |
542 | tAA = 0; | | 552 | tAA = 0; |
543 | for (i = 0; i < 8; i++) | | 553 | for (i = 0; i < 8; i++) |
544 | if (s->sm_sdr.sdr_tCAS & (1 << i)) | | 554 | if (s->sm_sdr.sdr_tCAS & (1 << i)) |
545 | tAA = i; | | 555 | tAA = i; |
546 | tAA++; | | 556 | tAA++; |
547 | aprint_verbose_dev(self, latency, tAA, s->sm_sdr.sdr_tRCD, | | 557 | aprint_verbose_dev(self, latency, tAA, s->sm_sdr.sdr_tRCD, |
548 | s->sm_sdr.sdr_tRP, s->sm_sdr.sdr_tRAS); | | 558 | s->sm_sdr.sdr_tRP, s->sm_sdr.sdr_tRAS); |
549 | | | 559 | |
550 | decode_voltage_refresh(self, s); | | 560 | decode_voltage_refresh(self, s); |
551 | } | | 561 | } |
552 | | | 562 | |
553 | static void | | 563 | static void |
554 | decode_ddr(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 564 | decode_ddr(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
555 | int dimm_size, cycle_time, bits, tAA, i; | | 565 | int dimm_size, cycle_time, bits, tAA, i; |
556 | | | 566 | |
557 | aprint_normal("%s, %s, ", | | 567 | aprint_normal("%s, %s, ", |
558 | (s->sm_ddr.ddr_mod_attrs & SPDMEM_DDR_MASK_REG)? | | 568 | (s->sm_ddr.ddr_mod_attrs & SPDMEM_DDR_MASK_REG)? |
559 | " (registered)":"", | | 569 | " (registered)":"", |
560 | (s->sm_config < __arraycount(spdmem_parity_types))? | | 570 | (s->sm_config < __arraycount(spdmem_parity_types))? |
561 | spdmem_parity_types[s->sm_config]:"invalid parity"); | | 571 | spdmem_parity_types[s->sm_config]:"invalid parity"); |
562 | | | 572 | |
563 | dimm_size = 1 << (s->sm_ddr.ddr_rows + s->sm_ddr.ddr_cols - 17); | | 573 | dimm_size = 1 << (s->sm_ddr.ddr_rows + s->sm_ddr.ddr_cols - 17); |
564 | dimm_size *= s->sm_ddr.ddr_ranks * s->sm_ddr.ddr_banks_per_chip; | | 574 | dimm_size *= s->sm_ddr.ddr_ranks * s->sm_ddr.ddr_banks_per_chip; |
565 | | | 575 | |
566 | cycle_time = s->sm_ddr.ddr_cycle_whole * 1000 + | | 576 | cycle_time = s->sm_ddr.ddr_cycle_whole * 1000 + |
567 | spdmem_cycle_frac[s->sm_ddr.ddr_cycle_tenths]; | | 577 | spdmem_cycle_frac[s->sm_ddr.ddr_cycle_tenths]; |
568 | bits = le16toh(s->sm_ddr.ddr_datawidth); | | 578 | bits = le16toh(s->sm_ddr.ddr_datawidth); |
569 | if (s->sm_config == 1 || s->sm_config == 2) | | 579 | if (s->sm_config == 1 || s->sm_config == 2) |
570 | bits -= 8; | | 580 | bits -= 8; |
571 | decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC", 0); | | 581 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, TRUE, |
| | | 582 | "PC", 0); |
572 | | | 583 | |
573 | aprint_verbose_dev(self, | | 584 | aprint_verbose_dev(self, |
574 | "%d rows, %d cols, %d ranks, %d banks/chip, %d.%dns cycle time\n", | | 585 | "%d rows, %d cols, %d ranks, %d banks/chip, %d.%dns cycle time\n", |
575 | s->sm_ddr.ddr_rows, s->sm_ddr.ddr_cols, s->sm_ddr.ddr_ranks, | | 586 | s->sm_ddr.ddr_rows, s->sm_ddr.ddr_cols, s->sm_ddr.ddr_ranks, |
576 | s->sm_ddr.ddr_banks_per_chip, cycle_time/1000, | | 587 | s->sm_ddr.ddr_banks_per_chip, cycle_time/1000, |
577 | (cycle_time % 1000 + 50) / 100); | | 588 | (cycle_time % 1000 + 50) / 100); |
578 | | | 589 | |
579 | tAA = 0; | | 590 | tAA = 0; |
580 | for (i = 2; i < 8; i++) | | 591 | for (i = 2; i < 8; i++) |
581 | if (s->sm_ddr.ddr_tCAS & (1 << i)) | | 592 | if (s->sm_ddr.ddr_tCAS & (1 << i)) |
582 | tAA = i; | | 593 | tAA = i; |
583 | tAA /= 2; | | 594 | tAA /= 2; |
584 | | | 595 | |
585 | #define __DDR_ROUND(scale, field) \ | | 596 | #define __DDR_ROUND(scale, field) \ |
586 | ((scale * s->sm_ddr.field + cycle_time - 1) / cycle_time) | | 597 | ((scale * s->sm_ddr.field + cycle_time - 1) / cycle_time) |
587 | | | 598 | |
588 | aprint_verbose_dev(self, latency, tAA, __DDR_ROUND(250, ddr_tRCD), | | 599 | aprint_verbose_dev(self, latency, tAA, __DDR_ROUND(250, ddr_tRCD), |
589 | __DDR_ROUND(250, ddr_tRP), __DDR_ROUND(1000, ddr_tRAS)); | | 600 | __DDR_ROUND(250, ddr_tRP), __DDR_ROUND(1000, ddr_tRAS)); |
590 | | | 601 | |
591 | #undef __DDR_ROUND | | 602 | #undef __DDR_ROUND |
592 | | | 603 | |
593 | decode_voltage_refresh(self, s); | | 604 | decode_voltage_refresh(self, s); |
594 | } | | 605 | } |
595 | | | 606 | |
596 | static void | | 607 | static void |
597 | decode_ddr2(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 608 | decode_ddr2(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
598 | int dimm_size, cycle_time, bits, tAA, i; | | 609 | int dimm_size, cycle_time, bits, tAA, i; |
599 | | | 610 | |
600 | aprint_normal("%s, %s, ", | | 611 | aprint_normal("%s, %s, ", |
601 | (s->sm_ddr2.ddr2_mod_attrs & SPDMEM_DDR2_MASK_REG)? | | 612 | (s->sm_ddr2.ddr2_mod_attrs & SPDMEM_DDR2_MASK_REG)? |
602 | " (registered)":"", | | 613 | " (registered)":"", |
603 | (s->sm_config < __arraycount(spdmem_parity_types))? | | 614 | (s->sm_config < __arraycount(spdmem_parity_types))? |
604 | spdmem_parity_types[s->sm_config]:"invalid parity"); | | 615 | spdmem_parity_types[s->sm_config]:"invalid parity"); |
605 | | | 616 | |
606 | dimm_size = 1 << (s->sm_ddr2.ddr2_rows + s->sm_ddr2.ddr2_cols - 17); | | 617 | dimm_size = 1 << (s->sm_ddr2.ddr2_rows + s->sm_ddr2.ddr2_cols - 17); |
607 | dimm_size *= (s->sm_ddr2.ddr2_ranks + 1) * | | 618 | dimm_size *= (s->sm_ddr2.ddr2_ranks + 1) * |
608 | s->sm_ddr2.ddr2_banks_per_chip; | | 619 | s->sm_ddr2.ddr2_banks_per_chip; |
609 | | | 620 | |
610 | cycle_time = s->sm_ddr2.ddr2_cycle_whole * 1000 + | | 621 | cycle_time = s->sm_ddr2.ddr2_cycle_whole * 1000 + |
611 | spdmem_cycle_frac[s->sm_ddr2.ddr2_cycle_frac]; | | 622 | spdmem_cycle_frac[s->sm_ddr2.ddr2_cycle_frac]; |
612 | bits = s->sm_ddr2.ddr2_datawidth; | | 623 | bits = s->sm_ddr2.ddr2_datawidth; |
613 | if ((s->sm_config & 0x03) != 0) | | 624 | if ((s->sm_config & 0x03) != 0) |
614 | bits -= 8; | | 625 | bits -= 8; |
615 | decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0); | | 626 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, TRUE, |
| | | 627 | "PC2", 0); |
616 | | | 628 | |
617 | aprint_verbose_dev(self, | | 629 | aprint_verbose_dev(self, |
618 | "%d rows, %d cols, %d ranks, %d banks/chip, %d.%02dns cycle time\n", | | 630 | "%d rows, %d cols, %d ranks, %d banks/chip, %d.%02dns cycle time\n", |
619 | s->sm_ddr2.ddr2_rows, s->sm_ddr2.ddr2_cols, | | 631 | s->sm_ddr2.ddr2_rows, s->sm_ddr2.ddr2_cols, |
620 | s->sm_ddr2.ddr2_ranks + 1, s->sm_ddr2.ddr2_banks_per_chip, | | 632 | s->sm_ddr2.ddr2_ranks + 1, s->sm_ddr2.ddr2_banks_per_chip, |
621 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); | | 633 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); |
622 | | | 634 | |
623 | tAA = 0; | | 635 | tAA = 0; |
624 | for (i = 2; i < 8; i++) | | 636 | for (i = 2; i < 8; i++) |
625 | if (s->sm_ddr2.ddr2_tCAS & (1 << i)) | | 637 | if (s->sm_ddr2.ddr2_tCAS & (1 << i)) |
626 | tAA = i; | | 638 | tAA = i; |
627 | | | 639 | |
628 | #define __DDR2_ROUND(scale, field) \ | | 640 | #define __DDR2_ROUND(scale, field) \ |
629 | ((scale * s->sm_ddr2.field + cycle_time - 1) / cycle_time) | | 641 | ((scale * s->sm_ddr2.field + cycle_time - 1) / cycle_time) |
630 | | | 642 | |
631 | aprint_verbose_dev(self, latency, tAA, __DDR2_ROUND(250, ddr2_tRCD), | | 643 | aprint_verbose_dev(self, latency, tAA, __DDR2_ROUND(250, ddr2_tRCD), |
632 | __DDR2_ROUND(250, ddr2_tRP), __DDR2_ROUND(1000, ddr2_tRAS)); | | 644 | __DDR2_ROUND(250, ddr2_tRP), __DDR2_ROUND(1000, ddr2_tRAS)); |
633 | | | 645 | |
634 | #undef __DDR_ROUND | | 646 | #undef __DDR_ROUND |
635 | | | 647 | |
636 | decode_voltage_refresh(self, s); | | 648 | decode_voltage_refresh(self, s); |
637 | } | | 649 | } |
638 | | | 650 | |
639 | static void | | 651 | static void |
640 | decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 652 | decode_ddr3(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
641 | int dimm_size, cycle_time, bits; | | 653 | int dimm_size, cycle_time, bits; |
642 | | | 654 | |
643 | if (s->sm_ddr3.ddr3_mod_type == | | 655 | if (s->sm_ddr3.ddr3_mod_type == |
644 | SPDMEM_DDR3_TYPE_MINI_RDIMM || | | 656 | SPDMEM_DDR3_TYPE_MINI_RDIMM || |
645 | s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM) | | 657 | s->sm_ddr3.ddr3_mod_type == SPDMEM_DDR3_TYPE_RDIMM) |
646 | aprint_normal(" (registered)"); | | 658 | aprint_normal(" (registered)"); |
647 | aprint_normal(", %sECC, %stemp-sensor, ", | | 659 | aprint_normal(", %sECC, %stemp-sensor, ", |
648 | (s->sm_ddr3.ddr3_hasECC)?"":"no ", | | 660 | (s->sm_ddr3.ddr3_hasECC)?"":"no ", |
649 | (s->sm_ddr3.ddr3_has_therm_sensor)?"":"no "); | | 661 | (s->sm_ddr3.ddr3_has_therm_sensor)?"":"no "); |
650 | | | 662 | |
651 | /* | | 663 | /* |
652 | * DDR3 size specification is quite different from others | | 664 | * DDR3 size specification is quite different from others |
653 | * | | 665 | * |
654 | * Module capacity is defined as | | 666 | * Module capacity is defined as |
655 | * Chip_Capacity_in_bits / 8bits-per-byte * | | 667 | * Chip_Capacity_in_bits / 8bits-per-byte * |
656 | * external_bus_width / internal_bus_width | | 668 | * external_bus_width / internal_bus_width |
657 | * We further divide by 2**20 to get our answer in MB | | 669 | * We further divide by 2**20 to get our answer in MB |
658 | */ | | 670 | */ |
659 | dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 + | | 671 | dimm_size = (s->sm_ddr3.ddr3_chipsize + 28 - 20) - 3 + |
660 | (s->sm_ddr3.ddr3_datawidth + 3) - | | 672 | (s->sm_ddr3.ddr3_datawidth + 3) - |
661 | (s->sm_ddr3.ddr3_chipwidth + 2); | | 673 | (s->sm_ddr3.ddr3_chipwidth + 2); |
662 | dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1); | | 674 | dimm_size = (1 << dimm_size) * (s->sm_ddr3.ddr3_physbanks + 1); |
663 | | | 675 | |
664 | cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend + | | 676 | cycle_time = (1000 * s->sm_ddr3.ddr3_mtb_dividend + |
665 | (s->sm_ddr3.ddr3_mtb_divisor / 2)) / | | 677 | (s->sm_ddr3.ddr3_mtb_divisor / 2)) / |
666 | s->sm_ddr3.ddr3_mtb_divisor; | | 678 | s->sm_ddr3.ddr3_mtb_divisor; |
667 | cycle_time *= s->sm_ddr3.ddr3_tCKmin; | | 679 | cycle_time *= s->sm_ddr3.ddr3_tCKmin; |
668 | bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3); | | 680 | bits = 1 << (s->sm_ddr3.ddr3_datawidth + 3); |
669 | decode_size_speed(node, dimm_size, cycle_time, 2, bits, FALSE, "PC3", 0); | | 681 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, FALSE, |
| | | 682 | "PC3", 0); |
670 | | | 683 | |
671 | aprint_verbose_dev(self, | | 684 | aprint_verbose_dev(self, |
672 | "%d rows, %d cols, %d log. banks, %d phys. banks, " | | 685 | "%d rows, %d cols, %d log. banks, %d phys. banks, " |
673 | "%d.%03dns cycle time\n", | | 686 | "%d.%03dns cycle time\n", |
674 | s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12, | | 687 | s->sm_ddr3.ddr3_rows + 9, s->sm_ddr3.ddr3_cols + 12, |
675 | 1 << (s->sm_ddr3.ddr3_logbanks + 3), | | 688 | 1 << (s->sm_ddr3.ddr3_logbanks + 3), |
676 | s->sm_ddr3.ddr3_physbanks + 1, | | 689 | s->sm_ddr3.ddr3_physbanks + 1, |
677 | cycle_time/1000, cycle_time % 1000); | | 690 | cycle_time/1000, cycle_time % 1000); |
678 | | | 691 | |
679 | #define __DDR3_CYCLES(field) (s->sm_ddr3.field / s->sm_ddr3.ddr3_tCKmin) | | 692 | #define __DDR3_CYCLES(field) (s->sm_ddr3.field / s->sm_ddr3.ddr3_tCKmin) |
680 | | | 693 | |
681 | aprint_verbose_dev(self, latency, __DDR3_CYCLES(ddr3_tAAmin), | | 694 | aprint_verbose_dev(self, latency, __DDR3_CYCLES(ddr3_tAAmin), |
682 | __DDR3_CYCLES(ddr3_tRCDmin), __DDR3_CYCLES(ddr3_tRPmin), | | 695 | __DDR3_CYCLES(ddr3_tRCDmin), __DDR3_CYCLES(ddr3_tRPmin), |
683 | (s->sm_ddr3.ddr3_tRAS_msb * 256 + s->sm_ddr3.ddr3_tRAS_lsb) / | | 696 | (s->sm_ddr3.ddr3_tRAS_msb * 256 + s->sm_ddr3.ddr3_tRAS_lsb) / |
684 | s->sm_ddr3.ddr3_tCKmin); | | 697 | s->sm_ddr3.ddr3_tCKmin); |
685 | | | 698 | |
686 | #undef __DDR3_CYCLES | | 699 | #undef __DDR3_CYCLES |
687 | } | | 700 | } |
688 | | | 701 | |
689 | static void | | 702 | static void |
690 | decode_fbdimm(const struct sysctlnode *node, device_t self, struct spdmem *s) { | | 703 | decode_fbdimm(const struct sysctlnode *node, device_t self, struct spdmem *s) { |
691 | int dimm_size, cycle_time, bits; | | 704 | int dimm_size, cycle_time, bits; |
692 | | | 705 | |
693 | /* | | 706 | /* |
694 | * FB-DIMM module size calculation is very much like DDR3 | | 707 | * FB-DIMM module size calculation is very much like DDR3 |
695 | */ | | 708 | */ |
696 | dimm_size = s->sm_fbd.fbdimm_rows + 12 + | | 709 | dimm_size = s->sm_fbd.fbdimm_rows + 12 + |
697 | s->sm_fbd.fbdimm_cols + 9 - 20 - 3; | | 710 | s->sm_fbd.fbdimm_cols + 9 - 20 - 3; |
698 | dimm_size = (1 << dimm_size) * (1 << (s->sm_fbd.fbdimm_banks + 2)); | | 711 | dimm_size = (1 << dimm_size) * (1 << (s->sm_fbd.fbdimm_banks + 2)); |
699 | | | 712 | |
700 | cycle_time = (1000 * s->sm_fbd.fbdimm_mtb_dividend + | | 713 | cycle_time = (1000 * s->sm_fbd.fbdimm_mtb_dividend + |
701 | (s->sm_fbd.fbdimm_mtb_divisor / 2)) / | | 714 | (s->sm_fbd.fbdimm_mtb_divisor / 2)) / |
702 | s->sm_fbd.fbdimm_mtb_divisor; | | 715 | s->sm_fbd.fbdimm_mtb_divisor; |
703 | bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2); | | 716 | bits = 1 << (s->sm_fbd.fbdimm_dev_width + 2); |
704 | decode_size_speed(node, dimm_size, cycle_time, 2, bits, TRUE, "PC2", 0); | | 717 | decode_size_speed(self, node, dimm_size, cycle_time, 2, bits, TRUE, |
| | | 718 | "PC2", 0); |
705 | | | 719 | |
706 | aprint_verbose_dev(self, | | 720 | aprint_verbose_dev(self, |
707 | "%d rows, %d cols, %d banks, %d.%02dns cycle time\n", | | 721 | "%d rows, %d cols, %d banks, %d.%02dns cycle time\n", |
708 | s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols, | | 722 | s->sm_fbd.fbdimm_rows, s->sm_fbd.fbdimm_cols, |
709 | 1 << (s->sm_fbd.fbdimm_banks + 2), | | 723 | 1 << (s->sm_fbd.fbdimm_banks + 2), |
710 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); | | 724 | cycle_time / 1000, (cycle_time % 1000 + 5) /10 ); |
711 | | | 725 | |
712 | #define __FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin) | | 726 | #define __FBDIMM_CYCLES(field) (s->sm_fbd.field / s->sm_fbd.fbdimm_tCKmin) |
713 | | | 727 | |
714 | aprint_verbose_dev(self, latency, __FBDIMM_CYCLES(fbdimm_tAAmin), | | 728 | aprint_verbose_dev(self, latency, __FBDIMM_CYCLES(fbdimm_tAAmin), |
715 | __FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin), | | 729 | __FBDIMM_CYCLES(fbdimm_tRCDmin), __FBDIMM_CYCLES(fbdimm_tRPmin), |
716 | (s->sm_fbd.fbdimm_tRAS_msb * 256 + | | 730 | (s->sm_fbd.fbdimm_tRAS_msb * 256 + |
717 | s->sm_fbd.fbdimm_tRAS_lsb) / | | 731 | s->sm_fbd.fbdimm_tRAS_lsb) / |
718 | s->sm_fbd.fbdimm_tCKmin); | | 732 | s->sm_fbd.fbdimm_tCKmin); |
719 | | | 733 | |
720 | #undef __FBDIMM_CYCLES | | 734 | #undef __FBDIMM_CYCLES |
721 | | | 735 | |
722 | decode_voltage_refresh(self, s); | | 736 | decode_voltage_refresh(self, s); |
723 | } | | 737 | } |