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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2023 Oxide Computer Company 25 */ 26 27 #ifndef _SYS_PCIE_HP_H 28 #define _SYS_PCIE_HP_H 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #ifdef _KERNEL 35 #include <sys/ddi_hp.h> 36 #include <sys/pcie_impl.h> 37 #include <sys/stdbool.h> 38 #endif /* _KERNEL */ 39 #include "../../../../../common/pci/pci_strings.h" 40 #include <sys/hotplug/pci/pcihp.h> 41 42 #define PCIEHPC_PROP_HELP "help" 43 #define PCIEHPC_PROP_ALL "all" 44 #define PCIEHPC_PROP_LED_FAULT "fault_led" 45 #define PCIEHPC_PROP_LED_POWER "power_led" 46 #define PCIEHPC_PROP_LED_ATTN "attn_led" 47 #define PCIEHPC_PROP_LED_ACTIVE "active_led" 48 #define PCIEHPC_PROP_CARD_TYPE "card_type" 49 #define PCIEHPC_PROP_BOARD_TYPE "board_type" 50 #define PCIEHPC_PROP_SLOT_CONDITION "slot_condition" 51 52 #define PCIEHPC_PROP_VALUE_UNKNOWN "unknown" 53 #define PCIEHPC_PROP_VALUE_ON "on" 54 #define PCIEHPC_PROP_VALUE_OFF "off" 55 #define PCIEHPC_PROP_VALUE_BLINK "blink" 56 #define PCIEHPC_PROP_VALUE_DEFAULT "default" 57 #define PCIEHPC_PROP_VALUE_PCIHOTPLUG "pci hotplug" 58 #define PCIEHPC_PROP_VALUE_OK "ok" 59 #define PCIEHPC_PROP_VALUE_FAILING "failing" 60 #define PCIEHPC_PROP_VALUE_FAILED "failed" 61 #define PCIEHPC_PROP_VALUE_UNUSABLE "unusable" 62 #define PCIEHPC_PROP_VALUE_LED "<on|off|blink>" 63 #define PCIEHPC_PROP_VALUE_LED_DEF "<on|off|blink|default>" 64 #define PCIEHPC_PROP_VALUE_TYPE "<type description>" 65 #define PCIEHPC_PROP_VALUE_CONDITION "<unknown|ok|failing|failed|unusable>" 66 67 /* condition */ 68 #define PCIEHPC_PROP_COND_OK "ok" 69 #define PCIEHPC_PROP_COND_FAILING "failing" 70 #define PCIEHPC_PROP_COND_FAILED "failed" 71 #define PCIEHPC_PROP_COND_UNUSABLE "unusable" 72 #define PCIEHPC_PROP_COND_UNKNOWN "unknown" 73 74 #ifdef _KERNEL 75 76 #define PCIE_HP_MAX_SLOTS 31 /* Max # of slots */ 77 #define PCIE_HP_CMD_WAIT_TIME 10000 /* Delay in microseconds */ 78 #define PCIE_HP_CMD_WAIT_RETRY 100 /* Max retry count */ 79 #define PCIE_HP_DLL_STATE_CHANGE_TIMEOUT 1 /* Timeout in seconds */ 80 #define PCIE_HP_POWER_GOOD_WAIT_TIME 220000 /* Wait time after issuing a */ 81 /* cmd to change slot state */ 82 83 /* Definitions for PCIEHPC/PCISHPC */ 84 #define PCIE_NATIVE_HP_TYPE "PCIe-Native" /* PCIe Native type */ 85 #define PCIE_ACPI_HP_TYPE "PCIe-ACPI" /* PCIe ACPI type */ 86 #define PCIE_PROP_HP_TYPE "PCIe-Proprietary" /* PCIe Prop type */ 87 #define PCIE_PCI_HP_TYPE "PCI-SHPC" /* PCI (SHPC) type */ 88 89 #define PCIE_GET_HP_CTRL(dip) \ 90 (pcie_hp_ctrl_t *)PCIE_DIP2BUS(dip)->bus_hp_ctrl 91 92 #define PCIE_SET_HP_CTRL(dip, ctrl_p) \ 93 (PCIE_DIP2BUS(dip)->bus_hp_ctrl) = (pcie_hp_ctrl_t *)ctrl_p 94 95 #define PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p) \ 96 ((bus_p->bus_hp_sup_modes & PCIE_ACPI_HP_MODE) || \ 97 (bus_p->bus_hp_sup_modes & PCIE_NATIVE_HP_MODE)) 98 99 #define PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p) \ 100 (bus_p->bus_hp_sup_modes & PCIE_PCI_HP_MODE) 101 102 #define PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p) \ 103 ((bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE) || \ 104 (bus_p->bus_hp_curr_mode == PCIE_NATIVE_HP_MODE)) 105 106 #define PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p) \ 107 (bus_p->bus_hp_curr_mode & PCIE_PCI_HP_MODE) 108 109 typedef struct pcie_hp_ctrl pcie_hp_ctrl_t; 110 typedef struct pcie_hp_slot pcie_hp_slot_t; 111 112 /* 113 * Maximum length of the string converted from the digital number of pci device 114 * number and function number, including the string's end mark. For example, 115 * device number 0 and function number 255 (ARI case), then the length is 116 * (1 + 3 + 1). 117 */ 118 #define PCIE_HP_DEV_FUNC_NUM_STRING_LEN 5 119 120 /* 121 * Length of the characters in a PCI port name. 122 * The format of the PCI port name is: pci.d,f where d is device number, f is 123 * function number. The constant string and characters are "pci." and ",". 124 */ 125 #define PCIE_HP_PORT_NAME_STRING_LEN 5 126 127 /* Platform specific ops (Native HP, ACPI, etc.) */ 128 typedef struct pcie_hp_ops { 129 /* initialize/setup hot plug controller hw */ 130 int (*init_hpc_hw)(pcie_hp_ctrl_t *ctrl_p); 131 132 /* uninitialize hot plug controller hw */ 133 int (*uninit_hpc_hw)(pcie_hp_ctrl_t *ctrl_p); 134 135 /* initialize slot information structure */ 136 int (*init_hpc_slotinfo)(pcie_hp_ctrl_t *ctrl_p); 137 138 /* uninitialize slot information structure */ 139 int (*uninit_hpc_slotinfo)(pcie_hp_ctrl_t *ctrl_p); 140 141 /* slot poweron */ 142 int (*poweron_hpc_slot)(pcie_hp_slot_t *slot_p, 143 ddi_hp_cn_state_t *result); 144 145 /* slot poweroff */ 146 /* uninitialize hot plug controller hw */ 147 int (*poweroff_hpc_slot)(pcie_hp_slot_t *slot_p, 148 ddi_hp_cn_state_t *result); 149 150 /* enable hot plug interrupts/events */ 151 int (*enable_hpc_intr)(pcie_hp_ctrl_t *ctrl_p); 152 153 /* disable hot plug interrupts/events */ 154 int (*disable_hpc_intr)(pcie_hp_ctrl_t *ctrl_p); 155 } pcie_hp_ops_t; 156 157 /* Slot occupant information structure */ 158 #define PCIE_HP_MAX_OCCUPANTS 128 159 typedef struct pcie_hp_occupant_info { 160 int i; 161 char *id[PCIE_HP_MAX_OCCUPANTS]; 162 } pcie_hp_occupant_info_t; 163 164 /* 165 * pcie_hp_led_t 166 * 167 * Type definitions for LED type. These are all the types of LEDs that the 168 * subsystem knows about; however, both PCIe and SHPC only implement the Power 169 * and Attention LEDs. 170 */ 171 typedef enum { 172 PCIE_HP_FAULT_LED, 173 PCIE_HP_POWER_LED, 174 PCIE_HP_ATTN_LED, 175 PCIE_HP_ACTIVE_LED 176 } pcie_hp_led_t; 177 178 /* 179 * pcie_hp_led_state_t 180 * 181 * Type definitions for LED state. This structure represents the underlying 182 * hardware state and not what we are using for tracking the meta state 183 * ourselves. 184 */ 185 typedef enum { 186 PCIE_HP_LED_OFF = 0, 187 PCIE_HP_LED_ON, 188 PCIE_HP_LED_BLINK 189 } pcie_hp_led_state_t; 190 191 /* 192 * The following enumerations and structures are used to track the way that we 193 * manage LEDs for the native PCIe hotplug subsystem. See the 'LED Management' 194 * section of the theory statement of uts/common/io/pciex/hotplug/pciehpc.c for 195 * more information. While this is all specific to the native PCIe 196 * implementation there and not used for the SHPC bits, because everything uses 197 * a shared structure for slots, we must track that here. 198 * 199 * Roughly the pcie_hp_led_act_t is used to describe what we can do to an LED in 200 * our table. The pciehpc_logical_led_t describes the different LED states that 201 * we can be in. Finally, the pciehpc_led_plat_id_t is yet another LED 202 * definition. This would be much simpler if the pcie_hp_led_t reflected 203 * reality. 204 */ 205 typedef enum pcie_hp_led_act { 206 PCIE_HLA_PASS, 207 PCIE_HLA_OFF, 208 PCIE_HLA_ON, 209 PCIE_HLA_BLINK 210 } pcie_hp_led_act_t; 211 212 typedef enum pciehpc_logical_led { 213 /* 214 * The base case here indicates what should happen when we have a slot 215 * without power and no device present. 216 */ 217 PCIE_LL_BASE = 0, 218 /* 219 * This is the state that the system should be in when a device is 220 * powered. 221 */ 222 PCIE_LL_POWERED, 223 /* 224 * This indicates what should happen when an explicit power transition 225 * has been requested. The standard PCIe activity is to blink the power 226 * LED. 227 */ 228 PCIE_LL_POWER_TRANSITION, 229 /* 230 * This is the activity to take when a device driver probe has failed. 231 * This lasts until another state transition or acknowledgement. 232 */ 233 PCIE_LL_PROBE_FAILED, 234 /* 235 * This is the activity to take when a power fault occurs. This will 236 * remain until a device is removed or an active state transition 237 * occurs. 238 */ 239 PCIE_LL_POWER_FAULT, 240 /* 241 * This is the activity to take when the attention button has been 242 * pushed during the 5 second window that is used to confirm behavior. 243 */ 244 PCIE_LL_ATTENTION_BUTTON 245 } pciehpc_logical_led_t; 246 247 #define PCIEHPC_LED_NSTATES 6 248 CTASSERT(PCIEHPC_LED_NSTATES == PCIE_LL_ATTENTION_BUTTON + 1); 249 250 typedef enum { 251 PCIEHPC_PLAT_ID_POWER, 252 PCIEHPC_PLAT_ID_ATTN 253 } pciehpc_led_plat_id_t; 254 255 #define PCIEHPC_LED_NLEDS 2 256 CTASSERT(PCIEHPC_LED_NLEDS == PCIEHPC_PLAT_ID_ATTN + 1); 257 258 typedef struct pciehpc_led_plat_state { 259 pcie_hp_led_act_t plps_acts[PCIEHPC_LED_NLEDS]; 260 } pciehpc_led_plat_state_t; 261 262 /* 263 * PCI and PCI Express Hotplug slot structure 264 */ 265 struct pcie_hp_slot { 266 uint32_t hs_num; /* Logical slot number */ 267 uint32_t hs_phy_slot_num; /* Physical slot number */ 268 uint32_t hs_device_num; /* PCI device num for slot */ 269 uint16_t hs_minor; /* Minor num for this slot */ 270 ddi_hp_cn_info_t hs_info; /* Slot information */ 271 ddi_hp_cn_state_t hs_state; /* Slot state */ 272 273 /* 274 * LED states are split into three groups. The first group is the state 275 * that we believe we should have set into hardware. This state is the 276 * only state the SHPC form of the hotplug controller uses. While there 277 * are four LEDs here, only two are actually supported by the SHPC and 278 * PCIe controllers: the attention and power LEDs. 279 * 280 * The subsequent two groups are only used by the PCIe backend. In the 281 * future we should consider whether or not these structures really 282 * should be shared by all hotplug backends (especially when we add the 283 * ACPI/PCI hotplug scheme that virtual machines use). 284 */ 285 pcie_hp_led_state_t hs_power_led_state; /* Power LED state */ 286 pcie_hp_led_state_t hs_attn_led_state; /* Attn LED state */ 287 pcie_hp_led_state_t hs_active_led_state; /* Active LED state */ 288 pcie_hp_led_state_t hs_fault_led_state; /* Fault LED state */ 289 290 /* 291 * The second of three LED groups. This is used to track when a user 292 * overrides an LED. This is separate from the third group so we can 293 * always return to the expected LED behavior when the override is 294 * disabled again. Currently only used by the PCIe backend. 295 */ 296 pcie_hp_led_state_t hs_power_usr_ovr_state; 297 pcie_hp_led_state_t hs_attn_usr_ovr_state; 298 bool hs_power_usr_ovr; 299 bool hs_attn_usr_ovr; 300 301 /* 302 * The final group of LED state. This array tracks logical events that 303 * have occurred in the hotplug controller. Higher indexed events that 304 * are true take priority over lower indexed ones. The actual mapping of 305 * states to LEDs is in hs_led_plat_conf. For more information see the 306 * pciehpc.c theory statement. 307 */ 308 bool hs_led_plat_en[PCIEHPC_LED_NSTATES]; 309 const pciehpc_led_plat_state_t *hs_led_plat_conf; 310 311 ap_condition_t hs_condition; /* Condition of the slot. */ 312 /* For cfgadm condition. */ 313 314 /* Synchronization variable(s) for hot plug events */ 315 kcondvar_t hs_attn_btn_cv; /* ATTN button pressed intr */ 316 boolean_t hs_attn_btn_pending; 317 kthread_t *hs_attn_btn_threadp; /* ATTN button event thread */ 318 boolean_t hs_attn_btn_thread_exit; 319 kcondvar_t hs_dll_active_cv; /* DLL State Changed intr */ 320 321 pcie_hp_ctrl_t *hs_ctrl; /* Hotplug ctrl for this slot */ 322 }; 323 324 /* 325 * Register ops for read/write of non-standard HPC (e.g: OPL platform). 326 */ 327 typedef struct pcie_hp_regops { 328 uint_t (*get)(void *cookie, off_t offset); 329 uint_t (*put)(void *cookie, off_t offset, uint_t val); 330 void *cookie; 331 } pcie_hp_regops_t; 332 333 /* 334 * PCI and PCI Express Hotplug controller structure 335 */ 336 struct pcie_hp_ctrl { 337 dev_info_t *hc_dip; /* DIP for HP controller */ 338 kmutex_t hc_mutex; /* Mutex for this ctrl */ 339 uint_t hc_flags; /* Misc flags */ 340 341 /* Slot information */ 342 pcie_hp_slot_t *hc_slots[PCIE_HP_MAX_SLOTS]; /* Slot pointers */ 343 boolean_t hc_has_attn; /* Do we have attn btn? */ 344 boolean_t hc_has_mrl; /* Do we have MRL? */ 345 boolean_t hc_has_pwr; /* Do we have a power ctl? */ 346 kcondvar_t hc_cmd_comp_cv; /* Command Completion intr */ 347 boolean_t hc_cmd_pending; /* Command completion pending */ 348 349 /* PCI Express Hotplug specific fields */ 350 boolean_t hc_has_emi_lock; /* Do we have EMI Lock? */ 351 boolean_t hc_dll_active_rep; /* Report DLL DL_Active state */ 352 taskqid_t hc_startup_sync; /* Startup synched? */ 353 pcie_hp_ops_t hc_ops; /* Platform specific ops */ 354 /* (Native, ACPI) */ 355 356 /* PCI Hotplug (SHPC) specific fields */ 357 uint32_t hc_num_slots_impl; /* # of HP Slots Implemented */ 358 uint32_t hc_num_slots_connected; /* # of HP Slots Connected */ 359 int hc_curr_bus_speed; /* Current Bus Speed */ 360 uint32_t hc_device_start; /* 1st PCI Device # */ 361 uint32_t hc_phys_start; /* 1st Phys Device # */ 362 uint32_t hc_device_increases; /* Device # Increases */ 363 boolean_t hc_arbiter_timeout; /* Got a Arb timeout IRQ */ 364 365 /* Register read/write ops for non-standard HPC (e.g: OPL) */ 366 pcie_hp_regops_t hc_regops; 367 368 /* Platform implementation specific data if any: ACPI, CK804,... */ 369 void *hc_misc_data; 370 }; 371 372 /* 373 * Control structure for tree walk during configure/unconfigure operation. 374 */ 375 typedef struct pcie_hp_cn_cfg_t { 376 void *slotp; 377 boolean_t flag; /* Flag to ignore errors */ 378 int rv; /* Return error code */ 379 dev_info_t *dip; /* dip at which the (first) */ 380 /* error occurred */ 381 void *cn_private; /* Connection specific data */ 382 } pcie_hp_cn_cfg_t; 383 384 /* 385 * arg for unregistering port of a pci bridge 386 */ 387 typedef struct pcie_hp_unreg_port { 388 /* pci bridge dip to which the port is associated */ 389 dev_info_t *nexus_dip; 390 /* 391 * Connector number of the physical slot whose dependent ports will be 392 * unregistered. If NULL, then all the ports of the pci bridge dip will 393 * be unregistered. 394 */ 395 int connector_num; 396 int rv; 397 } pcie_hp_unreg_port_t; 398 399 /* 400 * arg for getting a port's state 401 */ 402 typedef struct pcie_hp_port_state { 403 char *cn_name; 404 ddi_hp_cn_state_t cn_state; 405 int rv; 406 } pcie_hp_port_state_t; 407 408 /* hc_flags */ 409 #define PCIE_HP_INITIALIZED_FLAG (1 << 0) /* HPC initialized */ 410 /* 411 * These two flags are all related to initial synchronization. See 412 * uts/common/io/pciex/hotplug/pciehpc.c for more information. The first is used 413 * to track that this is required while the second indicates that it's actively 414 * occurring. 415 */ 416 #define PCIE_HP_SYNC_PENDING (1 << 1) 417 #define PCIE_HP_SYNC_RUNNING (1 << 2) 418 419 /* PCIe hotplug friendly functions */ 420 extern int pcie_hp_init(dev_info_t *dip, caddr_t arg); 421 extern int pcie_hp_uninit(dev_info_t *dip); 422 extern int pcie_hp_intr(dev_info_t *dip); 423 extern int pcie_hp_probe(pcie_hp_slot_t *slot_p); 424 extern int pcie_hp_unprobe(pcie_hp_slot_t *slot_p); 425 extern int pcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 426 void *arg, void *result); 427 extern dev_info_t *pcie_hp_devi_find(dev_info_t *dip, uint_t device, 428 uint_t function); 429 extern void pcie_hp_create_occupant_props(dev_info_t *self, dev_t dev, 430 int pci_dev); 431 extern void pcie_hp_create_occupant_props(dev_info_t *self, dev_t dev, 432 int pci_dev); 433 extern void pcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev); 434 extern int pcie_copyin_nvlist(char *packed_buf, size_t packed_sz, 435 nvlist_t **nvlp); 436 extern int pcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, 437 size_t *packed_sz); 438 extern char *pcie_led_state_text(pcie_hp_led_state_t state); 439 extern char *pcie_slot_condition_text(ap_condition_t condition); 440 extern int pcie_create_minor_node(pcie_hp_ctrl_t *, int); 441 extern void pcie_remove_minor_node(pcie_hp_ctrl_t *, int); 442 extern void pcie_hp_gen_sysevent_req(char *slot_name, int hint, 443 dev_info_t *self, int kmflag); 444 445 #endif /* _KERNEL */ 446 447 #ifdef __cplusplus 448 } 449 #endif 450 451 #endif /* _SYS_PCIE_HP_H */ 452