1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Oxide Computer Company
14 */
15
16 /*
17 * DDR4 EEPROM Driver
18 *
19 * -------------
20 * Device Design
21 * -------------
22 *
23 * The EE1004 device is found in DDR4 devices and is specified by JC-42.4.
24 * These EEPROMs are 512-byte devices that are split into two 256-byte pages and
25 * have the ability to lock data in 128-byte regions. As was the style of the
26 * time and likely a side effect of device operation, the page select and data
27 * read/write operations are split across two different I2C addresses.
28 *
29 * The JEDEC spec splits the 7-bit address into a 4-bit device class and a
30 * 3-bit device ID. The device ID is used to identify a single DIMM, whose id is
31 * usally set based on pins on the DDR4 socket. So to read from DIMM 0 we would
32 * target address 0x50. From DIMM4, 0x54. From DIMM7, 0x57.
33 *
34 * While these devices have separate addresses for the SPD reads and writes
35 * (along with the temperature sensor) all other addresses are shared between
36 * devices. In particular this includes the page address and the write
37 * protection features. In other words, if you change the active page, it's
38 * going to change it for all devices at that spot in the tree. Similarly if you
39 * issue a write protect command it's for everything that can be reached.
40 *
41 * Now of course, there are only up to 8 device IDs on a bus; however, DDR4
42 * server platforms often supported up to 16 DIMMs, which means muxes are in
43 * play. This means that on a common DDR4 server platform you often have
44 * something that looks like:
45 *
46 * +------------+
47 * | I2C |
48 * | controller |
49 * +------------+
50 * |
51 * |
52 * v
53 * +-------+
54 * +--------------| mux |--------------+
55 * | +-------+ |
56 * | |
57 * +-----+--+--+-----+ +-----+--+--+-----+
58 * | | | | | | | |
59 * v v v v v v v v
60 * +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
61 * | D | | D | | D | | D | | D | | D | | D | | D |
62 * | I | | I | | I | | I | | I | | I | | I | | I |
63 * | M | | M | | M | | M | | M | | M | | M | | M |
64 * | M | | M | | M | | M | | M | | M | | M | | M |
65 * | | | | | | | | | | | | | | | |
66 * | 0 | | 1 | | 2 | | 3 | | 8 | | 9 | | a | | b |
67 * +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
68 *
69 * So while we said earlier that all devices will change at the same time or be
70 * impacted by I/O to a common address, that isn't quite true. It's technically
71 * all devices that are on the same mux segment.
72 *
73 * -------------------------
74 * Driver Address Management
75 * -------------------------
76 *
77 *
78 * To keep the driver simple, we don't try to ask the question of whether
79 * or not a device is in the same spot of the tree. Similarly, we also don't
80 * actually try to remember what page was last set. We do this because we don't
81 * want to track what device was last active and then this allows someone else
82 * using the bus behind our backs to have made changes. In other words, we will
83 * always set the page for every I/O. While this wastes a bit of bus transaction
84 * time, it's not the end of world. Notably asking what page is set costs the
85 * same as just setting it.
86 *
87 * Each instance of the device ends up with three different I2C clients today:
88 *
89 * 1. A client (and reg handle) for the EEPROM itself.
90 * 2. A client for selecting page 0 (0x36).
91 * 3. A client for selecting page 1 (0x37).
92 *
93 * The client for (1) comes from the device reg[] array. The other two are
94 * shared addresses that we claim at run time. Due to having to change the page,
95 * we end up serializing I/O across all instances of the device with a shared
96 * mutex: ee100x_spa_mutex. Our lock ordering requires that one hold this mutex
97 * prior to beginning any bus transactions. A bus transaction must be made
98 * explicitly and passed from call to call to ensure that we don't have anyone
99 * else interrupt us for a single I/O and potentially change the page semantics
100 * on us.
101 *
102 * While there are are writable portions of the SPD, today the driver does not
103 * support that wanting to ensure that we don't actually damage the device and
104 * make it impossible for the CPU to use the DRAM in question.
105 */
106
107 #include <sys/modctl.h>
108 #include <sys/conf.h>
109 #include <sys/devops.h>
110 #include <sys/ddi.h>
111 #include <sys/sunddi.h>
112 #include <sys/sysmacros.h>
113 #include <sys/bitext.h>
114
115 #include <sys/i2c/client.h>
116 #include <eedev.h>
117
118 /*
119 * These are the I2C addresses that are used to change and query pages per
120 * EE1004. The way that the device indicates what page it's on is by issuing an
121 * ack (page 0) or a nack (page 1) to a request.
122 */
123 #define EE1004_GET_PAGE_ADDR 0x36
124 #define EE1004_SET_PAGE0_ADDR 0x36
125 #define EE1004_SET_PAGE1_ADDR 0x37
126
127 /*
128 * Organization of an EEPROM1004 device. The device is required to always be a
129 * 512 byte device organized in two banks of 256 bytes.
130 */
131 #define EE1004_LEN 512
132 #define EE1004_SEG 256
133
134 typedef struct ee100x {
135 dev_info_t *ee_dip;
136 i2c_client_t *ee_mem;
137 i2c_reg_hdl_t *ee_mem_hdl;
138 i2c_client_t *ee_spa0;
139 i2c_client_t *ee_spa1;
140 eedev_hdl_t *ee_devhdl;
141 uint8_t ee_buf[I2C_REQ_MAX];
142 } ee100x_t;
143
144 /*
145 * Device soft state
146 */
147 static void *ee100x_state;
148
149 /*
150 * This is a driver-wide mutex that we use to serialize all operations related
151 * to page switching and I/O. Effectively the driver can only support a single
152 * I/O outstanding across the system. See the theory statement for more
153 * information.
154 */
155 static kmutex_t ee100x_spa_mutex;
156
157 static int
ee100x_read(void * arg,struct uio * uio,uint32_t page,uint32_t pageoff,uint32_t nbytes)158 ee100x_read(void *arg, struct uio *uio, uint32_t page, uint32_t pageoff,
159 uint32_t nbytes)
160 {
161 int ret = 0;
162 ee100x_t *ee = arg;
163 i2c_client_t *client;
164 i2c_txn_t *txn;
165 i2c_error_t err;
166
167 if (page == 0) {
168 client = ee->ee_spa0;
169 } else {
170 client = ee->ee_spa1;
171 }
172
173 mutex_enter(&ee100x_spa_mutex);
174 if (i2c_bus_lock(client, 0, &txn) != I2C_CORE_E_OK) {
175 mutex_exit(&ee100x_spa_mutex);
176 return (EINTR);
177 }
178
179 if (!smbus_client_write_u8(txn, client, 0, 0, &err)) {
180 dev_err(ee->ee_dip, CE_WARN, "!failed to select page %u: "
181 "0x%x/0x%x", page, err.i2c_error, err.i2c_ctrl);
182 ret = EIO;
183 goto done;
184 }
185
186 if (i2c_reg_get(txn, ee->ee_mem_hdl, pageoff, ee->ee_buf, nbytes,
187 &err)) {
188 ret = uiomove(ee->ee_buf, nbytes, UIO_READ, uio);
189 } else {
190 dev_err(ee->ee_dip, CE_WARN, "!failed to read %u bytes of NVM "
191 "at 0x%x on page %u: 0x%x/0x%x", nbytes, pageoff, page,
192 err.i2c_error, err.i2c_ctrl);
193 ret = EIO;
194 }
195
196 done:
197 i2c_bus_unlock(txn);
198 mutex_exit(&ee100x_spa_mutex);
199
200 return (ret);
201 }
202
203 static const eedev_ops_t ee100x_eedev_ops = {
204 .eo_read = ee100x_read
205 };
206
207 static bool
ee100x_eedev_init(ee100x_t * ee)208 ee100x_eedev_init(ee100x_t *ee)
209 {
210 int ret;
211 eedev_reg_t reg;
212
213 bzero(®, sizeof (reg));
214 reg.ereg_vers = EEDEV_REG_VERS;
215 reg.ereg_size = EE1004_LEN;
216 reg.ereg_seg = EE1004_SEG;
217 reg.ereg_read_gran = 1;
218 reg.ereg_ro = true;
219 reg.ereg_dip = ee->ee_dip;
220 reg.ereg_driver = ee;
221 reg.ereg_name = NULL;
222 reg.ereg_ops = &ee100x_eedev_ops;
223 reg.ereg_max_read = MIN(i2c_reg_max_read(ee->ee_mem_hdl),
224 I2C_REQ_MAX / 2);
225
226 if ((ret = eedev_create(®, &ee->ee_devhdl)) != 0) {
227 dev_err(ee->ee_dip, CE_WARN, "failed to create eedev device: "
228 "%d", ret);
229 return (false);
230 }
231
232 return (true);
233 }
234
235 static void
ee100x_cleanup(ee100x_t * ee)236 ee100x_cleanup(ee100x_t *ee)
237 {
238 eedev_fini(ee->ee_devhdl);
239 i2c_client_destroy(ee->ee_spa1);
240 i2c_client_destroy(ee->ee_spa0);
241 i2c_reg_handle_destroy(ee->ee_mem_hdl);
242 i2c_client_destroy(ee->ee_mem);
243 ddi_soft_state_free(ee100x_state, ddi_get_instance(ee->ee_dip));
244 }
245
246 static int
ee100x_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)247 ee100x_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
248 {
249 i2c_errno_t ret;
250 i2c_addr_t addr;
251 i2c_reg_acc_attr_t attr;
252 ee100x_t *ee;
253
254 if (cmd == DDI_RESUME) {
255 return (DDI_SUCCESS);
256 } else if (cmd != DDI_ATTACH) {
257 return (DDI_FAILURE);
258 }
259
260 if (ddi_soft_state_zalloc(ee100x_state, ddi_get_instance(dip)) !=
261 DDI_SUCCESS) {
262 dev_err(dip, CE_WARN, "failed to alocate soft state");
263 return (DDI_FAILURE);
264 }
265
266 ee = ddi_get_soft_state(ee100x_state, ddi_get_instance(dip));
267 if (ee == NULL) {
268 dev_err(dip, CE_WARN, "failed to obtain soft state after "
269 "alloc");
270 return (DDI_FAILURE);
271 }
272 ee->ee_dip = dip;
273
274 if ((ret = i2c_client_init(ee->ee_dip, 0, &ee->ee_mem)) !=
275 I2C_CORE_E_OK) {
276 dev_err(dip, CE_WARN, "failed to initialize memory i2c "
277 "client: 0x%x", ret);
278 goto err;
279 }
280
281 bzero(&attr, sizeof (attr));
282 attr.i2cacc_version = I2C_REG_ACC_ATTR_V0;
283 attr.i2cacc_addr_len = 1;
284 attr.i2cacc_reg_len = 1;
285 attr.i2cacc_addr_max = UINT8_MAX;
286
287 if ((ret = i2c_reg_handle_init(ee->ee_mem, &attr, &ee->ee_mem_hdl)) !=
288 I2C_CORE_E_OK) {
289 dev_err(dip, CE_WARN, "failed to initialize client handle: "
290 "0x%x", ret);
291 goto err;
292 }
293
294 addr.ia_type = I2C_ADDR_7BIT;
295 addr.ia_addr = EE1004_SET_PAGE0_ADDR;
296 if ((ret = i2c_client_claim_addr(ee->ee_dip, &addr, I2C_CLAIM_F_SHARED,
297 &ee->ee_spa0)) != I2C_CORE_E_OK) {
298 dev_err(dip, CE_WARN, "failed to claim address 0x%x: 0x%x",
299 addr.ia_addr, ret);
300 goto err;
301 }
302
303 addr.ia_type = I2C_ADDR_7BIT;
304 addr.ia_addr = EE1004_SET_PAGE1_ADDR;
305 if ((ret = i2c_client_claim_addr(ee->ee_dip, &addr, I2C_CLAIM_F_SHARED,
306 &ee->ee_spa1)) != I2C_CORE_E_OK) {
307 dev_err(dip, CE_WARN, "failed to claim address 0x%x: 0x%x",
308 addr.ia_addr, ret);
309 goto err;
310 }
311
312 if (!ee100x_eedev_init(ee))
313 goto err;
314
315 return (DDI_SUCCESS);
316
317 err:
318 ee100x_cleanup(ee);
319 return (DDI_FAILURE);
320 }
321
322 static int
ee100x_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** outp)323 ee100x_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **outp)
324 {
325 ee100x_t *ee;
326
327 switch (cmd) {
328 case DDI_INFO_DEVT2DEVINFO:
329 ee = ddi_get_soft_state(ee100x_state, getminor((dev_t)arg));
330 if (ee == NULL) {
331 return (DDI_FAILURE);
332 }
333 *outp = ee->ee_dip;
334 break;
335 case DDI_INFO_DEVT2INSTANCE:
336 ee = ddi_get_soft_state(ee100x_state, getminor((dev_t)arg));
337 if (ee == NULL) {
338 return (DDI_FAILURE);
339 }
340
341 *outp = (void *)(uintptr_t)ddi_get_instance(ee->ee_dip);
342 break;
343 default:
344 return (DDI_FAILURE);
345 }
346
347 return (DDI_SUCCESS);
348 }
349
350 static int
ee100x_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)351 ee100x_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
352 {
353 ee100x_t *ee;
354
355 if (cmd == DDI_SUSPEND) {
356 return (DDI_SUCCESS);
357 } else if (cmd != DDI_DETACH) {
358 return (DDI_FAILURE);
359 }
360
361 ee = ddi_get_soft_state(ee100x_state, ddi_get_instance(dip));
362 if (ee == NULL) {
363 dev_err(dip, CE_WARN, "cannot detach: failed to obtain soft "
364 "state");
365 return (DDI_FAILURE);
366 }
367
368 ee100x_cleanup(ee);
369 return (DDI_SUCCESS);
370 }
371
372 static struct dev_ops ee100x_dev_ops = {
373 .devo_rev = DEVO_REV,
374 .devo_refcnt = 0,
375 .devo_getinfo = ee100x_getinfo,
376 .devo_identify = nulldev,
377 .devo_probe = nulldev,
378 .devo_attach = ee100x_attach,
379 .devo_detach = ee100x_detach,
380 .devo_reset = nodev,
381 .devo_quiesce = ddi_quiesce_not_needed
382 };
383
384 static struct modldrv ee100x_modldrv = {
385 .drv_modops = &mod_driverops,
386 .drv_linkinfo = "EE1004 Driver",
387 .drv_dev_ops = &ee100x_dev_ops
388 };
389
390 static struct modlinkage ee100x_modlinkage = {
391 .ml_rev = MODREV_1,
392 .ml_linkage = { &ee100x_modldrv, NULL }
393 };
394
395 static void
ee100x_globals_fini(void)396 ee100x_globals_fini(void)
397 {
398 ddi_soft_state_fini(&ee100x_state);
399 mutex_destroy(&ee100x_spa_mutex);
400 }
401
402 static int
ee100x_globals_init(void)403 ee100x_globals_init(void)
404 {
405 int ret;
406
407 if ((ret = ddi_soft_state_init(&ee100x_state, sizeof (ee100x_t), 0)) !=
408 0) {
409 return (ret);
410 }
411 mutex_init(&ee100x_spa_mutex, NULL, MUTEX_DRIVER, NULL);
412
413 return (0);
414 }
415
416 int
_init(void)417 _init(void)
418 {
419 int ret;
420
421 if ((ret = ee100x_globals_init()) != 0) {
422 return (ret);
423 }
424
425 if ((ret = mod_install(&ee100x_modlinkage)) != 0) {
426 ee100x_globals_fini();
427 }
428
429 return (ret);
430 }
431
432 int
_info(struct modinfo * modinfop)433 _info(struct modinfo *modinfop)
434 {
435 return (mod_info(&ee100x_modlinkage, modinfop));
436 }
437
438 int
_fini(void)439 _fini(void)
440 {
441 int ret;
442
443 if ((ret = mod_remove(&ee100x_modlinkage)) == 0) {
444 ee100x_globals_fini();
445 }
446
447 return (ret);
448 }
449