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 */