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 #ifndef _I2CNEX_H 17 #define _I2CNEX_H 18 19 /* 20 * Internal definitions for the i2c nexus driver. 21 */ 22 23 #include <sys/id_space.h> 24 #include <sys/avl.h> 25 #include <sys/list.h> 26 #include <sys/types.h> 27 #include <sys/mkdev.h> 28 #include <sys/i2c/controller.h> 29 #include <sys/i2c/client.h> 30 #include <sys/i2c/mux.h> 31 #include <sys/i2c/ioctl.h> 32 33 #ifdef __cplusplus 34 extern "C" { 35 #endif 36 37 /* 38 * This is the maximum number of ports we'll support on a controller or switch 39 * today. 40 */ 41 #define I2C_MAX_PORTS 16 42 43 /* 44 * We split our minor range in two. There is a range that is used for devices 45 * and a range that is used for users. The range for devices is in the range [1, 46 * MAXMIN32], where as users start at MAXMIN32+1 and are given up to a million 47 * entries. 48 */ 49 #define I2C_DEV_MINOR_MIN 1 50 #define I2C_DEV_MINOR_MAX MAXMIN32 51 #define I2C_USER_MINOR_MIN (MAXMIN32 + 1) 52 #define I2C_USER_MINOR_MAX (MAXMIN32 + (2 << 19)) 53 54 /* 55 * Global data that tracks minor mapping and related. 56 */ 57 typedef struct i2cnex_minors { 58 kmutex_t im_mutex; 59 id_space_t *im_ids; 60 id_space_t *im_user_ids; 61 avl_tree_t im_nexi; 62 avl_tree_t im_users; 63 list_t im_roots; 64 } i2cnex_minors_t; 65 66 /* 67 * Forward decls for various things. 68 */ 69 typedef struct i2c_root i2c_root_t; 70 typedef struct i2c_ctrl i2c_ctrl_t; 71 typedef struct i2c_port i2c_port_t; 72 typedef struct i2c_dev i2c_dev_t; 73 typedef struct i2c_mux i2c_mux_t; 74 typedef struct i2c_nexus i2c_nexus_t; 75 76 /* 77 * Address tracking structures. See i2cnex_addr.c theory statement for more 78 * information. 79 */ 80 typedef struct i2c_addr_track { 81 bool at_downstream[1 << 10]; 82 uint8_t at_refcnt[1 << 10]; 83 major_t at_major[1 << 10]; 84 } i2c_addr_track_t; 85 86 /* 87 * This represents a port on a mux or a controller. Device IDs are unique 88 * downstream of a port. 89 */ 90 struct i2c_port { 91 uint32_t ip_portno; 92 /* 93 * This is used to indicate the number of device's that exist on a port 94 * below this one. The number of devices that are on this port is just 95 * an avl_numnodes() call on ip_devices. 96 */ 97 uint32_t ip_ndevs_ds; 98 i2c_nexus_t *ip_nex; 99 i2c_addr_track_t ip_track_7b; 100 avl_tree_t ip_devices; 101 list_node_t ip_ctrl_link; 102 }; 103 104 /* 105 * This represents a single device on the i2c bus. 106 */ 107 struct i2c_dev { 108 avl_node_t id_link; 109 i2c_addr_t id_addr; 110 char **id_ucompat; 111 uint_t id_nucompat; 112 i2c_nexus_t *id_nex; 113 i2c_mux_t *id_mux; 114 list_t id_clients; 115 }; 116 117 /* 118 * This represents information about a single mux. This is used when a device 119 * registers with the mux framework. 120 */ 121 struct i2c_mux { 122 i2c_nexus_t *im_nex; 123 const i2c_mux_ops_t *im_ops; 124 void *im_drv; 125 uint32_t im_nports; 126 /* 127 * This data is all protected by the controller lock after 128 * initialization. 129 */ 130 uint32_t im_curport; 131 i2c_port_t im_ports[I2C_MAX_PORTS]; 132 }; 133 134 typedef enum { 135 I2C_CTRL_MA_NONE, 136 I2C_CTRL_MA_DESELECT, 137 I2C_CTRL_MA_UPDATE 138 } i2c_ctrl_mux_act_t; 139 140 typedef struct i2c_ctrl_lock { 141 kmutex_t cl_mutex; 142 i2c_txn_t *cl_owner; 143 list_t cl_waiters; 144 /* 145 * The following members are used to track when a nexus operation is 146 * active. These basically allow a subsequent nexus operation in the 147 * same thread to take advantage of the lock. See the locking section 148 * in the theory statement for more information. 149 */ 150 uintptr_t cl_nexus_thr; 151 list_t cl_stack; 152 /* 153 * Misc. debugging stats. 154 */ 155 uint32_t cl_nlocks; 156 uint32_t cl_nwait; 157 uint32_t cl_nnonblock; 158 uint32_t cl_nsig; 159 uint32_t cl_nsig_block; 160 uint32_t cl_nsig_acq; 161 uint32_t cl_nstack; 162 uint32_t cl_nnexus; 163 } i2c_ctrl_lock_t; 164 165 typedef struct i2c_ctrl_limit { 166 uint32_t lim_i2c_read; 167 uint32_t lim_i2c_write; 168 smbus_prop_op_t lim_smbus_ops; 169 uint32_t lim_smbus_block; 170 } i2c_ctrl_limit_t; 171 172 /* 173 * This represents an instance of a controller. A controller has independent 174 * controls and settings. 175 */ 176 struct i2c_ctrl { 177 list_node_t ic_link; 178 i2c_root_t *ic_root; 179 void *ic_drv; 180 const i2c_ctrl_ops_t *ic_ops; 181 i2c_ctrl_type_t ic_type; 182 i2c_nexus_t *ic_nexus; 183 uint32_t ic_nports; 184 i2c_port_t ic_ports[I2C_MAX_PORTS]; 185 i2c_ctrl_lock_t ic_lock; 186 i2c_ctrl_limit_t ic_limit; 187 union { 188 smbus_req_t req_smbus; 189 i2c_req_t req_i2c; 190 } ic_reqs; 191 /* 192 * These lists are used to manage and track the set of mux ports that 193 * are currently being used on the bus in the order that they exist in 194 * the tree. The head of the list will generally be the current port on 195 * the bus that's being used. The tail the furthest mux in the tree. 196 * When something is in here, it means that traffic will flow down the 197 * port. The plan list is used when we're switching between different 198 * muxes and want to indicate what the new order will be. See the I/O 199 * and Mux Tracking section of the theory statement for more 200 * information. 201 * 202 * The mux state is used to track what mux activity we're actively 203 * doing. This is useful because when we activate or deactivate a mux, 204 * it'll call back into the mux update logic. 205 */ 206 list_t ic_mux_active; 207 list_t ic_mux_plan; 208 i2c_ctrl_mux_act_t ic_mux_state; 209 /* 210 * The ic_txn_lock protects the list of i2c_txn_t only. It is not used 211 * as part of locking more broadly. 212 */ 213 kmutex_t ic_txn_lock; 214 list_t ic_txns; 215 }; 216 217 typedef enum { 218 I2C_NEXUS_T_CTRL, 219 I2C_NEXUS_T_PORT, 220 I2C_NEXUS_T_DEV, 221 I2C_NEXUS_T_MUX 222 } i2c_nexus_type_t; 223 224 typedef enum { 225 /* 226 * This indicates that the nexus is discoverable and present in the 227 * global tree. 228 */ 229 I2C_NEXUS_F_DISC = 1 << 0 230 } i2c_nexus_flags_t; 231 232 struct i2c_nexus { 233 avl_node_t in_avl; 234 i2c_nexus_type_t in_type; 235 i2c_nexus_flags_t in_flags; 236 i2c_ctrl_t *in_ctrl; 237 char in_name[I2C_NAME_MAX]; 238 char in_addr[I2C_NAME_MAX]; 239 id_t in_minor; 240 dev_info_t *in_dip; 241 dev_info_t *in_pdip; 242 i2c_nexus_t *in_pnex; 243 union { 244 i2c_port_t *in_port; 245 i2c_dev_t *in_dev; 246 i2c_mux_t *in_mux; 247 } in_data; 248 }; 249 250 /* 251 * This represents the root of an i2c controller tree. 252 */ 253 struct i2c_root { 254 list_node_t ir_link; 255 dev_info_t *ir_dip; 256 kmutex_t ir_mutex; 257 list_t ir_ctrls; 258 }; 259 260 /* 261 * Various debugging tags that indicate where we were trying to create an i2c 262 * transaction. 263 */ 264 typedef enum { 265 I2C_LOCK_TAG_MUX_REG, 266 I2C_LOCK_TAG_MUX_UNREG, 267 I2C_LOCK_TAG_BUS_CONFIG, 268 I2C_LOCK_TAG_BUS_UNCONFIG, 269 I2C_LOCK_TAG_DIP_DETACH, 270 I2C_LOCK_TAG_CLIENT_LOCK, 271 I2C_LOCK_TAG_CLIENT_ALLOC, 272 I2C_LOCK_TAG_CLIENT_ADDR, 273 I2C_LOCK_TAG_CLIENT_DESTROY, 274 I2C_LOCK_TAG_USER_IO, 275 I2C_LOCK_TAG_USER_DEV_ADD, 276 I2C_LOCK_TAG_USER_DEV_INFO, 277 I2C_LOCK_TAG_USER_DEV_RM, 278 I2C_LOCK_TAG_USER_PROP_INFO, 279 I2C_LOCK_TAG_USER_PROP_SET 280 } i2c_txn_tag_t; 281 282 typedef enum { 283 I2C_TXN_STATE_UNLOCKED = 0, 284 I2C_TXN_STATE_BLOCKED, 285 I2C_TXN_STATE_ACQUIRED 286 } i2c_txn_state_t; 287 288 /* 289 * This data structure represents an i2c transaction structure which is used to 290 * wait on and acquire exclusive access to a controller. 291 */ 292 typedef struct i2c_txn { 293 list_node_t txn_link; 294 list_node_t txn_wait_link; 295 list_node_t txn_stack_link; 296 i2c_ctrl_t *txn_ctrl; 297 kcondvar_t txn_cv; 298 i2c_txn_state_t txn_state; 299 i2c_errno_t txn_err; 300 /* 301 * Misc. debugging information. None of this may be relied upon for 302 * correct operation of lock information. The kthread_t and pid that 303 * acquired this may not be the same as the one that is actually later 304 * performing I/O and using it. Note, that txn_last_change is used for 305 * some correctness assertions. 306 */ 307 i2c_txn_tag_t txn_tag; 308 const void *txn_debug; 309 hrtime_t txn_last_change; 310 uintptr_t txn_alloc_kthread; 311 uintptr_t txn_acq_kthread; 312 pid_t txn_acq_pid; 313 } i2c_txn_t; 314 315 typedef enum { 316 /* 317 * This flag indicates that this minor currently holds its controller 318 * through a persistent ioctl (which isn't quite present). When this is 319 * the case, individual I/O operations don't need to acquire and release 320 * the bus. 321 */ 322 I2C_USER_F_CTRL_LOCK = 1 << 0, 323 /* 324 * This flag indicates that this minor is actively trying to perform 325 * I/O, manipulate the set of devices on the bus, etc. A thread may only 326 * hold this for the duration of a single ioctl. The thread that has set 327 * this will be noted in the iu_thread member. 328 */ 329 I2C_USER_F_ACTIVE = 1 << 1, 330 /* 331 * This flag indicates that we took the controller lock as part of this 332 * operation and therefore need to make sure that we release it. This 333 * can only be set if the I2C_USER_F_ACTIVE flag is set. 334 */ 335 I2C_USER_F_LOCK = 1 << 2 336 } i2c_user_flags_t; 337 338 /* 339 * This tracks information about an individual minor data that a user may have 340 * open. The user-specific information is protected by the corresponding 341 * controller's lock. A given user structure is always tied to some controller 342 * per the i2c_nexus_t pointer. 343 */ 344 typedef struct i2c_user { 345 /* 346 * This links the minor open instance in the global im_users. It is only 347 * manipulated while the minors im_muex is held. 348 */ 349 avl_node_t iu_avl; 350 /* 351 * These values are set at initial creation time and contain information 352 * about what device this is actually bound to. 353 */ 354 id_t iu_minor; 355 i2c_nexus_t *iu_nexus; 356 /* 357 * Dynamic data that is protected by the following mutex. 358 */ 359 kmutex_t iu_mutex; 360 i2c_txn_t *iu_txn; 361 i2c_user_flags_t iu_flags; 362 uintptr_t iu_thread; 363 } i2c_user_t; 364 365 typedef enum { 366 367 /* 368 * Indicates that this client has a claimed and/or shared address that 369 * should be released when it is freed and that the address doesn't 370 * belong to the device directly. 371 */ 372 I2C_CLIENT_F_CLAIM_ADDR = 1 << 0, 373 I2C_CLIENT_F_SHARED_ADDR = 1 << 1, 374 /* 375 * Indicates that the current I/O operation created the transaction for 376 * us. 377 */ 378 I2C_CLIENT_F_ALLOC_TXN = 1 << 2 379 } i2c_client_flags_t; 380 381 /* 382 * Structure used for kernel device driver consumers. 383 */ 384 typedef struct i2c_client { 385 list_node_t icli_dev_link; 386 dev_info_t *icli_dip; 387 i2c_addr_t icli_addr; 388 i2c_dev_t *icli_dev; 389 i2c_ctrl_t *icli_ctrl; 390 i2c_port_t *icli_io_port; 391 /* 392 * The icli_mutex is used to protect the fields below. 393 */ 394 kmutex_t icli_mutex; 395 i2c_client_flags_t icli_flags; 396 list_t icli_regs; 397 i2c_txn_t *icli_txn; 398 uintptr_t icli_curthread; 399 union { 400 smbus_req_t req_smbus; 401 i2c_req_t req_i2c; 402 } icli_reqs; 403 } i2c_client_t; 404 405 struct i2c_reg_hdl { 406 list_node_t reg_link; 407 i2c_client_t *reg_client; 408 i2c_reg_acc_attr_t reg_attr; 409 uint32_t reg_max_nread; 410 uint32_t reg_max_nwrite; 411 }; 412 413 /* 414 * Access to our global data and minor mapping. 415 */ 416 extern i2cnex_minors_t i2cnex_minors; 417 418 /* 419 * Shared bus_ops. 420 */ 421 extern struct bus_ops i2c_nex_bus_ops; 422 423 /* 424 * Misc. internal functions. 425 */ 426 extern i2c_root_t *i2c_dip_to_root(dev_info_t *); 427 extern i2c_root_t *i2c_root_init(dev_info_t *); 428 extern void i2c_root_fini(i2c_root_t *); 429 430 extern i2c_nexus_t *i2cnex_nex_alloc(i2c_nexus_type_t, dev_info_t *, 431 i2c_nexus_t *, const char *, const char *, i2c_ctrl_t *); 432 extern void i2cnex_nex_free(i2c_nexus_t *); 433 extern i2c_nexus_t *i2c_nex_find_by_minor(minor_t); 434 435 typedef struct { 436 bool inbc_matched; 437 ddi_bus_config_op_t inbc_op; 438 const void *inbc_arg; 439 int inbc_ret; 440 char *inbc_dup; 441 size_t inbc_duplen; 442 const char *inbc_name; 443 const char *inbc_addr; 444 } i2c_nex_bus_config_t; 445 446 extern int i2c_nex_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 447 void *); 448 extern bool i2c_nex_bus_config_init(i2c_nex_bus_config_t *, ddi_bus_config_op_t, 449 const void *); 450 extern void i2c_nex_bus_config_fini(i2c_nex_bus_config_t *); 451 extern void i2c_nex_bus_config_one(i2c_nexus_t *, i2c_nex_bus_config_t *); 452 extern void i2c_nex_bus_unconfig_one(i2c_nexus_t *, i2c_nex_bus_config_t *); 453 extern void i2c_nex_dev_cleanup(i2c_nexus_t *); 454 455 /* 456 * User Character Device Operations 457 */ 458 extern int i2c_nex_open(dev_t *, int, int, cred_t *); 459 extern int i2c_nex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 460 extern int i2c_nex_close(dev_t, int, int, cred_t *); 461 462 /* 463 * Error signaling back to clients. 464 */ 465 extern bool i2c_error(i2c_error_t *, i2c_errno_t, i2c_ctrl_error_t); 466 extern void i2c_success(i2c_error_t *); 467 468 /* 469 * Locking operations. 470 */ 471 extern i2c_txn_t *i2c_txn_alloc(i2c_ctrl_t *, i2c_txn_tag_t, const void *); 472 extern i2c_errno_t i2c_txn_ctrl_lock(i2c_txn_t *, bool); 473 extern bool i2c_txn_held(i2c_txn_t *); 474 extern void i2c_txn_nexus_op_begin(i2c_txn_t *); 475 extern void i2c_txn_nexus_op_end(i2c_txn_t *); 476 extern void i2c_txn_ctrl_unlock(i2c_txn_t *); 477 extern void i2c_txn_free(i2c_txn_t *); 478 479 /* 480 * I/O operations. These require the controller lock. 481 */ 482 extern bool i2c_ctrl_io_smbus(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *, 483 smbus_req_t *); 484 extern bool i2c_ctrl_io_i2c(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *, 485 i2c_req_t *); 486 487 /* 488 * Mux related functions. 489 */ 490 extern bool i2c_mux_update(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *, 491 i2c_error_t *); 492 extern void i2c_mux_remove_port(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *); 493 494 /* 495 * Address allocations. 496 */ 497 extern bool i2c_addr_alloc(i2c_port_t *, const i2c_addr_t *, 498 i2c_error_t *); 499 extern void i2c_addr_free(i2c_port_t *, const i2c_addr_t *); 500 extern bool i2c_addr_alloc_shared(i2c_port_t *, const i2c_addr_t *, 501 major_t, i2c_error_t *); 502 extern void i2c_addr_free_shared(i2c_port_t *, const i2c_addr_t *, 503 major_t); 504 extern void i2c_addr_info_7b(const i2c_port_t *, ui2c_port_info_t *); 505 506 /* 507 * Device related functions. 508 */ 509 extern i2c_dev_t *i2c_device_find_by_addr(i2c_txn_t *, i2c_port_t *, 510 const i2c_addr_t *); 511 extern i2c_dev_t *i2c_device_init(i2c_txn_t *, i2c_port_t *, const i2c_addr_t *, 512 const char *, char *const *, uint_t, i2c_error_t *); 513 extern bool i2c_device_config(i2c_port_t *, i2c_dev_t *); 514 extern bool i2c_device_unconfig(i2c_port_t *, i2c_dev_t *); 515 extern void i2c_device_fini(i2c_txn_t *, i2c_port_t *, i2c_dev_t *); 516 517 /* 518 * Misc. client related functions that are shared. 519 */ 520 extern bool i2c_dip_is_dev(dev_info_t *); 521 extern i2c_nexus_t *i2c_dev_to_nexus(dev_info_t *); 522 523 /* 524 * Validation functions shared across user / client requests. 525 */ 526 extern bool i2c_addr_validate(const i2c_addr_t *, i2c_error_t *); 527 528 /* 529 * Iterate over all parent ports that are above this entry. Note, there may be 530 * none and therefore the function may not be called. The callback will not be 531 * called for the starting port. 532 */ 533 typedef bool (*i2c_port_f)(i2c_port_t *, void *); 534 extern void i2c_port_parent_iter(i2c_port_t *, i2c_port_f, void *); 535 extern void i2c_port_iter(i2c_port_t *, i2c_port_f, void *); 536 537 /* 538 * Property Interfaces. 539 */ 540 extern uint16_t i2c_prop_nstd(); 541 extern const char *i2c_prop_name(i2c_prop_t); 542 extern bool i2c_prop_info(i2c_ctrl_t *, ui2c_prop_info_t *); 543 extern bool i2c_prop_get(i2c_ctrl_t *, i2c_prop_t, void *, uint32_t *, 544 i2c_error_t *); 545 extern bool i2c_prop_set(i2c_txn_t *, i2c_ctrl_t *, i2c_prop_t, const void *, 546 uint32_t, i2c_error_t *); 547 548 #ifdef __cplusplus 549 } 550 #endif 551 552 #endif /* _I2CNEX_H */ 553