1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2010, Intel Corporation. 27 * All rights reserved. 28 */ 29 30 /* 31 * Copyright 2023 Oxide Computer Company 32 */ 33 34 #ifndef _SYS_DR_H 35 #define _SYS_DR_H 36 #include <sys/types.h> 37 #include <sys/note.h> 38 #include <sys/processor.h> 39 #include <sys/obpdefs.h> 40 #include <sys/memlist.h> 41 #include <sys/mem_config.h> 42 #include <sys/param.h> /* for MAXPATHLEN */ 43 #include <sys/varargs.h> 44 #include <sys/sbd_ioctl.h> 45 #include <sys/dr_util.h> 46 #include <sys/drmach.h> 47 48 #ifdef __cplusplus 49 extern "C" { 50 #endif 51 52 /* 53 * helper macros for constructing and reporting internal error messages. 54 * NOTE: each module which uses one or more this these macros is expected 55 * to supply a char *dr_ie_fmt string containing the SCCS filename 56 * expansion macro (percent M percent) and a sprintf %d to render the 57 * line number argument. 58 */ 59 #define DR_INTERNAL_ERROR(hp) \ 60 drerr_new(1, ESBD_INTERNAL, dr_ie_fmt, __LINE__) 61 62 #define DR_OP_INTERNAL_ERROR(hp) \ 63 drerr_set_c(CE_WARN, &(hp)->h_err, \ 64 ESBD_INTERNAL, dr_ie_fmt, __LINE__) 65 66 #define DR_DEV_INTERNAL_ERROR(cp) \ 67 drerr_set_c(CE_WARN, &(cp)->sbdev_error, \ 68 ESBD_INTERNAL, dr_ie_fmt, __LINE__) 69 70 /* 71 * Macros for keeping an error code and an associated list of integers. 72 */ 73 #define DR_MAX_ERR_INT (32) 74 #define DR_GET_E_CODE(sep) ((sep)->e_code) 75 #define DR_SET_E_CODE(sep, en) ((sep)->e_code = (en)) 76 #define DR_GET_E_RSC(sep) ((sep)->e_rsc) 77 78 /* Number of device node types. */ 79 #define DR_MAXNUM_NT 3 80 81 /* used to map sbd_comp_type_t to array index */ 82 #define DEVSET_NIX(t) \ 83 (((t) == SBD_COMP_CPU) ? 0 : \ 84 ((t) == SBD_COMP_MEM) ? 1 : \ 85 ((t) == SBD_COMP_IO) ? 2 : \ 86 ((t) == SBD_COMP_CMP) ? 0 : DR_MAXNUM_NT) 87 88 /* 89 * Format of dr_devset_t bit masks: 90 * 91 * 64 56 48 40 32 24 16 8 0 92 * |....|IIII|IIII|IIII|IIII|MMMM|MMMM|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC| 93 * 94 * 1 = indicates respective component present/attached. 95 * I = I/O, M = Memory, C = CPU. 96 */ 97 #define DEVSET_CPU_OFFSET 0 98 #define DEVSET_CPU_NUMBER 32 99 #define DEVSET_MEM_OFFSET (DEVSET_CPU_OFFSET + DEVSET_CPU_NUMBER) 100 #define DEVSET_MEM_NUMBER 8 101 #define DEVSET_IO_OFFSET (DEVSET_MEM_OFFSET + DEVSET_MEM_NUMBER) 102 #define DEVSET_IO_NUMBER 16 103 #define DEVSET_MAX_BITS (DEVSET_IO_OFFSET + DEVSET_IO_NUMBER) 104 105 #define DEVSET_BIX(t) \ 106 (((t) == SBD_COMP_CPU) ? DEVSET_CPU_OFFSET : \ 107 ((t) == SBD_COMP_MEM) ? DEVSET_MEM_OFFSET : \ 108 ((t) == SBD_COMP_IO) ? DEVSET_IO_OFFSET : \ 109 ((t) == SBD_COMP_CMP) ? DEVSET_CPU_OFFSET : 0) 110 111 #define DEVSET_NT2DEVPOS(t, u) (((t) == SBD_COMP_CMP) ?\ 112 (DEVSET_BIX(t) + (u) * MAX_CORES_PER_CMP) : DEVSET_BIX(t) + (u)) 113 114 #if (DEVSET_MAX_BITS <= 64) 115 typedef uint64_t dr_devset_t; 116 117 #define DEVSET_ONEUNIT ((dr_devset_t)1) 118 #define DEVSET_ANYUNIT ((dr_devset_t)(-1)) 119 #define DEVSET_CPU_NMASK ((dr_devset_t)((1ULL << DEVSET_CPU_NUMBER) - 1)) 120 #define DEVSET_MEM_NMASK ((dr_devset_t)((1ULL << DEVSET_MEM_NUMBER) - 1)) 121 #define DEVSET_IO_NMASK ((dr_devset_t)((1ULL << DEVSET_IO_NUMBER) - 1)) 122 #define DEVSET_CMP_NMASK ((dr_devset_t)((1ULL << MAX_CORES_PER_CMP) - 1)) 123 124 #define DEVSET_NMASK(t) \ 125 (((t) == SBD_COMP_CPU) ? DEVSET_CPU_NMASK : \ 126 ((t) == SBD_COMP_MEM) ? DEVSET_MEM_NMASK : \ 127 ((t) == SBD_COMP_IO) ? DEVSET_IO_NMASK : \ 128 ((t) == SBD_COMP_CMP) ? DEVSET_CPU_NMASK : 0) 129 130 #define DEVSET_MASK \ 131 ((DEVSET_CPU_NMASK << DEVSET_CPU_OFFSET) | \ 132 (DEVSET_MEM_NMASK << DEVSET_MEM_OFFSET) | \ 133 (DEVSET_IO_NMASK << DEVSET_IO_OFFSET)) 134 135 #define DEVSET(t, u) \ 136 (((u) == DEVSET_ANYUNIT) ? \ 137 ((DEVSET_NMASK(t) << DEVSET_NT2DEVPOS((t), 0)) & \ 138 DEVSET_MASK) : \ 139 ((t) == SBD_COMP_CMP) ? \ 140 (DEVSET_CMP_NMASK << DEVSET_NT2DEVPOS((t), (u))) : \ 141 (DEVSET_ONEUNIT << DEVSET_NT2DEVPOS((t), (u)))) 142 143 #define DEVSET_IS_NULL(ds) ((ds) == 0) 144 #define DEVSET_IN_SET(ds, t, u) (((ds) & DEVSET((t), (u))) != 0) 145 #define DEVSET_ADD(ds, t, u) ((ds) |= DEVSET((t), (u))) 146 #define DEVSET_DEL(ds, t, u) ((ds) &= ~DEVSET((t), (u))) 147 #define DEVSET_AND(ds1, ds2) ((ds1) & (ds2)) 148 #define DEVSET_OR(ds1, ds2) ((ds1) | (ds2)) 149 #define DEVSET_NAND(ds1, ds2) ((ds1) & ~(ds2)) 150 #define DEVSET_GET_UNITSET(ds, t) \ 151 (((ds) & DEVSET((t), DEVSET_ANYUNIT)) >> DEVSET_NT2DEVPOS((t), 0)) 152 #define DEVSET_FMT_STR "0x%" PRIx64 "" 153 #define DEVSET_FMT_ARG(ds) (ds) 154 #else /* DEVSET_MAX_BITS <= 64 */ 155 #error please implement devset with bitmap to support more 64 devices 156 #endif /* DEVSET_MAX_BITS <= 64 */ 157 158 /* 159 * Ops for dr_board_t.b_dev_* 160 */ 161 #define DR_DEV_IS(ds, cp) DEVSET_IN_SET( \ 162 (cp)->sbdev_bp->b_dev_##ds, \ 163 (cp)->sbdev_type, \ 164 (cp)->sbdev_unum) 165 166 #define DR_DEV_ADD(ds, cp) DEVSET_ADD( \ 167 (cp)->sbdev_bp->b_dev_##ds, \ 168 (cp)->sbdev_type, \ 169 (cp)->sbdev_unum) 170 171 #define DR_DEV_DEL(ds, cp) DEVSET_DEL( \ 172 (cp)->sbdev_bp->b_dev_##ds, \ 173 (cp)->sbdev_type, \ 174 (cp)->sbdev_unum) 175 176 /* 177 * Ops for dr_board_t.b_dev_present 178 */ 179 #define DR_DEV_IS_PRESENT(cp) DR_DEV_IS(present, cp) 180 #define DR_DEV_SET_PRESENT(cp) DR_DEV_ADD(present, cp) 181 #define DR_DEV_CLR_PRESENT(cp) DR_DEV_DEL(present, cp) 182 183 /* 184 * Ops for dr_board_t.b_dev_attached 185 */ 186 #define DR_DEV_IS_ATTACHED(cp) DR_DEV_IS(attached, cp) 187 #define DR_DEV_SET_ATTACHED(cp) DR_DEV_ADD(attached, cp) 188 #define DR_DEV_CLR_ATTACHED(cp) DR_DEV_DEL(attached, cp) 189 190 /* 191 * Ops for dr_board_t.b_dev_released 192 */ 193 #define DR_DEV_IS_RELEASED(cp) DR_DEV_IS(released, cp) 194 #define DR_DEV_SET_RELEASED(cp) DR_DEV_ADD(released, cp) 195 #define DR_DEV_CLR_RELEASED(cp) DR_DEV_DEL(released, cp) 196 197 /* 198 * Ops for dr_board_t.b_dev_unreferenced 199 */ 200 #define DR_DEV_IS_UNREFERENCED(cp) DR_DEV_IS(unreferenced, cp) 201 #define DR_DEV_SET_UNREFERENCED(cp) DR_DEV_ADD(unreferenced, cp) 202 #define DR_DEV_CLR_UNREFERENCED(cp) DR_DEV_DEL(unreferenced, cp) 203 204 #define DR_DEVS_PRESENT(bp) \ 205 ((bp)->b_dev_present) 206 #define DR_DEVS_ATTACHED(bp) \ 207 ((bp)->b_dev_attached) 208 #define DR_DEVS_RELEASED(bp) \ 209 ((bp)->b_dev_released) 210 #define DR_DEVS_UNREFERENCED(bp) \ 211 ((bp)->b_dev_unreferenced) 212 #define DR_DEVS_UNATTACHED(bp) \ 213 ((bp)->b_dev_present & ~(bp)->b_dev_attached) 214 #define DR_DEVS_CONFIGURE(bp, devs) \ 215 ((bp)->b_dev_attached = (devs)) 216 #define DR_DEVS_DISCONNECT(bp, devs) \ 217 ((bp)->b_dev_present &= ~(devs)) 218 #define DR_DEVS_CANCEL(bp, devs) \ 219 ((bp)->b_dev_released &= ~(devs), \ 220 (bp)->b_dev_unreferenced &= ~(devs)) 221 222 /* 223 * CMP Specific Helpers 224 */ 225 #define DR_CMP_CORE_UNUM(cmp, core) ((cmp) * MAX_CORES_PER_CMP + (core)) 226 227 /* 228 * For CPU and CMP devices, DR_UNUM2SBD_UNUM is used to extract the physical 229 * CPU/CMP id from the device id. 230 */ 231 #define DR_UNUM2SBD_UNUM(n, d) \ 232 ((d) == SBD_COMP_CPU ? ((n) / MAX_CORES_PER_CMP) : \ 233 (d) == SBD_COMP_CMP ? ((n) / MAX_CORES_PER_CMP) : (n)) 234 235 /* 236 * Some stuff to assist in debug. 237 */ 238 #ifdef DEBUG 239 #define DRDBG_STATE 0x00000001 240 #define DRDBG_QR 0x00000002 241 #define DRDBG_CPU 0x00000004 242 #define DRDBG_MEM 0x00000008 243 #define DRDBG_IO 0x00000010 244 245 #define PR_ALL if (dr_debug) printf 246 #define PR_STATE if (dr_debug & DRDBG_STATE) printf 247 #define PR_QR if (dr_debug & DRDBG_QR) prom_printf 248 #define PR_CPU if (dr_debug & DRDBG_CPU) printf 249 #define PR_MEM if (dr_debug & DRDBG_MEM) printf 250 #define PR_IO if (dr_debug & DRDBG_IO) printf 251 #define PR_MEMLIST_DUMP if (dr_debug & DRDBG_MEM) MEMLIST_DUMP 252 253 extern uint_t dr_debug; 254 #else /* DEBUG */ 255 #define PR_ALL _NOTE(CONSTANTCONDITION) if (0) printf 256 #define PR_STATE PR_ALL 257 #define PR_QR PR_ALL 258 #define PR_CPU PR_ALL 259 #define PR_MEM PR_ALL 260 #define PR_IO PR_ALL 261 #define PR_MEMLIST_DUMP _NOTE(CONSTANTCONDITION) if (0) MEMLIST_DUMP 262 263 #endif /* DEBUG */ 264 265 /* 266 * dr_board_t b_sflags. 267 */ 268 #define DR_BSLOCK 0x01 /* for blocking status (protected by b_slock) */ 269 270 typedef const char *fn_t; 271 272 /* 273 * Unsafe devices based on dr.conf prop "unsupported-io-drivers" 274 */ 275 typedef struct { 276 char **devnames; 277 uint_t ndevs; 278 } dr_unsafe_devs_t; 279 280 /* 281 * Device states. 282 * PARTIAL state is really only relevant for board state. 283 */ 284 typedef enum { 285 DR_STATE_EMPTY = 0, 286 DR_STATE_OCCUPIED, 287 DR_STATE_CONNECTED, 288 DR_STATE_UNCONFIGURED, 289 DR_STATE_PARTIAL, /* part connected, part configured */ 290 DR_STATE_CONFIGURED, 291 DR_STATE_RELEASE, 292 DR_STATE_UNREFERENCED, 293 DR_STATE_FATAL, 294 DR_STATE_MAX 295 } dr_state_t; 296 297 typedef struct dr_handle { 298 struct dr_board *h_bd; 299 sbd_error_t *h_err; 300 int h_op_intr; /* nz if op interrupted */ 301 dev_t h_dev; /* dev_t of opened device */ 302 int h_cmd; /* PIM ioctl argument */ 303 int h_mode; /* device open mode */ 304 sbd_cmd_t h_sbdcmd; /* copied-in ioctl cmd struct */ 305 sbd_ioctl_arg_t *h_iap; /* ptr to caller-space cmd struct */ 306 dr_devset_t h_devset; /* based on h_dev */ 307 drmach_opts_t h_opts; /* command-line platform options */ 308 } dr_handle_t; 309 310 typedef struct dr_common_unit { 311 dr_state_t sbdev_state; 312 sbd_state_t sbdev_ostate; 313 sbd_cond_t sbdev_cond; 314 time_t sbdev_time; 315 int sbdev_busy; 316 struct dr_board *sbdev_bp; 317 int sbdev_unum; 318 sbd_comp_type_t sbdev_type; 319 drmachid_t sbdev_id; 320 char sbdev_path[MAXNAMELEN]; 321 sbd_error_t *sbdev_error; 322 } dr_common_unit_t; 323 324 typedef struct dr_mem_unit { 325 dr_common_unit_t sbm_cm; /* mem-unit state */ 326 uint_t sbm_flags; 327 pfn_t sbm_basepfn; 328 pgcnt_t sbm_npages; 329 pgcnt_t sbm_pageslost; 330 struct memlist *sbm_dyn_segs; /* kphysm_add_dynamic segs */ 331 /* 332 * The following fields are used during 333 * the memory detach process only. sbm_mlist 334 * will be used to store the board memlist 335 * following a detach. The memlist will be 336 * used to re-attach the board when configuring 337 * the unit directly after an unconfigure. 338 */ 339 struct dr_mem_unit *sbm_peer; 340 struct memlist *sbm_mlist; 341 struct memlist *sbm_del_mlist; 342 memhandle_t sbm_memhandle; 343 uint64_t sbm_alignment_mask; 344 uint64_t sbm_slice_base; 345 uint64_t sbm_slice_top; 346 uint64_t sbm_slice_size; 347 } dr_mem_unit_t; 348 349 /* 350 * Currently only maintain state information for individual 351 * components. 352 */ 353 typedef struct dr_cpu_unit { 354 dr_common_unit_t sbc_cm; /* cpu-unit state */ 355 processorid_t sbc_cpu_id; 356 cpu_flag_t sbc_cpu_flags; /* snapshot of CPU flags */ 357 ushort_t sbc_pad1; /* padded for compatibility */ 358 int sbc_speed; 359 int sbc_ecache; 360 int sbc_cpu_impl; 361 } dr_cpu_unit_t; 362 363 typedef struct dr_io_unit { 364 dr_common_unit_t sbi_cm; /* io-unit state */ 365 } dr_io_unit_t; 366 367 typedef union { 368 dr_common_unit_t du_common; 369 dr_mem_unit_t du_mem; 370 dr_cpu_unit_t du_cpu; 371 dr_io_unit_t du_io; 372 } dr_dev_unit_t; 373 374 typedef struct dr_board { 375 kmutex_t b_lock; /* lock for this board struct */ 376 kmutex_t b_slock; /* lock for status on the board */ 377 kcondvar_t b_scv; /* condvar for status on the board */ 378 int b_sflags; /* for serializing status */ 379 sbd_state_t b_rstate; /* board's cfgadm receptacle state */ 380 sbd_state_t b_ostate; /* board's cfgadm occupant state */ 381 sbd_cond_t b_cond; /* cfgadm condition */ 382 int b_busy; 383 int b_assigned; 384 time_t b_time; /* time of last board operation */ 385 char b_type[MAXNAMELEN]; 386 drmachid_t b_id; 387 int b_num; /* board number */ 388 int b_ndev; /* # of devices on board */ 389 dev_info_t *b_dip; /* dip for make-nodes */ 390 dr_state_t b_state; /* board DR state */ 391 dr_devset_t b_dev_present; /* present mask */ 392 dr_devset_t b_dev_attached; /* attached mask */ 393 dr_devset_t b_dev_released; /* released mask */ 394 dr_devset_t b_dev_unreferenced; /* unreferenced mask */ 395 char b_path[MAXNAMELEN]; 396 dr_dev_unit_t *b_dev[DR_MAXNUM_NT]; 397 } dr_board_t; 398 399 /* 400 * dr_quiesce.c interfaces 401 */ 402 struct dr_sr_handle; 403 typedef struct dr_sr_handle dr_sr_handle_t; 404 405 extern dr_sr_handle_t *dr_get_sr_handle(dr_handle_t *handle); 406 extern void dr_release_sr_handle(dr_sr_handle_t *srh); 407 extern int dr_suspend(dr_sr_handle_t *srh); 408 extern void dr_resume(dr_sr_handle_t *srh); 409 extern void dr_check_devices(dev_info_t *dip, int *refcount, 410 dr_handle_t *handle, uint64_t *arr, int *idx, 411 int len, int *refcount_non_gldv3); 412 extern int dr_pt_test_suspend(dr_handle_t *hp); 413 414 /* 415 * dr_cpu.c interface 416 */ 417 extern void dr_init_cpu_unit(dr_cpu_unit_t *cp); 418 extern int dr_pre_attach_cpu(dr_handle_t *hp, 419 dr_common_unit_t **devlist, int devnum); 420 extern void dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp); 421 extern int dr_post_attach_cpu(dr_handle_t *hp, 422 dr_common_unit_t **devlist, int devnum); 423 extern int dr_pre_release_cpu(dr_handle_t *hp, 424 dr_common_unit_t **devlist, int devnum); 425 extern int dr_pre_detach_cpu(dr_handle_t *hp, 426 dr_common_unit_t **devlist, int devnum); 427 extern void dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp); 428 extern int dr_post_detach_cpu(dr_handle_t *hp, 429 dr_common_unit_t **devlist, int devnum); 430 extern int dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, 431 sbd_dev_stat_t *dsp); 432 extern int dr_cancel_cpu(dr_cpu_unit_t *cp); 433 extern int dr_disconnect_cpu(dr_cpu_unit_t *cp); 434 435 436 /* 437 * dr_mem.c interface 438 */ 439 extern void dr_init_mem_unit(dr_mem_unit_t *mp); 440 extern int dr_pre_attach_mem(dr_handle_t *hp, 441 dr_common_unit_t **devlist, int devnum); 442 extern void dr_attach_mem(dr_handle_t *hp, dr_common_unit_t *cp); 443 extern int dr_post_attach_mem(dr_handle_t *hp, 444 dr_common_unit_t **devlist, int devnum); 445 extern int dr_pre_release_mem(dr_handle_t *hp, 446 dr_common_unit_t **devlist, int devnum); 447 extern void dr_release_mem(dr_common_unit_t *cp); 448 extern void dr_release_mem_done(dr_common_unit_t *cp); 449 extern int dr_pre_detach_mem(dr_handle_t *hp, 450 dr_common_unit_t **devlist, int devnum); 451 extern void dr_detach_mem(dr_handle_t *, dr_common_unit_t *); 452 extern int dr_post_detach_mem(dr_handle_t *hp, 453 dr_common_unit_t **devlist, int devnum); 454 extern int dr_mem_status(dr_handle_t *hp, dr_devset_t devset, 455 sbd_dev_stat_t *dsp); 456 extern int dr_cancel_mem(dr_mem_unit_t *mp); 457 extern int dr_disconnect_mem(dr_mem_unit_t *mp); 458 459 /* 460 * dr_io.c interface 461 */ 462 extern void dr_init_io_unit(dr_io_unit_t *io); 463 extern int dr_pre_attach_io(dr_handle_t *hp, 464 dr_common_unit_t **devlist, int devnum); 465 extern void dr_attach_io(dr_handle_t *hp, dr_common_unit_t *cp); 466 extern int dr_post_attach_io(dr_handle_t *hp, 467 dr_common_unit_t **devlist, int devnum); 468 extern int dr_pre_release_io(dr_handle_t *hp, 469 dr_common_unit_t **devlist, int devnum); 470 extern int dr_pre_detach_io(dr_handle_t *hp, 471 dr_common_unit_t **devlist, int devnum); 472 extern void dr_detach_io(dr_handle_t *hp, dr_common_unit_t *cp); 473 extern int dr_post_detach_io(dr_handle_t *hp, 474 dr_common_unit_t **devlist, int devnum); 475 extern int dr_io_status(dr_handle_t *hp, dr_devset_t devset, 476 sbd_dev_stat_t *dsp); 477 extern int dr_disconnect_io(dr_io_unit_t *ip); 478 479 480 /* 481 * dr.c interface 482 */ 483 extern void dr_op_err(int ce, dr_handle_t *hp, int code, char *fmt, ...); 484 extern void dr_dev_err(int ce, dr_common_unit_t *cp, int code); 485 486 extern dr_cpu_unit_t *dr_get_cpu_unit(dr_board_t *bp, int unit_num); 487 extern dr_mem_unit_t *dr_get_mem_unit(dr_board_t *bp, int unit_num); 488 extern dr_io_unit_t *dr_get_io_unit(dr_board_t *bp, int unit_num); 489 490 extern dr_board_t *dr_lookup_board(int board_num); 491 extern int dr_release_dev_done(dr_common_unit_t *cp); 492 extern char *dr_nt_to_dev_type(int type); 493 extern void dr_device_transition(dr_common_unit_t *cp, 494 dr_state_t new_state); 495 extern void dr_lock_status(dr_board_t *bp); 496 extern void dr_unlock_status(dr_board_t *bp); 497 extern int dr_cmd_flags(dr_handle_t *hp); 498 499 #ifdef __cplusplus 500 } 501 #endif 502 503 #endif /* _SYS_DR_H */ 504