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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2017 Joyent, Inc. 24 */ 25 26 #ifndef __SYS_APIX_APIX_H 27 #define __SYS_APIX_APIX_H 28 29 #include <sys/note.h> 30 #include <sys/avintr.h> 31 #include <sys/traptrace.h> 32 #include <sys/apic.h> 33 #include <sys/apic_common.h> 34 #include <sys/apic_timer.h> 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 #ifdef DEBUG 41 #ifndef TRAPTRACE 42 #define TRAPTRACE 43 #endif 44 #endif 45 46 #define APIX_NAME "apix" 47 48 #define APIX_NVECTOR 256 /* max number of per-cpu vectors */ 49 #define APIX_NIRQ 256 /* maximum number of IRQs */ 50 #define APIX_INVALID_VECT 0 /* invalid vector */ 51 52 /* vector type */ 53 #define APIX_TYPE_FIXED DDI_INTR_TYPE_FIXED /* 1 */ 54 #define APIX_TYPE_MSI DDI_INTR_TYPE_MSI /* 2 */ 55 #define APIX_TYPE_MSIX DDI_INTR_TYPE_MSIX /* 4 */ 56 #define APIX_TYPE_IPI 8 57 58 /* vector states */ 59 enum { 60 APIX_STATE_FREED = 0, 61 APIX_STATE_OBSOLETED, /* 1 */ 62 APIX_STATE_ALLOCED, /* 2 */ 63 APIX_STATE_ENABLED, /* 3 */ 64 APIX_STATE_DISABLED /* 4 */ 65 }; 66 #define IS_VECT_FREE(p) \ 67 (((p) == NULL) || ((p)->v_state == APIX_STATE_FREED)) 68 #define IS_VECT_OBSOL(p) \ 69 (((p) != NULL) && ((p)->v_state == APIX_STATE_OBSOLETED)) 70 #define IS_VECT_ENABLED(p) \ 71 (((p) != NULL) && ((p)->v_state == APIX_STATE_ENABLED)) 72 73 /* flags */ 74 #define APIX_VECT_USER_BOUND 0x1 75 #define APIX_VECT_MASKABLE 0x2 76 77 /* 78 * Number of interrupt vectors reserved by software on each LOCAL APIC: 79 * 1. Dtrace 80 * 2. int80 81 * 3. system-call 82 * 4. fast-trap 83 * 5. apix-reserved 84 */ 85 #define APIX_SW_RESERVED_VECTORS 5 86 87 /* 88 * Macros to help deal with shared interrupts and to differentiate 89 * between vector and irq number when passing arguments to interfaces 90 * xxx_avintr() 91 */ 92 #define APIX_VIRTVEC_VECMASK 0xff 93 #define APIX_VIRTVEC_FLAG 0x80000000 94 #define APIX_VIRTVECTOR(cpuid, v) \ 95 (APIX_VIRTVEC_FLAG | ((cpuid) << 8) | (v)) 96 #define APIX_IS_VIRTVEC(vv) \ 97 ((vv) & APIX_VIRTVEC_FLAG) 98 #define APIX_VIRTVEC_VECTOR(vv) \ 99 (((uchar_t)(vv)) & APIX_VIRTVEC_VECMASK) 100 #define APIX_VIRTVEC_CPU(vv) \ 101 (((uint32_t)(vv) & ~APIX_VIRTVEC_FLAG) >> 8) 102 103 struct apix_dev_vector; 104 typedef struct apix_vector { 105 ushort_t v_state; 106 ushort_t v_type; /* interrupt type */ 107 processorid_t v_cpuid; /* current target cpu */ 108 uchar_t v_vector; /* vector */ 109 uchar_t v_share; /* intrs at this vector */ 110 int v_inum; /* irq for fixed, inum for msi/x */ 111 uint_t v_flags; 112 processorid_t v_bound_cpuid; /* binding cpu */ 113 uint_t v_busy; /* How frequently did clock */ 114 /* find us in this */ 115 uint_t v_pri; /* maximum priority */ 116 struct autovec *v_autovect; /* ISR linked list */ 117 void *v_intrmap_private; /* intr remap data */ 118 struct apix_dev_vector *v_devp; /* pointer to device */ 119 struct apix_vector *v_next; /* next on per-cpu obosoletes chain */ 120 } apix_vector_t; 121 122 typedef struct apix_impl { 123 processorid_t x_cpuid; /* cpu number */ 124 125 uint16_t x_intr_pending; /* pending intr by IPL */ 126 /* pointer to head of interrupt pending list */ 127 struct autovec *x_intr_head[PIL_MAX + 1]; 128 /* pointer to tail of interrupt pending list */ 129 struct autovec *x_intr_tail[PIL_MAX + 1]; 130 131 apix_vector_t *x_obsoletes; /* obosoleted vectors */ 132 apix_vector_t *x_vectbl[APIX_NVECTOR]; /* vector table */ 133 134 lock_t x_lock; 135 } apix_impl_t; 136 137 #define HILEVEL_PENDING(cpu) \ 138 (apixs[(cpu)->cpu_id]->x_intr_pending & CPU_INTR_ACTV_HIGH_LEVEL_MASK) 139 #define LOWLEVEL_PENDING(cpu) \ 140 (apixs[(cpu)->cpu_id]->x_intr_pending & ~CPU_INTR_ACTV_HIGH_LEVEL_MASK) 141 #define IS_HILEVEL_RUNNING(cpu) \ 142 (((ushort_t)((cpu)->intr_actv)) & CPU_INTR_ACTV_HIGH_LEVEL_MASK) 143 #define IS_LOWLEVEL_RUNNING(cpu) \ 144 (((ushort_t)((cpu)->intr_actv)) & ~CPU_INTR_ACTV_HIGH_LEVEL_MASK) 145 146 #define INTR_PENDING(apixp, ipl) \ 147 ((ipl) <= LOCK_LEVEL ? \ 148 ((apixp)->x_intr_pending & (1 << (ipl))) : \ 149 ((apixp)->x_intr_pending >> (LOCK_LEVEL + 1))) 150 151 /* 152 * We need a way to find allocated vector for a device. One option 153 * is to maintain a mapping table in pcplusmp. Another option would 154 * be to record vector or irq with interrupt handler hdlp->ih_vector or 155 * hdlp->ih_irq. 156 * Second option requires interface changes, such as, a new interface 157 * for noticing vector changes caused by interrupt re-targeting. 158 * Currently we choose the first option cause it doesn't require 159 * new interfaces. 160 */ 161 typedef struct apix_dev_vector { 162 dev_info_t *dv_dip; 163 int dv_inum; /* interrupt number */ 164 int dv_type; /* interrupt type */ 165 apix_vector_t *dv_vector; /* vector */ 166 struct apix_dev_vector *dv_next; /* per major chain */ 167 } apix_dev_vector_t; 168 169 extern lock_t apix_lock; 170 extern apix_impl_t *apixs[]; 171 extern int apix_nipis; 172 extern int apix_cpu_nvectors; 173 extern apix_dev_vector_t **apix_dev_vector; 174 extern processorid_t *apix_major_to_cpu; 175 extern kmutex_t apix_mutex; 176 177 #define xv_vector(cpu, v) apixs[(cpu)]->x_vectbl[(v)] 178 #define xv_intrmap_private(cpu, v) (xv_vector(cpu, v))->v_intrmap_private 179 180 #define APIX_IPI_MAX APIC_MAX_VECTOR 181 #define APIX_IPI_MIN (APIX_NVECTOR - apix_nipis) 182 #define APIX_AVINTR_MIN 0x20 183 #define APIX_NAVINTR \ 184 (apix_cpu_nvectors - apix_nipis - APIX_AVINTR_MIN) 185 #define APIX_AVINTR_MAX \ 186 ((APIX_NAVINTR <= 0) ? 0 : \ 187 (((APIX_AVINTR_MIN + APIX_NAVINTR) > APIX_IPI_MIN) ? \ 188 (APIX_IPI_MIN - 2) : \ 189 (APIX_AVINTR_MIN + APIX_NAVINTR - 2))) 190 #define APIX_RESV_VECTOR (APIX_AVINTR_MAX + 1) 191 192 #define IS_VALID_AVINTR(v) \ 193 ((v) >= APIX_AVINTR_MIN && (v) <= APIX_AVINTR_MAX) 194 195 #define APIX_ENTER_CPU_LOCK(cpuid) lock_set(&apixs[(cpuid)]->x_lock) 196 #define APIX_LEAVE_CPU_LOCK(cpuid) lock_clear(&apixs[(cpuid)]->x_lock) 197 #define APIX_CPU_LOCK_HELD(cpuid) LOCK_HELD(&apixs[(cpuid)]->x_lock) 198 199 /* Get dip for msi/x */ 200 #define APIX_GET_DIP(v) \ 201 ((v)->v_devp->dv_dip) 202 203 /* 204 * For irq 205 */ 206 extern apic_irq_t *apic_irq_table[APIC_MAX_VECTOR+1]; 207 #define IS_IRQ_FREE(p) \ 208 ((p) == NULL || ((p)->airq_mps_intr_index == FREE_INDEX)) 209 210 #define UNREFERENCED_1PARAMETER(_p) _NOTE(ARGUNUSED(_p)) 211 #define UNREFERENCED_3PARAMETER(_p, _q, _r) _NOTE(ARGUNUSED(_p, _q, _r)) 212 213 /* 214 * From mp_platform_common.c 215 */ 216 extern int apic_intr_policy; 217 extern iflag_t apic_sci_flags; 218 extern int apic_hpet_vect; 219 extern iflag_t apic_hpet_flags; 220 extern int apic_redist_cpu_skip; 221 extern int apic_num_imbalance; 222 extern int apic_num_rebind; 223 extern struct apic_io_intr *apic_io_intrp; 224 extern int apic_use_acpi_madt_only; 225 extern uint32_t eisa_level_intr_mask; 226 extern int apic_pci_bus_total; 227 extern uchar_t apic_single_pci_busid; 228 229 extern ACPI_MADT_INTERRUPT_OVERRIDE *acpi_isop; 230 extern int acpi_iso_cnt; 231 232 extern int apic_defconf; 233 extern int apic_irq_translate; 234 235 extern int apic_max_reps_clear_pending; 236 237 extern int apic_probe_common(char *modname); 238 extern uchar_t acpi_find_ioapic(int irq); 239 extern int apic_find_bus_id(int bustype); 240 extern int apic_find_intin(uchar_t ioapic, uchar_t intin); 241 extern struct apic_io_intr *apic_find_io_intr_w_busid(int irqno, int busid); 242 extern int apic_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid, 243 int ipin, int *pci_irqp, iflag_t *intr_flagp); 244 extern int apic_handle_pci_pci_bridge(dev_info_t *idip, int child_devno, 245 int child_ipin, struct apic_io_intr **intrp); 246 extern void apic_record_rdt_entry(apic_irq_t *irqptr, int irq); 247 248 /* 249 * From apic_regops.c 250 */ 251 extern int apic_have_32bit_cr8; 252 253 /* 254 * apix_intr.c 255 */ 256 extern void apix_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp); 257 258 /* 259 * apix_utils.c 260 */ 261 262 typedef struct apix_rebind_info { 263 int i_go; /* if rebinding op is in progress */ 264 uint_t i_pri; 265 processorid_t i_old_cpuid; 266 struct autovec *i_old_av; 267 processorid_t i_new_cpuid; 268 struct autovec *i_new_av; 269 } apix_rebind_info_t; 270 271 extern struct apix_rebind_info apix_rebindinfo; 272 273 #define APIX_SET_REBIND_INFO(_ovp, _nvp)\ 274 if (((_ovp)->v_flags & APIX_VECT_MASKABLE) == 0) {\ 275 apix_rebindinfo.i_pri = (_ovp)->v_pri;\ 276 apix_rebindinfo.i_old_cpuid = (_ovp)->v_cpuid;\ 277 apix_rebindinfo.i_old_av = (_ovp)->v_autovect;\ 278 apix_rebindinfo.i_new_cpuid = (_nvp)->v_cpuid;\ 279 apix_rebindinfo.i_new_av = (_nvp)->v_autovect;\ 280 apix_rebindinfo.i_go = 1;\ 281 } 282 283 #define APIX_CLR_REBIND_INFO() \ 284 apix_rebindinfo.i_go = 0 285 286 #define APIX_IS_FAKE_INTR(_vector)\ 287 (apix_rebindinfo.i_go && (_vector) == APIX_RESV_VECTOR) 288 289 #define APIX_DO_FAKE_INTR(_cpu, _vector)\ 290 if (APIX_IS_FAKE_INTR(_vector)) {\ 291 struct autovec *tp = NULL;\ 292 if ((_cpu) == apix_rebindinfo.i_old_cpuid)\ 293 tp = apix_rebindinfo.i_old_av;\ 294 else if ((_cpu) == apix_rebindinfo.i_new_cpuid)\ 295 tp = apix_rebindinfo.i_new_av;\ 296 ASSERT(tp != NULL);\ 297 if (tp->av_vector != NULL &&\ 298 (tp->av_flags & AV_PENTRY_PEND) == 0) {\ 299 tp->av_flags |= AV_PENTRY_PEND;\ 300 apix_insert_pending_av(apixs[(_cpu)], tp,\ 301 tp->av_prilevel);\ 302 apixs[(_cpu)]->x_intr_pending |=\ 303 (1 << tp->av_prilevel);\ 304 }\ 305 } 306 307 extern int apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name, 308 int vector, caddr_t arg1, caddr_t arg2, uint64_t *ticksp, dev_info_t *dip); 309 extern void apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, 310 int virt_vect); 311 312 extern uint32_t apix_bind_cpu_locked(dev_info_t *dip); 313 extern apix_vector_t *apix_rebind(apix_vector_t *vecp, processorid_t tocpu, 314 int count); 315 316 extern uchar_t apix_alloc_ipi(int ipl); 317 extern apix_vector_t *apix_alloc_intx(dev_info_t *dip, int inum, int irqno); 318 extern int apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior); 319 extern int apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior); 320 extern void apix_free_vectors(dev_info_t *dip, int inum, int count, int type); 321 extern void apix_enable_vector(apix_vector_t *vecp); 322 extern void apix_disable_vector(apix_vector_t *vecp); 323 extern int apix_obsolete_vector(apix_vector_t *vecp); 324 extern int apix_find_cont_vector_oncpu(uint32_t cpuid, int count); 325 326 extern void apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum); 327 extern apix_vector_t *apix_get_dev_map(dev_info_t *dip, int inum, int type); 328 extern apix_vector_t *apix_setup_io_intr(apix_vector_t *vecp); 329 extern void ioapix_init_intr(int mask_apic); 330 extern int apix_get_min_dev_inum(dev_info_t *dip, int type); 331 extern int apix_get_max_dev_inum(dev_info_t *dip, int type); 332 333 /* 334 * apix.c 335 */ 336 extern int apix_addspl(int virtvec, int ipl, int min_ipl, int max_ipl); 337 extern int apix_delspl(int virtvec, int ipl, int min_ipl, int max_ipl); 338 extern void apix_intx_set_vector(int irqno, uint32_t cpuid, uchar_t vector); 339 extern apix_vector_t *apix_intx_get_vector(int irqno); 340 extern void apix_intx_enable(int irqno); 341 extern void apix_intx_disable(int irqno); 342 extern void apix_intx_free(int irqno); 343 extern int apix_intx_rebind(int irqno, processorid_t cpuid, uchar_t vector); 344 extern apix_vector_t *apix_set_cpu(apix_vector_t *vecp, int new_cpu, 345 int *result); 346 extern apix_vector_t *apix_grp_set_cpu(apix_vector_t *vecp, int new_cpu, 347 int *result); 348 extern void apix_level_intr_pre_eoi(int irq); 349 extern void apix_level_intr_post_dispatch(int irq); 350 351 #ifdef __cplusplus 352 } 353 #endif 354 355 #endif /* __SYS_APIX_APIX_H */ 356