17ff178cdSJimmy Vetayases /*
27ff178cdSJimmy Vetayases * CDDL HEADER START
37ff178cdSJimmy Vetayases *
47ff178cdSJimmy Vetayases * The contents of this file are subject to the terms of the
57ff178cdSJimmy Vetayases * Common Development and Distribution License (the "License").
67ff178cdSJimmy Vetayases * You may not use this file except in compliance with the License.
77ff178cdSJimmy Vetayases *
87ff178cdSJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97ff178cdSJimmy Vetayases * or http://www.opensolaris.org/os/licensing.
107ff178cdSJimmy Vetayases * See the License for the specific language governing permissions
117ff178cdSJimmy Vetayases * and limitations under the License.
127ff178cdSJimmy Vetayases *
137ff178cdSJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each
147ff178cdSJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157ff178cdSJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the
167ff178cdSJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying
177ff178cdSJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner]
187ff178cdSJimmy Vetayases *
197ff178cdSJimmy Vetayases * CDDL HEADER END
207ff178cdSJimmy Vetayases */
217ff178cdSJimmy Vetayases
227ff178cdSJimmy Vetayases /*
237ff178cdSJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
247ff178cdSJimmy Vetayases */
257ff178cdSJimmy Vetayases /*
267ff178cdSJimmy Vetayases * Copyright (c) 2010, Intel Corporation.
277ff178cdSJimmy Vetayases * All rights reserved.
287ff178cdSJimmy Vetayases */
29584d084aSHans Rosenfeld /*
30584d084aSHans Rosenfeld * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
31*8181b438SGarrett D'Amore * Copyright 2013 Pluribus Networks, Inc.
32584d084aSHans Rosenfeld */
337ff178cdSJimmy Vetayases
347ff178cdSJimmy Vetayases #include <sys/processor.h>
357ff178cdSJimmy Vetayases #include <sys/time.h>
367ff178cdSJimmy Vetayases #include <sys/psm.h>
377ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h>
387ff178cdSJimmy Vetayases #include <sys/cram.h>
397ff178cdSJimmy Vetayases #include <sys/acpi/acpi.h>
407ff178cdSJimmy Vetayases #include <sys/acpica.h>
417ff178cdSJimmy Vetayases #include <sys/psm_common.h>
427ff178cdSJimmy Vetayases #include <sys/pit.h>
437ff178cdSJimmy Vetayases #include <sys/ddi.h>
447ff178cdSJimmy Vetayases #include <sys/sunddi.h>
457ff178cdSJimmy Vetayases #include <sys/ddi_impldefs.h>
467ff178cdSJimmy Vetayases #include <sys/pci.h>
477ff178cdSJimmy Vetayases #include <sys/promif.h>
487ff178cdSJimmy Vetayases #include <sys/x86_archext.h>
497ff178cdSJimmy Vetayases #include <sys/cpc_impl.h>
507ff178cdSJimmy Vetayases #include <sys/uadmin.h>
517ff178cdSJimmy Vetayases #include <sys/panic.h>
527ff178cdSJimmy Vetayases #include <sys/debug.h>
537ff178cdSJimmy Vetayases #include <sys/archsystm.h>
547ff178cdSJimmy Vetayases #include <sys/trap.h>
557ff178cdSJimmy Vetayases #include <sys/machsystm.h>
567ff178cdSJimmy Vetayases #include <sys/sysmacros.h>
577ff178cdSJimmy Vetayases #include <sys/cpuvar.h>
587ff178cdSJimmy Vetayases #include <sys/rm_platter.h>
597ff178cdSJimmy Vetayases #include <sys/privregs.h>
607ff178cdSJimmy Vetayases #include <sys/note.h>
617ff178cdSJimmy Vetayases #include <sys/pci_intr_lib.h>
627ff178cdSJimmy Vetayases #include <sys/spl.h>
637ff178cdSJimmy Vetayases #include <sys/clock.h>
647ff178cdSJimmy Vetayases #include <sys/dditypes.h>
657ff178cdSJimmy Vetayases #include <sys/sunddi.h>
667ff178cdSJimmy Vetayases #include <sys/x_call.h>
677ff178cdSJimmy Vetayases #include <sys/reboot.h>
687ff178cdSJimmy Vetayases #include <sys/apix.h>
697ff178cdSJimmy Vetayases
707ff178cdSJimmy Vetayases static int apix_get_avail_vector_oncpu(uint32_t, int, int);
717ff178cdSJimmy Vetayases static apix_vector_t *apix_init_vector(processorid_t, uchar_t);
727ff178cdSJimmy Vetayases static void apix_cleanup_vector(apix_vector_t *);
737ff178cdSJimmy Vetayases static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t,
747ff178cdSJimmy Vetayases uint64_t *, int, dev_info_t *);
757ff178cdSJimmy Vetayases static void apix_remove_av(apix_vector_t *, struct autovec *);
767ff178cdSJimmy Vetayases static void apix_clear_dev_map(dev_info_t *, int, int);
777ff178cdSJimmy Vetayases static boolean_t apix_is_cpu_enabled(processorid_t);
787ff178cdSJimmy Vetayases static void apix_wait_till_seen(processorid_t, int);
797ff178cdSJimmy Vetayases
807ff178cdSJimmy Vetayases #define GET_INTR_INUM(ihdlp) \
817ff178cdSJimmy Vetayases (((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0)
827ff178cdSJimmy Vetayases
837ff178cdSJimmy Vetayases apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL};
847ff178cdSJimmy Vetayases
857ff178cdSJimmy Vetayases /*
867ff178cdSJimmy Vetayases * Allocate IPI
877ff178cdSJimmy Vetayases *
887ff178cdSJimmy Vetayases * Return vector number or 0 on error
897ff178cdSJimmy Vetayases */
907ff178cdSJimmy Vetayases uchar_t
apix_alloc_ipi(int ipl)917ff178cdSJimmy Vetayases apix_alloc_ipi(int ipl)
927ff178cdSJimmy Vetayases {
937ff178cdSJimmy Vetayases apix_vector_t *vecp;
947ff178cdSJimmy Vetayases uchar_t vector;
957ff178cdSJimmy Vetayases int cpun;
967ff178cdSJimmy Vetayases int nproc;
977ff178cdSJimmy Vetayases
987ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(0);
997ff178cdSJimmy Vetayases
1007ff178cdSJimmy Vetayases vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX);
1017ff178cdSJimmy Vetayases if (vector == 0) {
1027ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(0);
1037ff178cdSJimmy Vetayases cmn_err(CE_WARN, "apix: no available IPI\n");
1047ff178cdSJimmy Vetayases apic_error |= APIC_ERR_GET_IPIVECT_FAIL;
1057ff178cdSJimmy Vetayases return (0);
1067ff178cdSJimmy Vetayases }
1077ff178cdSJimmy Vetayases
1087ff178cdSJimmy Vetayases nproc = max(apic_nproc, apic_max_nproc);
1097ff178cdSJimmy Vetayases for (cpun = 0; cpun < nproc; cpun++) {
1107ff178cdSJimmy Vetayases vecp = xv_vector(cpun, vector);
1117ff178cdSJimmy Vetayases if (vecp == NULL) {
1127ff178cdSJimmy Vetayases vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
1137ff178cdSJimmy Vetayases if (vecp == NULL) {
1147ff178cdSJimmy Vetayases cmn_err(CE_WARN, "apix: No memory for ipi");
1157ff178cdSJimmy Vetayases goto fail;
1167ff178cdSJimmy Vetayases }
1177ff178cdSJimmy Vetayases xv_vector(cpun, vector) = vecp;
1187ff178cdSJimmy Vetayases }
1197ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_ALLOCED;
1207ff178cdSJimmy Vetayases vecp->v_type = APIX_TYPE_IPI;
1217ff178cdSJimmy Vetayases vecp->v_cpuid = vecp->v_bound_cpuid = cpun;
1227ff178cdSJimmy Vetayases vecp->v_vector = vector;
1237ff178cdSJimmy Vetayases vecp->v_pri = ipl;
1247ff178cdSJimmy Vetayases }
1257ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(0);
1267ff178cdSJimmy Vetayases return (vector);
1277ff178cdSJimmy Vetayases
1287ff178cdSJimmy Vetayases fail:
1297ff178cdSJimmy Vetayases while (--cpun >= 0)
1307ff178cdSJimmy Vetayases apix_cleanup_vector(xv_vector(cpun, vector));
1317ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(0);
1327ff178cdSJimmy Vetayases return (0);
1337ff178cdSJimmy Vetayases }
1347ff178cdSJimmy Vetayases
1357ff178cdSJimmy Vetayases /*
1367ff178cdSJimmy Vetayases * Add IPI service routine
1377ff178cdSJimmy Vetayases */
1387ff178cdSJimmy Vetayases static int
apix_add_ipi(int ipl,avfunc xxintr,char * name,int vector,caddr_t arg1,caddr_t arg2)1397ff178cdSJimmy Vetayases apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector,
1407ff178cdSJimmy Vetayases caddr_t arg1, caddr_t arg2)
1417ff178cdSJimmy Vetayases {
1427ff178cdSJimmy Vetayases int cpun;
1437ff178cdSJimmy Vetayases apix_vector_t *vecp;
1447ff178cdSJimmy Vetayases int nproc;
1457ff178cdSJimmy Vetayases
1467ff178cdSJimmy Vetayases ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX);
1477ff178cdSJimmy Vetayases
1487ff178cdSJimmy Vetayases nproc = max(apic_nproc, apic_max_nproc);
1497ff178cdSJimmy Vetayases for (cpun = 0; cpun < nproc; cpun++) {
1507ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpun);
1517ff178cdSJimmy Vetayases vecp = xv_vector(cpun, vector);
1527ff178cdSJimmy Vetayases apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL);
1537ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_ENABLED;
1547ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpun);
1557ff178cdSJimmy Vetayases }
1567ff178cdSJimmy Vetayases
1577ff178cdSJimmy Vetayases APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x "
1587ff178cdSJimmy Vetayases "ipl %x\n", name, vector, ipl));
1597ff178cdSJimmy Vetayases
1607ff178cdSJimmy Vetayases return (1);
1617ff178cdSJimmy Vetayases }
1627ff178cdSJimmy Vetayases
1637ff178cdSJimmy Vetayases /*
1647ff178cdSJimmy Vetayases * Find and return first free vector in range (start, end)
1657ff178cdSJimmy Vetayases */
1667ff178cdSJimmy Vetayases static int
apix_get_avail_vector_oncpu(uint32_t cpuid,int start,int end)1677ff178cdSJimmy Vetayases apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end)
1687ff178cdSJimmy Vetayases {
1697ff178cdSJimmy Vetayases int i;
1707ff178cdSJimmy Vetayases apix_impl_t *apixp = apixs[cpuid];
1717ff178cdSJimmy Vetayases
1727ff178cdSJimmy Vetayases for (i = start; i <= end; i++) {
1737ff178cdSJimmy Vetayases if (APIC_CHECK_RESERVE_VECTORS(i))
1747ff178cdSJimmy Vetayases continue;
1757ff178cdSJimmy Vetayases if (IS_VECT_FREE(apixp->x_vectbl[i]))
1767ff178cdSJimmy Vetayases return (i);
1777ff178cdSJimmy Vetayases }
1787ff178cdSJimmy Vetayases
1797ff178cdSJimmy Vetayases return (0);
1807ff178cdSJimmy Vetayases }
1817ff178cdSJimmy Vetayases
1827ff178cdSJimmy Vetayases /*
1837ff178cdSJimmy Vetayases * Allocate a vector on specified cpu
1847ff178cdSJimmy Vetayases *
1857ff178cdSJimmy Vetayases * Return NULL on error
1867ff178cdSJimmy Vetayases */
1877ff178cdSJimmy Vetayases static apix_vector_t *
apix_alloc_vector_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int type)1887ff178cdSJimmy Vetayases apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type)
1897ff178cdSJimmy Vetayases {
1907ff178cdSJimmy Vetayases processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
1917ff178cdSJimmy Vetayases apix_vector_t *vecp;
1927ff178cdSJimmy Vetayases int vector;
1937ff178cdSJimmy Vetayases
1947ff178cdSJimmy Vetayases ASSERT(APIX_CPU_LOCK_HELD(tocpu));
1957ff178cdSJimmy Vetayases
1967ff178cdSJimmy Vetayases /* find free vector */
1977ff178cdSJimmy Vetayases vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN,
1987ff178cdSJimmy Vetayases APIX_AVINTR_MAX);
1997ff178cdSJimmy Vetayases if (vector == 0)
2007ff178cdSJimmy Vetayases return (NULL);
2017ff178cdSJimmy Vetayases
2027ff178cdSJimmy Vetayases vecp = apix_init_vector(tocpu, vector);
2037ff178cdSJimmy Vetayases vecp->v_type = (ushort_t)type;
2047ff178cdSJimmy Vetayases vecp->v_inum = inum;
2057ff178cdSJimmy Vetayases vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
2067ff178cdSJimmy Vetayases
2077ff178cdSJimmy Vetayases if (dip != NULL)
2087ff178cdSJimmy Vetayases apix_set_dev_map(vecp, dip, inum);
2097ff178cdSJimmy Vetayases
2107ff178cdSJimmy Vetayases return (vecp);
2117ff178cdSJimmy Vetayases }
2127ff178cdSJimmy Vetayases
2137ff178cdSJimmy Vetayases /*
2147ff178cdSJimmy Vetayases * Allocates "count" contiguous MSI vectors starting at the proper alignment.
2157ff178cdSJimmy Vetayases * Caller needs to make sure that count has to be power of 2 and should not
2167ff178cdSJimmy Vetayases * be < 1.
2177ff178cdSJimmy Vetayases *
2187ff178cdSJimmy Vetayases * Return first vector number
2197ff178cdSJimmy Vetayases */
2207ff178cdSJimmy Vetayases apix_vector_t *
apix_alloc_nvectors_oncpu(uint32_t cpuid,dev_info_t * dip,int inum,int count,int type)2217ff178cdSJimmy Vetayases apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum,
2227ff178cdSJimmy Vetayases int count, int type)
2237ff178cdSJimmy Vetayases {
2247ff178cdSJimmy Vetayases int i, msibits, start = 0, navail = 0;
2257ff178cdSJimmy Vetayases apix_vector_t *vecp, *startp = NULL;
2267ff178cdSJimmy Vetayases processorid_t tocpu = cpuid & ~IRQ_USER_BOUND;
2277ff178cdSJimmy Vetayases uint_t flags;
2287ff178cdSJimmy Vetayases
2297ff178cdSJimmy Vetayases ASSERT(APIX_CPU_LOCK_HELD(tocpu));
2307ff178cdSJimmy Vetayases
2317ff178cdSJimmy Vetayases /*
2327ff178cdSJimmy Vetayases * msibits is the no. of lower order message data bits for the
2337ff178cdSJimmy Vetayases * allocated MSI vectors and is used to calculate the aligned
2347ff178cdSJimmy Vetayases * starting vector
2357ff178cdSJimmy Vetayases */
2367ff178cdSJimmy Vetayases msibits = count - 1;
2377ff178cdSJimmy Vetayases
2387ff178cdSJimmy Vetayases /* It has to be contiguous */
2397ff178cdSJimmy Vetayases for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) {
2407ff178cdSJimmy Vetayases if (!IS_VECT_FREE(xv_vector(tocpu, i)))
2417ff178cdSJimmy Vetayases continue;
2427ff178cdSJimmy Vetayases
2437ff178cdSJimmy Vetayases /*
2447ff178cdSJimmy Vetayases * starting vector has to be aligned accordingly for
2457ff178cdSJimmy Vetayases * multiple MSIs
2467ff178cdSJimmy Vetayases */
2477ff178cdSJimmy Vetayases if (msibits)
2487ff178cdSJimmy Vetayases i = (i + msibits) & ~msibits;
2497ff178cdSJimmy Vetayases
2507ff178cdSJimmy Vetayases for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) {
2517ff178cdSJimmy Vetayases if (!IS_VECT_FREE(xv_vector(tocpu, i)))
2527ff178cdSJimmy Vetayases break;
2537ff178cdSJimmy Vetayases if (APIC_CHECK_RESERVE_VECTORS(i))
2547ff178cdSJimmy Vetayases break;
2557ff178cdSJimmy Vetayases if (++navail == count)
2567ff178cdSJimmy Vetayases goto done;
2577ff178cdSJimmy Vetayases }
2587ff178cdSJimmy Vetayases }
2597ff178cdSJimmy Vetayases
2607ff178cdSJimmy Vetayases return (NULL);
2617ff178cdSJimmy Vetayases
2627ff178cdSJimmy Vetayases done:
2637ff178cdSJimmy Vetayases flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0;
2647ff178cdSJimmy Vetayases
2657ff178cdSJimmy Vetayases for (i = 0; i < count; i++) {
2667ff178cdSJimmy Vetayases if ((vecp = apix_init_vector(tocpu, start + i)) == NULL)
2677ff178cdSJimmy Vetayases goto fail;
2687ff178cdSJimmy Vetayases
2697ff178cdSJimmy Vetayases vecp->v_type = (ushort_t)type;
2707ff178cdSJimmy Vetayases vecp->v_inum = inum + i;
2717ff178cdSJimmy Vetayases vecp->v_flags = flags;
2727ff178cdSJimmy Vetayases
2737ff178cdSJimmy Vetayases if (dip != NULL)
2747ff178cdSJimmy Vetayases apix_set_dev_map(vecp, dip, inum + i);
2757ff178cdSJimmy Vetayases
2767ff178cdSJimmy Vetayases if (i == 0)
2777ff178cdSJimmy Vetayases startp = vecp;
2787ff178cdSJimmy Vetayases }
2797ff178cdSJimmy Vetayases
2807ff178cdSJimmy Vetayases return (startp);
2817ff178cdSJimmy Vetayases
2827ff178cdSJimmy Vetayases fail:
2837ff178cdSJimmy Vetayases while (i-- > 0) { /* Free allocated vectors */
2847ff178cdSJimmy Vetayases vecp = xv_vector(tocpu, start + i);
2857ff178cdSJimmy Vetayases apix_clear_dev_map(dip, inum + i, type);
2867ff178cdSJimmy Vetayases apix_cleanup_vector(vecp);
2877ff178cdSJimmy Vetayases }
2887ff178cdSJimmy Vetayases return (NULL);
2897ff178cdSJimmy Vetayases }
2907ff178cdSJimmy Vetayases
2917ff178cdSJimmy Vetayases #define APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\
2927ff178cdSJimmy Vetayases do {\
2937ff178cdSJimmy Vetayases if ((_ctrl) & PCI_MSI_64BIT_MASK)\
2947ff178cdSJimmy Vetayases pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\
2957ff178cdSJimmy Vetayases else\
2967ff178cdSJimmy Vetayases pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\
2977ff178cdSJimmy Vetayases _NOTE(CONSTCOND)} while (0)
2987ff178cdSJimmy Vetayases
2997ff178cdSJimmy Vetayases static void
apix_pci_msi_enable_vector(apix_vector_t * vecp,dev_info_t * dip,int type,int inum,int count,uchar_t vector,int target_apic_id)3007ff178cdSJimmy Vetayases apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type,
3017ff178cdSJimmy Vetayases int inum, int count, uchar_t vector, int target_apic_id)
3027ff178cdSJimmy Vetayases {
3037ff178cdSJimmy Vetayases uint64_t msi_addr, msi_data;
3047ff178cdSJimmy Vetayases ushort_t msi_ctrl;
3057ff178cdSJimmy Vetayases int i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
3067ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip);
3077ff178cdSJimmy Vetayases msi_regs_t msi_regs;
3087ff178cdSJimmy Vetayases void *intrmap_tbl[PCI_MSI_MAX_INTRS];
3097ff178cdSJimmy Vetayases
3107ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n"
3117ff178cdSJimmy Vetayases "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip,
3127ff178cdSJimmy Vetayases ddi_driver_name(dip), inum, vector, target_apic_id));
3137ff178cdSJimmy Vetayases
3147ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0));
3157ff178cdSJimmy Vetayases
3167ff178cdSJimmy Vetayases msi_regs.mr_data = vector;
3177ff178cdSJimmy Vetayases msi_regs.mr_addr = target_apic_id;
3187ff178cdSJimmy Vetayases
3192edb3dccSJudy Chen for (i = 0; i < count; i++)
3202edb3dccSJudy Chen intrmap_tbl[i] = xv_intrmap_private(vecp->v_cpuid, vector + i);
3217ff178cdSJimmy Vetayases apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type,
3227ff178cdSJimmy Vetayases count, 0xff);
3237ff178cdSJimmy Vetayases for (i = 0; i < count; i++)
3247ff178cdSJimmy Vetayases xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i];
3257ff178cdSJimmy Vetayases
3267ff178cdSJimmy Vetayases apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private,
3277ff178cdSJimmy Vetayases (void *)&msi_regs, type, count);
3287ff178cdSJimmy Vetayases apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private,
3297ff178cdSJimmy Vetayases &msi_regs);
3307ff178cdSJimmy Vetayases
3317ff178cdSJimmy Vetayases /* MSI Address */
3327ff178cdSJimmy Vetayases msi_addr = msi_regs.mr_addr;
3337ff178cdSJimmy Vetayases
3347ff178cdSJimmy Vetayases /* MSI Data: MSI is edge triggered according to spec */
3357ff178cdSJimmy Vetayases msi_data = msi_regs.mr_data;
3367ff178cdSJimmy Vetayases
3377ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx "
3387ff178cdSJimmy Vetayases "data=0x%lx\n", (long)msi_addr, (long)msi_data));
3397ff178cdSJimmy Vetayases
3407ff178cdSJimmy Vetayases if (type == APIX_TYPE_MSI) {
3417ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
3427ff178cdSJimmy Vetayases
3437ff178cdSJimmy Vetayases /* Set the bits to inform how many MSIs are enabled */
3447ff178cdSJimmy Vetayases msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT);
3457ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
3467ff178cdSJimmy Vetayases
3477ff178cdSJimmy Vetayases if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0)
3487ff178cdSJimmy Vetayases APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl,
3497ff178cdSJimmy Vetayases APIX_RESV_VECTOR);
3507ff178cdSJimmy Vetayases
3517ff178cdSJimmy Vetayases pci_config_put32(handle,
3527ff178cdSJimmy Vetayases cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr);
3537ff178cdSJimmy Vetayases if (msi_ctrl & PCI_MSI_64BIT_MASK)
3547ff178cdSJimmy Vetayases pci_config_put32(handle,
3557ff178cdSJimmy Vetayases cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32);
3567ff178cdSJimmy Vetayases
3577ff178cdSJimmy Vetayases APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data);
3587ff178cdSJimmy Vetayases } else if (type == APIX_TYPE_MSIX) {
3597ff178cdSJimmy Vetayases uintptr_t off;
3607ff178cdSJimmy Vetayases ddi_intr_msix_t *msix_p = i_ddi_get_msix(dip);
3617ff178cdSJimmy Vetayases
3627ff178cdSJimmy Vetayases /* Offset into the "inum"th entry in the MSI-X table */
3637ff178cdSJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr +
3647ff178cdSJimmy Vetayases (inum * PCI_MSIX_VECTOR_SIZE);
3657ff178cdSJimmy Vetayases
3667ff178cdSJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl,
3677ff178cdSJimmy Vetayases (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data);
368*8181b438SGarrett D'Amore ddi_put32(msix_p->msix_tbl_hdl,
369*8181b438SGarrett D'Amore (uint32_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr);
370*8181b438SGarrett D'Amore ddi_put32(msix_p->msix_tbl_hdl,
371*8181b438SGarrett D'Amore (uint32_t *)(off + PCI_MSIX_UPPER_ADDR_OFFSET),
372*8181b438SGarrett D'Amore msi_addr >> 32);
3737ff178cdSJimmy Vetayases }
3747ff178cdSJimmy Vetayases }
3757ff178cdSJimmy Vetayases
3767ff178cdSJimmy Vetayases static void
apix_pci_msi_enable_mode(dev_info_t * dip,int type,int inum)3777ff178cdSJimmy Vetayases apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum)
3787ff178cdSJimmy Vetayases {
3797ff178cdSJimmy Vetayases ushort_t msi_ctrl;
3807ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
3817ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip);
3827ff178cdSJimmy Vetayases
3837ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0));
3847ff178cdSJimmy Vetayases
3857ff178cdSJimmy Vetayases if (type == APIX_TYPE_MSI) {
3867ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
3877ff178cdSJimmy Vetayases if ((msi_ctrl & PCI_MSI_ENABLE_BIT))
3887ff178cdSJimmy Vetayases return;
3897ff178cdSJimmy Vetayases
3907ff178cdSJimmy Vetayases msi_ctrl |= PCI_MSI_ENABLE_BIT;
3917ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
3927ff178cdSJimmy Vetayases
3937ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) {
3947ff178cdSJimmy Vetayases uintptr_t off;
3957ff178cdSJimmy Vetayases uint32_t mask;
3967ff178cdSJimmy Vetayases ddi_intr_msix_t *msix_p;
3977ff178cdSJimmy Vetayases
3987ff178cdSJimmy Vetayases msix_p = i_ddi_get_msix(dip);
3997ff178cdSJimmy Vetayases
4007ff178cdSJimmy Vetayases /* Offset into "inum"th entry in the MSI-X table & clear mask */
4017ff178cdSJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
4027ff178cdSJimmy Vetayases PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
4037ff178cdSJimmy Vetayases
4047ff178cdSJimmy Vetayases mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
4057ff178cdSJimmy Vetayases
4067ff178cdSJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1));
4077ff178cdSJimmy Vetayases
4087ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
4097ff178cdSJimmy Vetayases
4107ff178cdSJimmy Vetayases if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) {
4117ff178cdSJimmy Vetayases msi_ctrl |= PCI_MSIX_ENABLE_BIT;
4127ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,
4137ff178cdSJimmy Vetayases msi_ctrl);
4147ff178cdSJimmy Vetayases }
4157ff178cdSJimmy Vetayases }
4167ff178cdSJimmy Vetayases }
4177ff178cdSJimmy Vetayases
4187ff178cdSJimmy Vetayases /*
4197ff178cdSJimmy Vetayases * Setup interrupt, pogramming IO-APIC or MSI/X address/data.
4207ff178cdSJimmy Vetayases */
4217ff178cdSJimmy Vetayases void
apix_enable_vector(apix_vector_t * vecp)4227ff178cdSJimmy Vetayases apix_enable_vector(apix_vector_t *vecp)
4237ff178cdSJimmy Vetayases {
4247ff178cdSJimmy Vetayases int tocpu = vecp->v_cpuid, type = vecp->v_type;
4257ff178cdSJimmy Vetayases apic_cpus_info_t *cpu_infop;
4267ff178cdSJimmy Vetayases ulong_t iflag;
4277ff178cdSJimmy Vetayases
4287ff178cdSJimmy Vetayases ASSERT(tocpu < apic_nproc);
4297ff178cdSJimmy Vetayases
4307ff178cdSJimmy Vetayases cpu_infop = &apic_cpus[tocpu];
4317ff178cdSJimmy Vetayases if (vecp->v_flags & APIX_VECT_USER_BOUND)
4327ff178cdSJimmy Vetayases cpu_infop->aci_bound++;
4337ff178cdSJimmy Vetayases else
4347ff178cdSJimmy Vetayases cpu_infop->aci_temp_bound++;
4357ff178cdSJimmy Vetayases
4367ff178cdSJimmy Vetayases iflag = intr_clear();
4377ff178cdSJimmy Vetayases lock_set(&apic_ioapic_lock);
4387ff178cdSJimmy Vetayases
4397ff178cdSJimmy Vetayases if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { /* fixed */
4407ff178cdSJimmy Vetayases apix_intx_enable(vecp->v_inum);
4417ff178cdSJimmy Vetayases } else {
4427ff178cdSJimmy Vetayases int inum = vecp->v_inum;
4437ff178cdSJimmy Vetayases dev_info_t *dip = APIX_GET_DIP(vecp);
4447ff178cdSJimmy Vetayases int count = i_ddi_intr_get_current_nintrs(dip);
4457ff178cdSJimmy Vetayases
4467ff178cdSJimmy Vetayases if (type == APIX_TYPE_MSI) { /* MSI */
4477ff178cdSJimmy Vetayases if (inum == apix_get_max_dev_inum(dip, type)) {
4487ff178cdSJimmy Vetayases /* last one */
4497ff178cdSJimmy Vetayases uchar_t start_inum = inum + 1 - count;
4507ff178cdSJimmy Vetayases uchar_t start_vect = vecp->v_vector + 1 - count;
4517ff178cdSJimmy Vetayases apix_vector_t *start_vecp =
4527ff178cdSJimmy Vetayases xv_vector(vecp->v_cpuid, start_vect);
4537ff178cdSJimmy Vetayases
4547ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
4557ff178cdSJimmy Vetayases "apix_pci_msi_enable_vector\n"));
4567ff178cdSJimmy Vetayases apix_pci_msi_enable_vector(start_vecp, dip,
4577ff178cdSJimmy Vetayases type, start_inum, count, start_vect,
4587ff178cdSJimmy Vetayases cpu_infop->aci_local_id);
4597ff178cdSJimmy Vetayases
4607ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT, "apix: call "
4617ff178cdSJimmy Vetayases "apix_pci_msi_enable_mode\n"));
4627ff178cdSJimmy Vetayases apix_pci_msi_enable_mode(dip, type, inum);
4637ff178cdSJimmy Vetayases }
4647ff178cdSJimmy Vetayases } else { /* MSI-X */
4657ff178cdSJimmy Vetayases apix_pci_msi_enable_vector(vecp, dip,
4667ff178cdSJimmy Vetayases type, inum, 1, vecp->v_vector,
4677ff178cdSJimmy Vetayases cpu_infop->aci_local_id);
4687ff178cdSJimmy Vetayases apix_pci_msi_enable_mode(dip, type, inum);
4697ff178cdSJimmy Vetayases }
4707ff178cdSJimmy Vetayases }
4717ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_ENABLED;
4727ff178cdSJimmy Vetayases apic_redist_cpu_skip &= ~(1 << tocpu);
4737ff178cdSJimmy Vetayases
4747ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock);
4757ff178cdSJimmy Vetayases intr_restore(iflag);
4767ff178cdSJimmy Vetayases }
4777ff178cdSJimmy Vetayases
4787ff178cdSJimmy Vetayases /*
4797ff178cdSJimmy Vetayases * Disable the interrupt
4807ff178cdSJimmy Vetayases */
4817ff178cdSJimmy Vetayases void
apix_disable_vector(apix_vector_t * vecp)4827ff178cdSJimmy Vetayases apix_disable_vector(apix_vector_t *vecp)
4837ff178cdSJimmy Vetayases {
4847ff178cdSJimmy Vetayases struct autovec *avp = vecp->v_autovect;
4857ff178cdSJimmy Vetayases ulong_t iflag;
4867ff178cdSJimmy Vetayases
4877ff178cdSJimmy Vetayases ASSERT(avp != NULL);
4887ff178cdSJimmy Vetayases
4897ff178cdSJimmy Vetayases iflag = intr_clear();
4907ff178cdSJimmy Vetayases lock_set(&apic_ioapic_lock);
4917ff178cdSJimmy Vetayases
4927ff178cdSJimmy Vetayases switch (vecp->v_type) {
4937ff178cdSJimmy Vetayases case APIX_TYPE_MSI:
4947ff178cdSJimmy Vetayases ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
4957ff178cdSJimmy Vetayases /*
4967ff178cdSJimmy Vetayases * Disable the MSI vector
4977ff178cdSJimmy Vetayases * Make sure we only disable on the last
4987ff178cdSJimmy Vetayases * of the multi-MSI support
4997ff178cdSJimmy Vetayases */
5007ff178cdSJimmy Vetayases if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
5017ff178cdSJimmy Vetayases apic_pci_msi_disable_mode(avp->av_dip,
5027ff178cdSJimmy Vetayases DDI_INTR_TYPE_MSI);
5037ff178cdSJimmy Vetayases }
5047ff178cdSJimmy Vetayases break;
5057ff178cdSJimmy Vetayases case APIX_TYPE_MSIX:
5067ff178cdSJimmy Vetayases ASSERT(avp->av_vector != NULL && avp->av_dip != NULL);
5077ff178cdSJimmy Vetayases /*
5087ff178cdSJimmy Vetayases * Disable the MSI-X vector
5097ff178cdSJimmy Vetayases * needs to clear its mask and addr/data for each MSI-X
5107ff178cdSJimmy Vetayases */
5117ff178cdSJimmy Vetayases apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX,
5127ff178cdSJimmy Vetayases vecp->v_inum);
5137ff178cdSJimmy Vetayases /*
5147ff178cdSJimmy Vetayases * Make sure we only disable on the last MSI-X
5157ff178cdSJimmy Vetayases */
5167ff178cdSJimmy Vetayases if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) {
5177ff178cdSJimmy Vetayases apic_pci_msi_disable_mode(avp->av_dip,
5187ff178cdSJimmy Vetayases DDI_INTR_TYPE_MSIX);
5197ff178cdSJimmy Vetayases }
5207ff178cdSJimmy Vetayases break;
5217ff178cdSJimmy Vetayases default:
5227ff178cdSJimmy Vetayases apix_intx_disable(vecp->v_inum);
5237ff178cdSJimmy Vetayases break;
5247ff178cdSJimmy Vetayases }
5257ff178cdSJimmy Vetayases
5267ff178cdSJimmy Vetayases if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND))
5277ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_DISABLED;
5287ff178cdSJimmy Vetayases apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private);
5297ff178cdSJimmy Vetayases vecp->v_intrmap_private = NULL;
5307ff178cdSJimmy Vetayases
5317ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock);
5327ff178cdSJimmy Vetayases intr_restore(iflag);
5337ff178cdSJimmy Vetayases }
5347ff178cdSJimmy Vetayases
5357ff178cdSJimmy Vetayases /*
5367ff178cdSJimmy Vetayases * Mark vector as obsoleted or freed. The vector is marked
5377ff178cdSJimmy Vetayases * obsoleted if there are pending requests on it. Otherwise,
5387ff178cdSJimmy Vetayases * free the vector. The obsoleted vectors get freed after
5397ff178cdSJimmy Vetayases * being serviced.
5407ff178cdSJimmy Vetayases *
5417ff178cdSJimmy Vetayases * Return 1 on being obosoleted and 0 on being freed.
5427ff178cdSJimmy Vetayases */
5437ff178cdSJimmy Vetayases #define INTR_BUSY(_avp)\
5447ff178cdSJimmy Vetayases ((((volatile ushort_t)(_avp)->av_flags) &\
5457ff178cdSJimmy Vetayases (AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0)
5467ff178cdSJimmy Vetayases #define LOCAL_WITH_INTR_DISABLED(_cpuid)\
5477ff178cdSJimmy Vetayases ((_cpuid) == psm_get_cpu_id() && !interrupts_enabled())
5487ff178cdSJimmy Vetayases static uint64_t dummy_tick;
5497ff178cdSJimmy Vetayases
5507ff178cdSJimmy Vetayases int
apix_obsolete_vector(apix_vector_t * vecp)5517ff178cdSJimmy Vetayases apix_obsolete_vector(apix_vector_t *vecp)
5527ff178cdSJimmy Vetayases {
5537ff178cdSJimmy Vetayases struct autovec *avp = vecp->v_autovect;
5547ff178cdSJimmy Vetayases int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid;
5557ff178cdSJimmy Vetayases apix_impl_t *apixp = apixs[cpuid];
5567ff178cdSJimmy Vetayases
5577ff178cdSJimmy Vetayases ASSERT(APIX_CPU_LOCK_HELD(cpuid));
5587ff178cdSJimmy Vetayases
5597ff178cdSJimmy Vetayases for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) {
5607ff178cdSJimmy Vetayases if (avp->av_vector == NULL)
5617ff178cdSJimmy Vetayases continue;
5627ff178cdSJimmy Vetayases
5637ff178cdSJimmy Vetayases if (LOCAL_WITH_INTR_DISABLED(cpuid)) {
5647ff178cdSJimmy Vetayases int bit, index, irr;
5657ff178cdSJimmy Vetayases
5667ff178cdSJimmy Vetayases if (INTR_BUSY(avp)) {
5677ff178cdSJimmy Vetayases busy++;
5687ff178cdSJimmy Vetayases continue;
5697ff178cdSJimmy Vetayases }
5707ff178cdSJimmy Vetayases
5717ff178cdSJimmy Vetayases /* check IRR for pending interrupts */
5727ff178cdSJimmy Vetayases index = vecp->v_vector / 32;
5737ff178cdSJimmy Vetayases bit = vecp->v_vector % 32;
5747ff178cdSJimmy Vetayases irr = apic_reg_ops->apic_read(APIC_IRR_REG + index);
5757ff178cdSJimmy Vetayases if ((irr & (1 << bit)) != 0)
5767ff178cdSJimmy Vetayases busy++;
5777ff178cdSJimmy Vetayases
5787ff178cdSJimmy Vetayases if (!busy)
5797ff178cdSJimmy Vetayases apix_remove_av(vecp, avp);
5807ff178cdSJimmy Vetayases
5817ff178cdSJimmy Vetayases continue;
5827ff178cdSJimmy Vetayases }
5837ff178cdSJimmy Vetayases
5847ff178cdSJimmy Vetayases repeats = 0;
5857ff178cdSJimmy Vetayases do {
5867ff178cdSJimmy Vetayases repeats++;
5877ff178cdSJimmy Vetayases for (tries = 0; tries < apic_max_reps_clear_pending;
5887ff178cdSJimmy Vetayases tries++)
5897ff178cdSJimmy Vetayases if (!INTR_BUSY(avp))
5907ff178cdSJimmy Vetayases break;
5917ff178cdSJimmy Vetayases } while (INTR_BUSY(avp) &&
5927ff178cdSJimmy Vetayases (repeats < apic_max_reps_clear_pending));
5937ff178cdSJimmy Vetayases
5947ff178cdSJimmy Vetayases if (INTR_BUSY(avp))
5957ff178cdSJimmy Vetayases busy++;
5967ff178cdSJimmy Vetayases else {
5977ff178cdSJimmy Vetayases /*
5987ff178cdSJimmy Vetayases * Interrupt is not in pending list or being serviced.
5997ff178cdSJimmy Vetayases * However it might be cached in Local APIC's IRR
6007ff178cdSJimmy Vetayases * register. It's impossible to check another CPU's
6017ff178cdSJimmy Vetayases * IRR register. Then wait till lower levels finish
6027ff178cdSJimmy Vetayases * running.
6037ff178cdSJimmy Vetayases */
6047ff178cdSJimmy Vetayases for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++)
6057ff178cdSJimmy Vetayases apix_wait_till_seen(cpuid, ipl);
6067ff178cdSJimmy Vetayases if (INTR_BUSY(avp))
6077ff178cdSJimmy Vetayases busy++;
6087ff178cdSJimmy Vetayases }
6097ff178cdSJimmy Vetayases
6107ff178cdSJimmy Vetayases if (!busy)
6117ff178cdSJimmy Vetayases apix_remove_av(vecp, avp);
6127ff178cdSJimmy Vetayases }
6137ff178cdSJimmy Vetayases
6147ff178cdSJimmy Vetayases if (busy) {
6157ff178cdSJimmy Vetayases apix_vector_t *tp = apixp->x_obsoletes;
6167ff178cdSJimmy Vetayases
6177ff178cdSJimmy Vetayases if (vecp->v_state == APIX_STATE_OBSOLETED)
6187ff178cdSJimmy Vetayases return (1);
6197ff178cdSJimmy Vetayases
6207ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_OBSOLETED;
6217ff178cdSJimmy Vetayases vecp->v_next = NULL;
6227ff178cdSJimmy Vetayases if (tp == NULL)
6237ff178cdSJimmy Vetayases apixp->x_obsoletes = vecp;
6247ff178cdSJimmy Vetayases else {
6257ff178cdSJimmy Vetayases while (tp->v_next != NULL)
6267ff178cdSJimmy Vetayases tp = tp->v_next;
6277ff178cdSJimmy Vetayases tp->v_next = vecp;
6287ff178cdSJimmy Vetayases }
6297ff178cdSJimmy Vetayases return (1);
6307ff178cdSJimmy Vetayases }
6317ff178cdSJimmy Vetayases
6327ff178cdSJimmy Vetayases /* interrupt is not busy */
6337ff178cdSJimmy Vetayases if (vecp->v_state == APIX_STATE_OBSOLETED) {
6347ff178cdSJimmy Vetayases /* remove from obsoleted list */
6357ff178cdSJimmy Vetayases apixp->x_obsoletes = vecp->v_next;
6367ff178cdSJimmy Vetayases vecp->v_next = NULL;
6377ff178cdSJimmy Vetayases }
6387ff178cdSJimmy Vetayases apix_cleanup_vector(vecp);
6397ff178cdSJimmy Vetayases return (0);
6407ff178cdSJimmy Vetayases }
6417ff178cdSJimmy Vetayases
6427ff178cdSJimmy Vetayases /*
6437ff178cdSJimmy Vetayases * Duplicate number of continuous vectors to specified target vectors.
6447ff178cdSJimmy Vetayases */
6457ff178cdSJimmy Vetayases static void
apix_dup_vectors(apix_vector_t * oldp,apix_vector_t * newp,int count)6467ff178cdSJimmy Vetayases apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count)
6477ff178cdSJimmy Vetayases {
6487ff178cdSJimmy Vetayases struct autovec *avp;
6497ff178cdSJimmy Vetayases apix_vector_t *fromp, *top;
6507ff178cdSJimmy Vetayases processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid;
6517ff178cdSJimmy Vetayases uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector;
6527ff178cdSJimmy Vetayases int i, inum;
6537ff178cdSJimmy Vetayases
6547ff178cdSJimmy Vetayases ASSERT(oldp->v_type != APIX_TYPE_IPI);
6557ff178cdSJimmy Vetayases
6567ff178cdSJimmy Vetayases for (i = 0; i < count; i++) {
6577ff178cdSJimmy Vetayases fromp = xv_vector(oldcpu, oldvec + i);
6587ff178cdSJimmy Vetayases top = xv_vector(newcpu, newvec + i);
6597ff178cdSJimmy Vetayases ASSERT(fromp != NULL && top != NULL);
6607ff178cdSJimmy Vetayases
6617ff178cdSJimmy Vetayases /* copy over original one */
6627ff178cdSJimmy Vetayases top->v_state = fromp->v_state;
6637ff178cdSJimmy Vetayases top->v_type = fromp->v_type;
6647ff178cdSJimmy Vetayases top->v_bound_cpuid = fromp->v_bound_cpuid;
6657ff178cdSJimmy Vetayases top->v_inum = fromp->v_inum;
6667ff178cdSJimmy Vetayases top->v_flags = fromp->v_flags;
6677ff178cdSJimmy Vetayases top->v_intrmap_private = fromp->v_intrmap_private;
6687ff178cdSJimmy Vetayases
6697ff178cdSJimmy Vetayases for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) {
6707ff178cdSJimmy Vetayases if (avp->av_vector == NULL)
6717ff178cdSJimmy Vetayases continue;
6727ff178cdSJimmy Vetayases
6737ff178cdSJimmy Vetayases apix_insert_av(top, avp->av_intr_id, avp->av_vector,
6747ff178cdSJimmy Vetayases avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
6757ff178cdSJimmy Vetayases avp->av_prilevel, avp->av_dip);
6767ff178cdSJimmy Vetayases
6777ff178cdSJimmy Vetayases if (fromp->v_type == APIX_TYPE_FIXED &&
6787ff178cdSJimmy Vetayases avp->av_dip != NULL) {
6797ff178cdSJimmy Vetayases inum = GET_INTR_INUM(avp->av_intr_id);
6807ff178cdSJimmy Vetayases apix_set_dev_map(top, avp->av_dip, inum);
6817ff178cdSJimmy Vetayases }
6827ff178cdSJimmy Vetayases }
6837ff178cdSJimmy Vetayases
6847ff178cdSJimmy Vetayases if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) &&
6857ff178cdSJimmy Vetayases fromp->v_devp != NULL)
6867ff178cdSJimmy Vetayases apix_set_dev_map(top, fromp->v_devp->dv_dip,
6877ff178cdSJimmy Vetayases fromp->v_devp->dv_inum);
6887ff178cdSJimmy Vetayases }
6897ff178cdSJimmy Vetayases }
6907ff178cdSJimmy Vetayases
6917ff178cdSJimmy Vetayases static apix_vector_t *
apix_init_vector(processorid_t cpuid,uchar_t vector)6927ff178cdSJimmy Vetayases apix_init_vector(processorid_t cpuid, uchar_t vector)
6937ff178cdSJimmy Vetayases {
6947ff178cdSJimmy Vetayases apix_impl_t *apixp = apixs[cpuid];
6957ff178cdSJimmy Vetayases apix_vector_t *vecp = apixp->x_vectbl[vector];
6967ff178cdSJimmy Vetayases
6977ff178cdSJimmy Vetayases ASSERT(IS_VECT_FREE(vecp));
6987ff178cdSJimmy Vetayases
6997ff178cdSJimmy Vetayases if (vecp == NULL) {
7007ff178cdSJimmy Vetayases vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP);
7017ff178cdSJimmy Vetayases if (vecp == NULL) {
7027ff178cdSJimmy Vetayases cmn_err(CE_WARN, "apix: no memory to allocate vector");
7037ff178cdSJimmy Vetayases return (NULL);
7047ff178cdSJimmy Vetayases }
7057ff178cdSJimmy Vetayases apixp->x_vectbl[vector] = vecp;
7067ff178cdSJimmy Vetayases }
7077ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_ALLOCED;
7087ff178cdSJimmy Vetayases vecp->v_cpuid = vecp->v_bound_cpuid = cpuid;
7097ff178cdSJimmy Vetayases vecp->v_vector = vector;
7107ff178cdSJimmy Vetayases
7117ff178cdSJimmy Vetayases return (vecp);
7127ff178cdSJimmy Vetayases }
7137ff178cdSJimmy Vetayases
7147ff178cdSJimmy Vetayases static void
apix_cleanup_vector(apix_vector_t * vecp)7157ff178cdSJimmy Vetayases apix_cleanup_vector(apix_vector_t *vecp)
7167ff178cdSJimmy Vetayases {
7177ff178cdSJimmy Vetayases ASSERT(vecp->v_share == 0);
7187ff178cdSJimmy Vetayases vecp->v_bound_cpuid = IRQ_UNINIT;
7197ff178cdSJimmy Vetayases vecp->v_state = APIX_STATE_FREED;
7207ff178cdSJimmy Vetayases vecp->v_type = 0;
7217ff178cdSJimmy Vetayases vecp->v_flags = 0;
7227ff178cdSJimmy Vetayases vecp->v_busy = 0;
7231053f4b7SPrasad Singamsetty vecp->v_intrmap_private = NULL;
7247ff178cdSJimmy Vetayases }
7257ff178cdSJimmy Vetayases
7267ff178cdSJimmy Vetayases static void
apix_dprint_vector(apix_vector_t * vecp,dev_info_t * dip,int count)7277ff178cdSJimmy Vetayases apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count)
7287ff178cdSJimmy Vetayases {
7297ff178cdSJimmy Vetayases #ifdef DEBUG
7307ff178cdSJimmy Vetayases major_t major;
7317ff178cdSJimmy Vetayases char *name, *drv_name;
7327ff178cdSJimmy Vetayases int instance, len, t_len;
7337ff178cdSJimmy Vetayases char mesg[1024] = "apix: ";
7347ff178cdSJimmy Vetayases
7357ff178cdSJimmy Vetayases t_len = sizeof (mesg);
7367ff178cdSJimmy Vetayases len = strlen(mesg);
7377ff178cdSJimmy Vetayases if (dip != NULL) {
7387ff178cdSJimmy Vetayases name = ddi_get_name(dip);
7397ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
7407ff178cdSJimmy Vetayases drv_name = ddi_major_to_name(major);
7417ff178cdSJimmy Vetayases instance = ddi_get_instance(dip);
7427ff178cdSJimmy Vetayases (void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ",
7437ff178cdSJimmy Vetayases name, drv_name, instance);
7447ff178cdSJimmy Vetayases }
7457ff178cdSJimmy Vetayases len = strlen(mesg);
7467ff178cdSJimmy Vetayases
7477ff178cdSJimmy Vetayases switch (vecp->v_type) {
7487ff178cdSJimmy Vetayases case APIX_TYPE_FIXED:
7497ff178cdSJimmy Vetayases (void) snprintf(mesg + len, t_len - len, "irqno %d",
7507ff178cdSJimmy Vetayases vecp->v_inum);
7517ff178cdSJimmy Vetayases break;
7527ff178cdSJimmy Vetayases case APIX_TYPE_MSI:
7537ff178cdSJimmy Vetayases (void) snprintf(mesg + len, t_len - len,
7547ff178cdSJimmy Vetayases "msi inum %d (count %d)", vecp->v_inum, count);
7557ff178cdSJimmy Vetayases break;
7567ff178cdSJimmy Vetayases case APIX_TYPE_MSIX:
7577ff178cdSJimmy Vetayases (void) snprintf(mesg + len, t_len - len, "msi-x inum %d",
7587ff178cdSJimmy Vetayases vecp->v_inum);
7597ff178cdSJimmy Vetayases break;
7607ff178cdSJimmy Vetayases default:
7617ff178cdSJimmy Vetayases break;
7627ff178cdSJimmy Vetayases
7637ff178cdSJimmy Vetayases }
7647ff178cdSJimmy Vetayases
7657ff178cdSJimmy Vetayases APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on "
7667ff178cdSJimmy Vetayases "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid));
7677ff178cdSJimmy Vetayases #endif /* DEBUG */
7687ff178cdSJimmy Vetayases }
7697ff178cdSJimmy Vetayases
7707ff178cdSJimmy Vetayases /*
7717ff178cdSJimmy Vetayases * Operations on avintr
7727ff178cdSJimmy Vetayases */
7737ff178cdSJimmy Vetayases
7747ff178cdSJimmy Vetayases #define INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip) \
7757ff178cdSJimmy Vetayases do { \
7767ff178cdSJimmy Vetayases (p)->av_intr_id = intr_id; \
7777ff178cdSJimmy Vetayases (p)->av_vector = f; \
7787ff178cdSJimmy Vetayases (p)->av_intarg1 = arg1; \
7797ff178cdSJimmy Vetayases (p)->av_intarg2 = arg2; \
7807ff178cdSJimmy Vetayases (p)->av_ticksp = ticksp; \
7817ff178cdSJimmy Vetayases (p)->av_prilevel = ipl; \
7827ff178cdSJimmy Vetayases (p)->av_dip = dip; \
7837ff178cdSJimmy Vetayases (p)->av_flags = 0; \
7847ff178cdSJimmy Vetayases _NOTE(CONSTCOND)} while (0)
7857ff178cdSJimmy Vetayases
7867ff178cdSJimmy Vetayases /*
7877ff178cdSJimmy Vetayases * Insert an interrupt service routine into chain by its priority from
7887ff178cdSJimmy Vetayases * high to low
7897ff178cdSJimmy Vetayases */
7907ff178cdSJimmy Vetayases static void
apix_insert_av(apix_vector_t * vecp,void * intr_id,avfunc f,caddr_t arg1,caddr_t arg2,uint64_t * ticksp,int ipl,dev_info_t * dip)7917ff178cdSJimmy Vetayases apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1,
7927ff178cdSJimmy Vetayases caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip)
7937ff178cdSJimmy Vetayases {
7947ff178cdSJimmy Vetayases struct autovec *p, *prep, *mem;
7957ff178cdSJimmy Vetayases
7967ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, "
7977ff178cdSJimmy Vetayases "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid));
7987ff178cdSJimmy Vetayases
7997ff178cdSJimmy Vetayases mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP);
8007ff178cdSJimmy Vetayases INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip);
8017ff178cdSJimmy Vetayases if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum])
8027ff178cdSJimmy Vetayases mem->av_flags |= AV_PENTRY_LEVEL;
8037ff178cdSJimmy Vetayases
8047ff178cdSJimmy Vetayases vecp->v_share++;
8057ff178cdSJimmy Vetayases vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri;
8067ff178cdSJimmy Vetayases if (vecp->v_autovect == NULL) { /* Nothing on list - put it at head */
8077ff178cdSJimmy Vetayases vecp->v_autovect = mem;
8087ff178cdSJimmy Vetayases return;
8097ff178cdSJimmy Vetayases }
8107ff178cdSJimmy Vetayases
8117ff178cdSJimmy Vetayases if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { /* MSI/X */
8127ff178cdSJimmy Vetayases ASSERT(vecp->v_share == 1); /* No sharing for MSI/X */
8137ff178cdSJimmy Vetayases
8147ff178cdSJimmy Vetayases INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp,
8157ff178cdSJimmy Vetayases ipl, dip);
8167ff178cdSJimmy Vetayases prep = vecp->v_autovect->av_link;
8177ff178cdSJimmy Vetayases vecp->v_autovect->av_link = NULL;
8187ff178cdSJimmy Vetayases
8197ff178cdSJimmy Vetayases /* Free the following autovect chain */
8207ff178cdSJimmy Vetayases while (prep != NULL) {
8217ff178cdSJimmy Vetayases ASSERT(prep->av_vector == NULL);
8227ff178cdSJimmy Vetayases
8237ff178cdSJimmy Vetayases p = prep;
8247ff178cdSJimmy Vetayases prep = prep->av_link;
8257ff178cdSJimmy Vetayases kmem_free(p, sizeof (struct autovec));
8267ff178cdSJimmy Vetayases }
8277ff178cdSJimmy Vetayases
8287ff178cdSJimmy Vetayases kmem_free(mem, sizeof (struct autovec));
8297ff178cdSJimmy Vetayases return;
8307ff178cdSJimmy Vetayases }
8317ff178cdSJimmy Vetayases
8327ff178cdSJimmy Vetayases /* find where it goes in list */
8337ff178cdSJimmy Vetayases prep = NULL;
8347ff178cdSJimmy Vetayases for (p = vecp->v_autovect; p != NULL; p = p->av_link) {
8357ff178cdSJimmy Vetayases if (p->av_vector && p->av_prilevel <= ipl)
8367ff178cdSJimmy Vetayases break;
8377ff178cdSJimmy Vetayases prep = p;
8387ff178cdSJimmy Vetayases }
8397ff178cdSJimmy Vetayases if (prep != NULL) {
8407ff178cdSJimmy Vetayases if (prep->av_vector == NULL) { /* freed struct available */
8417ff178cdSJimmy Vetayases INIT_AUTOVEC(prep, intr_id, f, arg1, arg2,
8427ff178cdSJimmy Vetayases ticksp, ipl, dip);
8437ff178cdSJimmy Vetayases prep->av_flags = mem->av_flags;
8447ff178cdSJimmy Vetayases kmem_free(mem, sizeof (struct autovec));
8457ff178cdSJimmy Vetayases return;
8467ff178cdSJimmy Vetayases }
8477ff178cdSJimmy Vetayases
8487ff178cdSJimmy Vetayases mem->av_link = prep->av_link;
8497ff178cdSJimmy Vetayases prep->av_link = mem;
8507ff178cdSJimmy Vetayases } else {
8517ff178cdSJimmy Vetayases /* insert new intpt at beginning of chain */
8527ff178cdSJimmy Vetayases mem->av_link = vecp->v_autovect;
8537ff178cdSJimmy Vetayases vecp->v_autovect = mem;
8547ff178cdSJimmy Vetayases }
8557ff178cdSJimmy Vetayases }
8567ff178cdSJimmy Vetayases
8577ff178cdSJimmy Vetayases /*
8587ff178cdSJimmy Vetayases * After having made a change to an autovector list, wait until we have
8597ff178cdSJimmy Vetayases * seen specified cpu not executing an interrupt at that level--so we
8607ff178cdSJimmy Vetayases * know our change has taken effect completely (no old state in registers,
8617ff178cdSJimmy Vetayases * etc).
8627ff178cdSJimmy Vetayases */
8637ff178cdSJimmy Vetayases #define APIX_CPU_ENABLED(_cp) \
8647ff178cdSJimmy Vetayases (quiesce_active == 0 && \
8657ff178cdSJimmy Vetayases (((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0))
8667ff178cdSJimmy Vetayases
8677ff178cdSJimmy Vetayases static void
apix_wait_till_seen(processorid_t cpuid,int ipl)8687ff178cdSJimmy Vetayases apix_wait_till_seen(processorid_t cpuid, int ipl)
8697ff178cdSJimmy Vetayases {
8707ff178cdSJimmy Vetayases struct cpu *cp = cpu[cpuid];
8717ff178cdSJimmy Vetayases
8727ff178cdSJimmy Vetayases if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid))
8737ff178cdSJimmy Vetayases return;
8747ff178cdSJimmy Vetayases
8757ff178cdSJimmy Vetayases /*
8767ff178cdSJimmy Vetayases * Don't wait if the CPU is quiesced or offlined. This can happen
8777ff178cdSJimmy Vetayases * when a CPU is running pause thread but hardware triggered an
8787ff178cdSJimmy Vetayases * interrupt and the interrupt gets queued.
8797ff178cdSJimmy Vetayases */
8807ff178cdSJimmy Vetayases for (;;) {
8817ff178cdSJimmy Vetayases if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) &&
8827ff178cdSJimmy Vetayases (!APIX_CPU_ENABLED(cp) ||
8837ff178cdSJimmy Vetayases !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl)))
8847ff178cdSJimmy Vetayases return;
8857ff178cdSJimmy Vetayases }
8867ff178cdSJimmy Vetayases }
8877ff178cdSJimmy Vetayases
8887ff178cdSJimmy Vetayases static void
apix_remove_av(apix_vector_t * vecp,struct autovec * target)8897ff178cdSJimmy Vetayases apix_remove_av(apix_vector_t *vecp, struct autovec *target)
8907ff178cdSJimmy Vetayases {
8917ff178cdSJimmy Vetayases int hi_pri = 0;
8927ff178cdSJimmy Vetayases struct autovec *p;
8937ff178cdSJimmy Vetayases
8947ff178cdSJimmy Vetayases if (target == NULL)
8957ff178cdSJimmy Vetayases return;
8967ff178cdSJimmy Vetayases
8977ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, "
8987ff178cdSJimmy Vetayases "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid));
8997ff178cdSJimmy Vetayases
9007ff178cdSJimmy Vetayases for (p = vecp->v_autovect; p; p = p->av_link) {
9017ff178cdSJimmy Vetayases if (p == target || p->av_vector == NULL)
9027ff178cdSJimmy Vetayases continue;
9037ff178cdSJimmy Vetayases hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri;
9047ff178cdSJimmy Vetayases }
9057ff178cdSJimmy Vetayases
9067ff178cdSJimmy Vetayases vecp->v_share--;
9077ff178cdSJimmy Vetayases vecp->v_pri = hi_pri;
9087ff178cdSJimmy Vetayases
9097ff178cdSJimmy Vetayases /*
9107ff178cdSJimmy Vetayases * This drops the handler from the chain, it can no longer be called.
9117ff178cdSJimmy Vetayases * However, there is no guarantee that the handler is not currently
9127ff178cdSJimmy Vetayases * still executing.
9137ff178cdSJimmy Vetayases */
9147ff178cdSJimmy Vetayases target->av_vector = NULL;
9157ff178cdSJimmy Vetayases /*
9167ff178cdSJimmy Vetayases * There is a race where we could be just about to pick up the ticksp
9177ff178cdSJimmy Vetayases * pointer to increment it after returning from the service routine
9187ff178cdSJimmy Vetayases * in av_dispatch_autovect. Rather than NULL it out let's just point
9197ff178cdSJimmy Vetayases * it off to something safe so that any final tick update attempt
9207ff178cdSJimmy Vetayases * won't fault.
9217ff178cdSJimmy Vetayases */
9227ff178cdSJimmy Vetayases target->av_ticksp = &dummy_tick;
9237ff178cdSJimmy Vetayases apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel);
9247ff178cdSJimmy Vetayases }
9257ff178cdSJimmy Vetayases
9267ff178cdSJimmy Vetayases static struct autovec *
apix_find_av(apix_vector_t * vecp,void * intr_id,avfunc f)9277ff178cdSJimmy Vetayases apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f)
9287ff178cdSJimmy Vetayases {
9297ff178cdSJimmy Vetayases struct autovec *p;
9307ff178cdSJimmy Vetayases
9317ff178cdSJimmy Vetayases for (p = vecp->v_autovect; p; p = p->av_link) {
9327ff178cdSJimmy Vetayases if ((p->av_vector == f) && (p->av_intr_id == intr_id)) {
9337ff178cdSJimmy Vetayases /* found the handler */
9347ff178cdSJimmy Vetayases return (p);
9357ff178cdSJimmy Vetayases }
9367ff178cdSJimmy Vetayases }
9377ff178cdSJimmy Vetayases
9387ff178cdSJimmy Vetayases return (NULL);
9397ff178cdSJimmy Vetayases }
9407ff178cdSJimmy Vetayases
9417ff178cdSJimmy Vetayases static apix_vector_t *
apix_find_vector_by_avintr(void * intr_id,avfunc f)9427ff178cdSJimmy Vetayases apix_find_vector_by_avintr(void *intr_id, avfunc f)
9437ff178cdSJimmy Vetayases {
9447ff178cdSJimmy Vetayases apix_vector_t *vecp;
9457ff178cdSJimmy Vetayases processorid_t n;
9467ff178cdSJimmy Vetayases uchar_t v;
9477ff178cdSJimmy Vetayases
9487ff178cdSJimmy Vetayases for (n = 0; n < apic_nproc; n++) {
9497ff178cdSJimmy Vetayases if (!apix_is_cpu_enabled(n))
9507ff178cdSJimmy Vetayases continue;
9517ff178cdSJimmy Vetayases
9527ff178cdSJimmy Vetayases for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) {
9537ff178cdSJimmy Vetayases vecp = xv_vector(n, v);
9547ff178cdSJimmy Vetayases if (vecp == NULL ||
9557ff178cdSJimmy Vetayases vecp->v_state <= APIX_STATE_OBSOLETED)
9567ff178cdSJimmy Vetayases continue;
9577ff178cdSJimmy Vetayases
9587ff178cdSJimmy Vetayases if (apix_find_av(vecp, intr_id, f) != NULL)
9597ff178cdSJimmy Vetayases return (vecp);
9607ff178cdSJimmy Vetayases }
9617ff178cdSJimmy Vetayases }
9627ff178cdSJimmy Vetayases
9637ff178cdSJimmy Vetayases return (NULL);
9647ff178cdSJimmy Vetayases }
9657ff178cdSJimmy Vetayases
9667ff178cdSJimmy Vetayases /*
9677ff178cdSJimmy Vetayases * Add interrupt service routine.
9687ff178cdSJimmy Vetayases *
9697ff178cdSJimmy Vetayases * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually
9707ff178cdSJimmy Vetayases * IRQ no. A vector is then allocated. Otherwise, the vector is already
9717ff178cdSJimmy Vetayases * allocated. The input argument virt_vect is virtual vector of format
9727ff178cdSJimmy Vetayases * APIX_VIRTVEC_VECTOR(cpuid, vector).
9737ff178cdSJimmy Vetayases *
9747ff178cdSJimmy Vetayases * Return 1 on success, 0 on failure.
9757ff178cdSJimmy Vetayases */
9767ff178cdSJimmy Vetayases int
apix_add_avintr(void * intr_id,int ipl,avfunc xxintr,char * name,int virt_vect,caddr_t arg1,caddr_t arg2,uint64_t * ticksp,dev_info_t * dip)9777ff178cdSJimmy Vetayases apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name,
9787ff178cdSJimmy Vetayases int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp,
9797ff178cdSJimmy Vetayases dev_info_t *dip)
9807ff178cdSJimmy Vetayases {
9817ff178cdSJimmy Vetayases int cpuid;
9827ff178cdSJimmy Vetayases uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect);
9837ff178cdSJimmy Vetayases apix_vector_t *vecp;
9847ff178cdSJimmy Vetayases
9857ff178cdSJimmy Vetayases if (xxintr == NULL) {
9867ff178cdSJimmy Vetayases cmn_err(CE_WARN, "Attempt to add null for %s "
9877ff178cdSJimmy Vetayases "on vector 0x%x,0x%x", name,
9887ff178cdSJimmy Vetayases APIX_VIRTVEC_CPU(virt_vect),
9897ff178cdSJimmy Vetayases APIX_VIRTVEC_VECTOR(virt_vect));
9907ff178cdSJimmy Vetayases return (0);
9917ff178cdSJimmy Vetayases }
9927ff178cdSJimmy Vetayases
9937ff178cdSJimmy Vetayases if (v >= APIX_IPI_MIN) /* IPIs */
9947ff178cdSJimmy Vetayases return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2));
9957ff178cdSJimmy Vetayases
9967ff178cdSJimmy Vetayases if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */
9977ff178cdSJimmy Vetayases int irqno = virt_vect;
9987ff178cdSJimmy Vetayases int inum = GET_INTR_INUM(intr_id);
9997ff178cdSJimmy Vetayases
10007ff178cdSJimmy Vetayases /*
10017ff178cdSJimmy Vetayases * Senarios include:
10027ff178cdSJimmy Vetayases * a. add_avintr() is called before irqp initialized (legacy)
10037ff178cdSJimmy Vetayases * b. irqp is initialized, vector is not allocated (fixed)
10047ff178cdSJimmy Vetayases * c. irqp is initialized, vector is allocated (fixed & shared)
10057ff178cdSJimmy Vetayases */
10067ff178cdSJimmy Vetayases if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL)
10077ff178cdSJimmy Vetayases return (0);
10087ff178cdSJimmy Vetayases
10097ff178cdSJimmy Vetayases cpuid = vecp->v_cpuid;
10107ff178cdSJimmy Vetayases v = vecp->v_vector;
10117ff178cdSJimmy Vetayases virt_vect = APIX_VIRTVECTOR(cpuid, v);
10127ff178cdSJimmy Vetayases } else { /* got virtual vector */
10137ff178cdSJimmy Vetayases cpuid = APIX_VIRTVEC_CPU(virt_vect);
10147ff178cdSJimmy Vetayases vecp = xv_vector(cpuid, v);
10157ff178cdSJimmy Vetayases ASSERT(vecp != NULL);
10167ff178cdSJimmy Vetayases }
10177ff178cdSJimmy Vetayases
10187ff178cdSJimmy Vetayases lock_set(&apix_lock);
10197ff178cdSJimmy Vetayases if (vecp->v_state <= APIX_STATE_OBSOLETED) {
10207ff178cdSJimmy Vetayases vecp = NULL;
10217ff178cdSJimmy Vetayases
10227ff178cdSJimmy Vetayases /*
10237ff178cdSJimmy Vetayases * Basically the allocated but not enabled interrupts
10247ff178cdSJimmy Vetayases * will not get re-targeted. But MSIs in allocated state
10257ff178cdSJimmy Vetayases * could be re-targeted due to group re-targeting.
10267ff178cdSJimmy Vetayases */
10277ff178cdSJimmy Vetayases if (intr_id != NULL && dip != NULL) {
10287ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *hdlp = intr_id;
10297ff178cdSJimmy Vetayases vecp = apix_get_dev_map(dip, hdlp->ih_inum,
10307ff178cdSJimmy Vetayases hdlp->ih_type);
10317ff178cdSJimmy Vetayases ASSERT(vecp->v_state == APIX_STATE_ALLOCED);
10327ff178cdSJimmy Vetayases }
10337ff178cdSJimmy Vetayases if (vecp == NULL) {
10347ff178cdSJimmy Vetayases lock_clear(&apix_lock);
10357ff178cdSJimmy Vetayases cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x "
10367ff178cdSJimmy Vetayases " for %p to add", cpuid, v, intr_id);
10377ff178cdSJimmy Vetayases return (0);
10387ff178cdSJimmy Vetayases }
10397ff178cdSJimmy Vetayases cpuid = vecp->v_cpuid;
10407ff178cdSJimmy Vetayases virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector);
10417ff178cdSJimmy Vetayases }
10427ff178cdSJimmy Vetayases
10437ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpuid);
10447ff178cdSJimmy Vetayases apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip);
10457ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
10467ff178cdSJimmy Vetayases
10477ff178cdSJimmy Vetayases (void) apix_addspl(virt_vect, ipl, 0, 0);
10487ff178cdSJimmy Vetayases
10497ff178cdSJimmy Vetayases lock_clear(&apix_lock);
10507ff178cdSJimmy Vetayases
10517ff178cdSJimmy Vetayases return (1);
10527ff178cdSJimmy Vetayases }
10537ff178cdSJimmy Vetayases
10547ff178cdSJimmy Vetayases /*
10557ff178cdSJimmy Vetayases * Remove avintr
10567ff178cdSJimmy Vetayases *
10577ff178cdSJimmy Vetayases * For fixed, if it's the last one of shared interrupts, free the vector.
10587ff178cdSJimmy Vetayases * For msi/x, only disable the interrupt but not free the vector, which
10597ff178cdSJimmy Vetayases * is freed by PSM_XXX_FREE_XXX.
10607ff178cdSJimmy Vetayases */
10617ff178cdSJimmy Vetayases void
apix_rem_avintr(void * intr_id,int ipl,avfunc xxintr,int virt_vect)10627ff178cdSJimmy Vetayases apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect)
10637ff178cdSJimmy Vetayases {
10647ff178cdSJimmy Vetayases avfunc f;
10657ff178cdSJimmy Vetayases apix_vector_t *vecp;
10667ff178cdSJimmy Vetayases struct autovec *avp;
10677ff178cdSJimmy Vetayases processorid_t cpuid;
10687ff178cdSJimmy Vetayases
10697ff178cdSJimmy Vetayases if ((f = xxintr) == NULL)
10707ff178cdSJimmy Vetayases return;
10717ff178cdSJimmy Vetayases
10727ff178cdSJimmy Vetayases lock_set(&apix_lock);
10737ff178cdSJimmy Vetayases
10747ff178cdSJimmy Vetayases if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */
10757ff178cdSJimmy Vetayases vecp = apix_intx_get_vector(virt_vect);
10767ff178cdSJimmy Vetayases virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
10777ff178cdSJimmy Vetayases } else /* got virtual vector */
10787ff178cdSJimmy Vetayases vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect),
10797ff178cdSJimmy Vetayases APIX_VIRTVEC_VECTOR(virt_vect));
10807ff178cdSJimmy Vetayases
10817ff178cdSJimmy Vetayases if (vecp == NULL) {
10827ff178cdSJimmy Vetayases lock_clear(&apix_lock);
10837ff178cdSJimmy Vetayases cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove",
10847ff178cdSJimmy Vetayases APIX_VIRTVEC_CPU(virt_vect),
10857ff178cdSJimmy Vetayases APIX_VIRTVEC_VECTOR(virt_vect));
10867ff178cdSJimmy Vetayases return;
10877ff178cdSJimmy Vetayases }
10887ff178cdSJimmy Vetayases
10897ff178cdSJimmy Vetayases if (vecp->v_state <= APIX_STATE_OBSOLETED ||
10907ff178cdSJimmy Vetayases ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) {
10917ff178cdSJimmy Vetayases /*
10927ff178cdSJimmy Vetayases * It's possible that the interrupt is rebound to a
10937ff178cdSJimmy Vetayases * different cpu before rem_avintr() is called. Search
10947ff178cdSJimmy Vetayases * through all vectors once it happens.
10957ff178cdSJimmy Vetayases */
10967ff178cdSJimmy Vetayases if ((vecp = apix_find_vector_by_avintr(intr_id, f))
10977ff178cdSJimmy Vetayases == NULL) {
10987ff178cdSJimmy Vetayases lock_clear(&apix_lock);
10997ff178cdSJimmy Vetayases cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x "
11007ff178cdSJimmy Vetayases "for %p to remove", APIX_VIRTVEC_CPU(virt_vect),
11017ff178cdSJimmy Vetayases APIX_VIRTVEC_VECTOR(virt_vect), intr_id);
11027ff178cdSJimmy Vetayases return;
11037ff178cdSJimmy Vetayases }
11047ff178cdSJimmy Vetayases virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector);
11057ff178cdSJimmy Vetayases avp = apix_find_av(vecp, intr_id, f);
11067ff178cdSJimmy Vetayases }
11077ff178cdSJimmy Vetayases cpuid = vecp->v_cpuid;
11087ff178cdSJimmy Vetayases
11097ff178cdSJimmy Vetayases /* disable interrupt */
11107ff178cdSJimmy Vetayases (void) apix_delspl(virt_vect, ipl, 0, 0);
11117ff178cdSJimmy Vetayases
11127ff178cdSJimmy Vetayases /* remove ISR entry */
11137ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpuid);
11147ff178cdSJimmy Vetayases apix_remove_av(vecp, avp);
11157ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
11167ff178cdSJimmy Vetayases
11177ff178cdSJimmy Vetayases lock_clear(&apix_lock);
11187ff178cdSJimmy Vetayases }
11197ff178cdSJimmy Vetayases
11207ff178cdSJimmy Vetayases /*
11217ff178cdSJimmy Vetayases * Device to vector mapping table
11227ff178cdSJimmy Vetayases */
11237ff178cdSJimmy Vetayases
11247ff178cdSJimmy Vetayases static void
apix_clear_dev_map(dev_info_t * dip,int inum,int type)11257ff178cdSJimmy Vetayases apix_clear_dev_map(dev_info_t *dip, int inum, int type)
11267ff178cdSJimmy Vetayases {
11277ff178cdSJimmy Vetayases char *name;
11287ff178cdSJimmy Vetayases major_t major;
11297ff178cdSJimmy Vetayases apix_dev_vector_t *dvp, *prev = NULL;
11307ff178cdSJimmy Vetayases int found = 0;
11317ff178cdSJimmy Vetayases
11327ff178cdSJimmy Vetayases name = ddi_get_name(dip);
11337ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
11347ff178cdSJimmy Vetayases
11357ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
11367ff178cdSJimmy Vetayases
11377ff178cdSJimmy Vetayases for (dvp = apix_dev_vector[major]; dvp != NULL;
11387ff178cdSJimmy Vetayases prev = dvp, dvp = dvp->dv_next) {
11397ff178cdSJimmy Vetayases if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
11407ff178cdSJimmy Vetayases dvp->dv_type == type) {
11417ff178cdSJimmy Vetayases found++;
11427ff178cdSJimmy Vetayases break;
11437ff178cdSJimmy Vetayases }
11447ff178cdSJimmy Vetayases }
11457ff178cdSJimmy Vetayases
11467ff178cdSJimmy Vetayases if (!found) {
11477ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
11487ff178cdSJimmy Vetayases return;
11497ff178cdSJimmy Vetayases }
11507ff178cdSJimmy Vetayases
11517ff178cdSJimmy Vetayases if (prev != NULL)
11527ff178cdSJimmy Vetayases prev->dv_next = dvp->dv_next;
11537ff178cdSJimmy Vetayases
11547ff178cdSJimmy Vetayases if (apix_dev_vector[major] == dvp)
11557ff178cdSJimmy Vetayases apix_dev_vector[major] = dvp->dv_next;
11567ff178cdSJimmy Vetayases
11577ff178cdSJimmy Vetayases dvp->dv_vector->v_devp = NULL;
11587ff178cdSJimmy Vetayases
11597ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
11607ff178cdSJimmy Vetayases
11617ff178cdSJimmy Vetayases kmem_free(dvp, sizeof (apix_dev_vector_t));
11627ff178cdSJimmy Vetayases }
11637ff178cdSJimmy Vetayases
11647ff178cdSJimmy Vetayases void
apix_set_dev_map(apix_vector_t * vecp,dev_info_t * dip,int inum)11657ff178cdSJimmy Vetayases apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum)
11667ff178cdSJimmy Vetayases {
11677ff178cdSJimmy Vetayases apix_dev_vector_t *dvp;
11687ff178cdSJimmy Vetayases char *name;
11697ff178cdSJimmy Vetayases major_t major;
11707ff178cdSJimmy Vetayases uint32_t found = 0;
11717ff178cdSJimmy Vetayases
11727ff178cdSJimmy Vetayases ASSERT(dip != NULL);
11737ff178cdSJimmy Vetayases name = ddi_get_name(dip);
11747ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
11757ff178cdSJimmy Vetayases
11767ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
11777ff178cdSJimmy Vetayases
11787ff178cdSJimmy Vetayases for (dvp = apix_dev_vector[major]; dvp != NULL;
11797ff178cdSJimmy Vetayases dvp = dvp->dv_next) {
11807ff178cdSJimmy Vetayases if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
11817ff178cdSJimmy Vetayases dvp->dv_type == vecp->v_type) {
11827ff178cdSJimmy Vetayases found++;
11837ff178cdSJimmy Vetayases break;
11847ff178cdSJimmy Vetayases }
11857ff178cdSJimmy Vetayases }
11867ff178cdSJimmy Vetayases
11877ff178cdSJimmy Vetayases if (found == 0) { /* not found */
11887ff178cdSJimmy Vetayases dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP);
11897ff178cdSJimmy Vetayases dvp->dv_dip = dip;
11907ff178cdSJimmy Vetayases dvp->dv_inum = inum;
11917ff178cdSJimmy Vetayases dvp->dv_type = vecp->v_type;
11927ff178cdSJimmy Vetayases
11937ff178cdSJimmy Vetayases dvp->dv_next = apix_dev_vector[major];
11947ff178cdSJimmy Vetayases apix_dev_vector[major] = dvp;
11957ff178cdSJimmy Vetayases }
11967ff178cdSJimmy Vetayases dvp->dv_vector = vecp;
11977ff178cdSJimmy Vetayases vecp->v_devp = dvp;
11987ff178cdSJimmy Vetayases
11997ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
12007ff178cdSJimmy Vetayases
12017ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p "
12027ff178cdSJimmy Vetayases "inum=0x%x vector=0x%x/0x%x\n",
12037ff178cdSJimmy Vetayases (void *)dip, inum, vecp->v_cpuid, vecp->v_vector));
12047ff178cdSJimmy Vetayases }
12057ff178cdSJimmy Vetayases
12067ff178cdSJimmy Vetayases apix_vector_t *
apix_get_dev_map(dev_info_t * dip,int inum,int type)12077ff178cdSJimmy Vetayases apix_get_dev_map(dev_info_t *dip, int inum, int type)
12087ff178cdSJimmy Vetayases {
12097ff178cdSJimmy Vetayases char *name;
12107ff178cdSJimmy Vetayases major_t major;
12117ff178cdSJimmy Vetayases apix_dev_vector_t *dvp;
12127ff178cdSJimmy Vetayases apix_vector_t *vecp;
12137ff178cdSJimmy Vetayases
12147ff178cdSJimmy Vetayases name = ddi_get_name(dip);
12157ff178cdSJimmy Vetayases if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE)
12167ff178cdSJimmy Vetayases return (NULL);
12177ff178cdSJimmy Vetayases
12187ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
12197ff178cdSJimmy Vetayases for (dvp = apix_dev_vector[major]; dvp != NULL;
12207ff178cdSJimmy Vetayases dvp = dvp->dv_next) {
12217ff178cdSJimmy Vetayases if (dvp->dv_dip == dip && dvp->dv_inum == inum &&
12227ff178cdSJimmy Vetayases dvp->dv_type == type) {
12237ff178cdSJimmy Vetayases vecp = dvp->dv_vector;
12247ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
12257ff178cdSJimmy Vetayases return (vecp);
12267ff178cdSJimmy Vetayases }
12277ff178cdSJimmy Vetayases }
12287ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
12297ff178cdSJimmy Vetayases
12307ff178cdSJimmy Vetayases return (NULL);
12317ff178cdSJimmy Vetayases }
12327ff178cdSJimmy Vetayases
12337ff178cdSJimmy Vetayases /*
12347ff178cdSJimmy Vetayases * Get minimum inum for specified device, used for MSI
12357ff178cdSJimmy Vetayases */
12367ff178cdSJimmy Vetayases int
apix_get_min_dev_inum(dev_info_t * dip,int type)12377ff178cdSJimmy Vetayases apix_get_min_dev_inum(dev_info_t *dip, int type)
12387ff178cdSJimmy Vetayases {
12397ff178cdSJimmy Vetayases char *name;
12407ff178cdSJimmy Vetayases major_t major;
12417ff178cdSJimmy Vetayases apix_dev_vector_t *dvp;
12427ff178cdSJimmy Vetayases int inum = -1;
12437ff178cdSJimmy Vetayases
12447ff178cdSJimmy Vetayases name = ddi_get_name(dip);
12457ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
12467ff178cdSJimmy Vetayases
12477ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
12487ff178cdSJimmy Vetayases for (dvp = apix_dev_vector[major]; dvp != NULL;
12497ff178cdSJimmy Vetayases dvp = dvp->dv_next) {
12507ff178cdSJimmy Vetayases if (dvp->dv_dip == dip && dvp->dv_type == type) {
12517ff178cdSJimmy Vetayases if (inum == -1)
12527ff178cdSJimmy Vetayases inum = dvp->dv_inum;
12537ff178cdSJimmy Vetayases else
12547ff178cdSJimmy Vetayases inum = (dvp->dv_inum < inum) ?
12557ff178cdSJimmy Vetayases dvp->dv_inum : inum;
12567ff178cdSJimmy Vetayases }
12577ff178cdSJimmy Vetayases }
12587ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
12597ff178cdSJimmy Vetayases
12607ff178cdSJimmy Vetayases return (inum);
12617ff178cdSJimmy Vetayases }
12627ff178cdSJimmy Vetayases
12637ff178cdSJimmy Vetayases int
apix_get_max_dev_inum(dev_info_t * dip,int type)12647ff178cdSJimmy Vetayases apix_get_max_dev_inum(dev_info_t *dip, int type)
12657ff178cdSJimmy Vetayases {
12667ff178cdSJimmy Vetayases char *name;
12677ff178cdSJimmy Vetayases major_t major;
12687ff178cdSJimmy Vetayases apix_dev_vector_t *dvp;
12697ff178cdSJimmy Vetayases int inum = -1;
12707ff178cdSJimmy Vetayases
12717ff178cdSJimmy Vetayases name = ddi_get_name(dip);
12727ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
12737ff178cdSJimmy Vetayases
12747ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
12757ff178cdSJimmy Vetayases for (dvp = apix_dev_vector[major]; dvp != NULL;
12767ff178cdSJimmy Vetayases dvp = dvp->dv_next) {
12777ff178cdSJimmy Vetayases if (dvp->dv_dip == dip && dvp->dv_type == type) {
12787ff178cdSJimmy Vetayases if (inum == -1)
12797ff178cdSJimmy Vetayases inum = dvp->dv_inum;
12807ff178cdSJimmy Vetayases else
12817ff178cdSJimmy Vetayases inum = (dvp->dv_inum > inum) ?
12827ff178cdSJimmy Vetayases dvp->dv_inum : inum;
12837ff178cdSJimmy Vetayases }
12847ff178cdSJimmy Vetayases }
12857ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
12867ff178cdSJimmy Vetayases
12877ff178cdSJimmy Vetayases return (inum);
12887ff178cdSJimmy Vetayases }
12897ff178cdSJimmy Vetayases
12907ff178cdSJimmy Vetayases /*
12917ff178cdSJimmy Vetayases * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu
12927ff178cdSJimmy Vetayases * binding policy
12937ff178cdSJimmy Vetayases */
12947ff178cdSJimmy Vetayases
12957ff178cdSJimmy Vetayases static uint32_t
apix_get_dev_binding(dev_info_t * dip)12967ff178cdSJimmy Vetayases apix_get_dev_binding(dev_info_t *dip)
12977ff178cdSJimmy Vetayases {
12987ff178cdSJimmy Vetayases major_t major;
12997ff178cdSJimmy Vetayases char *name;
13007ff178cdSJimmy Vetayases uint32_t cpu = IRQ_UNINIT;
13017ff178cdSJimmy Vetayases
13027ff178cdSJimmy Vetayases name = ddi_get_name(dip);
13037ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
13047ff178cdSJimmy Vetayases if (major < devcnt) {
13057ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
13067ff178cdSJimmy Vetayases cpu = apix_major_to_cpu[major];
13077ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
13087ff178cdSJimmy Vetayases }
13097ff178cdSJimmy Vetayases
13107ff178cdSJimmy Vetayases return (cpu);
13117ff178cdSJimmy Vetayases }
13127ff178cdSJimmy Vetayases
13137ff178cdSJimmy Vetayases static void
apix_set_dev_binding(dev_info_t * dip,uint32_t cpu)13147ff178cdSJimmy Vetayases apix_set_dev_binding(dev_info_t *dip, uint32_t cpu)
13157ff178cdSJimmy Vetayases {
13167ff178cdSJimmy Vetayases major_t major;
13177ff178cdSJimmy Vetayases char *name;
13187ff178cdSJimmy Vetayases
13197ff178cdSJimmy Vetayases /* setup major to cpu mapping */
13207ff178cdSJimmy Vetayases name = ddi_get_name(dip);
13217ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
13227ff178cdSJimmy Vetayases if (apix_major_to_cpu[major] == IRQ_UNINIT) {
13237ff178cdSJimmy Vetayases mutex_enter(&apix_mutex);
13247ff178cdSJimmy Vetayases apix_major_to_cpu[major] = cpu;
13257ff178cdSJimmy Vetayases mutex_exit(&apix_mutex);
13267ff178cdSJimmy Vetayases }
13277ff178cdSJimmy Vetayases }
13287ff178cdSJimmy Vetayases
13297ff178cdSJimmy Vetayases /*
13307ff178cdSJimmy Vetayases * return the cpu to which this intr should be bound.
13317ff178cdSJimmy Vetayases * Check properties or any other mechanism to see if user wants it
13327ff178cdSJimmy Vetayases * bound to a specific CPU. If so, return the cpu id with high bit set.
13337ff178cdSJimmy Vetayases * If not, use the policy to choose a cpu and return the id.
13347ff178cdSJimmy Vetayases */
13357ff178cdSJimmy Vetayases uint32_t
apix_bind_cpu(dev_info_t * dip)13367ff178cdSJimmy Vetayases apix_bind_cpu(dev_info_t *dip)
13377ff178cdSJimmy Vetayases {
13387ff178cdSJimmy Vetayases int instance, instno, prop_len, bind_cpu, count;
13397ff178cdSJimmy Vetayases uint_t i, rc;
13407ff178cdSJimmy Vetayases major_t major;
13417ff178cdSJimmy Vetayases char *name, *drv_name, *prop_val, *cptr;
13427ff178cdSJimmy Vetayases char prop_name[32];
13437ff178cdSJimmy Vetayases
13447ff178cdSJimmy Vetayases lock_set(&apix_lock);
13457ff178cdSJimmy Vetayases
13467ff178cdSJimmy Vetayases if (apic_intr_policy == INTR_LOWEST_PRIORITY) {
13477ff178cdSJimmy Vetayases cmn_err(CE_WARN, "apix: unsupported interrupt binding policy "
13487ff178cdSJimmy Vetayases "LOWEST PRIORITY, use ROUND ROBIN instead");
13497ff178cdSJimmy Vetayases apic_intr_policy = INTR_ROUND_ROBIN;
13507ff178cdSJimmy Vetayases }
13517ff178cdSJimmy Vetayases
13527ff178cdSJimmy Vetayases if (apic_nproc == 1) {
13537ff178cdSJimmy Vetayases lock_clear(&apix_lock);
13547ff178cdSJimmy Vetayases return (0);
13557ff178cdSJimmy Vetayases }
13567ff178cdSJimmy Vetayases
13577ff178cdSJimmy Vetayases drv_name = NULL;
13587ff178cdSJimmy Vetayases rc = DDI_PROP_NOT_FOUND;
13597ff178cdSJimmy Vetayases major = (major_t)-1;
13607ff178cdSJimmy Vetayases if (dip != NULL) {
13617ff178cdSJimmy Vetayases name = ddi_get_name(dip);
13627ff178cdSJimmy Vetayases major = ddi_name_to_major(name);
13637ff178cdSJimmy Vetayases drv_name = ddi_major_to_name(major);
13647ff178cdSJimmy Vetayases instance = ddi_get_instance(dip);
13657ff178cdSJimmy Vetayases if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
13667ff178cdSJimmy Vetayases bind_cpu = apix_get_dev_binding(dip);
13677ff178cdSJimmy Vetayases if (bind_cpu != IRQ_UNINIT) {
13687ff178cdSJimmy Vetayases lock_clear(&apix_lock);
13697ff178cdSJimmy Vetayases return (bind_cpu);
13707ff178cdSJimmy Vetayases }
13717ff178cdSJimmy Vetayases }
13727ff178cdSJimmy Vetayases /*
13737ff178cdSJimmy Vetayases * search for "drvname"_intpt_bind_cpus property first, the
13747ff178cdSJimmy Vetayases * syntax of the property should be "a[,b,c,...]" where
13757ff178cdSJimmy Vetayases * instance 0 binds to cpu a, instance 1 binds to cpu b,
13767ff178cdSJimmy Vetayases * instance 3 binds to cpu c...
13777ff178cdSJimmy Vetayases * ddi_getlongprop() will search /option first, then /
13787ff178cdSJimmy Vetayases * if "drvname"_intpt_bind_cpus doesn't exist, then find
13797ff178cdSJimmy Vetayases * intpt_bind_cpus property. The syntax is the same, and
13807ff178cdSJimmy Vetayases * it applies to all the devices if its "drvname" specific
13817ff178cdSJimmy Vetayases * property doesn't exist
13827ff178cdSJimmy Vetayases */
13837ff178cdSJimmy Vetayases (void) strcpy(prop_name, drv_name);
13847ff178cdSJimmy Vetayases (void) strcat(prop_name, "_intpt_bind_cpus");
13857ff178cdSJimmy Vetayases rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name,
13867ff178cdSJimmy Vetayases (caddr_t)&prop_val, &prop_len);
13877ff178cdSJimmy Vetayases if (rc != DDI_PROP_SUCCESS) {
13887ff178cdSJimmy Vetayases rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0,
13897ff178cdSJimmy Vetayases "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len);
13907ff178cdSJimmy Vetayases }
13917ff178cdSJimmy Vetayases }
13927ff178cdSJimmy Vetayases if (rc == DDI_PROP_SUCCESS) {
13937ff178cdSJimmy Vetayases for (i = count = 0; i < (prop_len - 1); i++)
13947ff178cdSJimmy Vetayases if (prop_val[i] == ',')
13957ff178cdSJimmy Vetayases count++;
13967ff178cdSJimmy Vetayases if (prop_val[i-1] != ',')
13977ff178cdSJimmy Vetayases count++;
13987ff178cdSJimmy Vetayases /*
13997ff178cdSJimmy Vetayases * if somehow the binding instances defined in the
14007ff178cdSJimmy Vetayases * property are not enough for this instno., then
14017ff178cdSJimmy Vetayases * reuse the pattern for the next instance until
14027ff178cdSJimmy Vetayases * it reaches the requested instno
14037ff178cdSJimmy Vetayases */
14047ff178cdSJimmy Vetayases instno = instance % count;
14057ff178cdSJimmy Vetayases i = 0;
14067ff178cdSJimmy Vetayases cptr = prop_val;
14077ff178cdSJimmy Vetayases while (i < instno)
14087ff178cdSJimmy Vetayases if (*cptr++ == ',')
14097ff178cdSJimmy Vetayases i++;
14107ff178cdSJimmy Vetayases bind_cpu = stoi(&cptr);
14117ff178cdSJimmy Vetayases kmem_free(prop_val, prop_len);
14127ff178cdSJimmy Vetayases /* if specific cpu is bogus, then default to cpu 0 */
14137ff178cdSJimmy Vetayases if (bind_cpu >= apic_nproc) {
14147ff178cdSJimmy Vetayases cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present",
14157ff178cdSJimmy Vetayases prop_name, prop_val, bind_cpu);
14167ff178cdSJimmy Vetayases bind_cpu = 0;
14177ff178cdSJimmy Vetayases } else {
14187ff178cdSJimmy Vetayases /* indicate that we are bound at user request */
14197ff178cdSJimmy Vetayases bind_cpu |= IRQ_USER_BOUND;
14207ff178cdSJimmy Vetayases }
14217ff178cdSJimmy Vetayases /*
14227ff178cdSJimmy Vetayases * no need to check apic_cpus[].aci_status, if specific cpu is
14237ff178cdSJimmy Vetayases * not up, then post_cpu_start will handle it.
14247ff178cdSJimmy Vetayases */
14257ff178cdSJimmy Vetayases } else {
14267ff178cdSJimmy Vetayases bind_cpu = apic_get_next_bind_cpu();
14277ff178cdSJimmy Vetayases }
14287ff178cdSJimmy Vetayases
14297ff178cdSJimmy Vetayases lock_clear(&apix_lock);
14307ff178cdSJimmy Vetayases
14317ff178cdSJimmy Vetayases return ((uint32_t)bind_cpu);
14327ff178cdSJimmy Vetayases }
14337ff178cdSJimmy Vetayases
14347ff178cdSJimmy Vetayases static boolean_t
apix_is_cpu_enabled(processorid_t cpuid)14357ff178cdSJimmy Vetayases apix_is_cpu_enabled(processorid_t cpuid)
14367ff178cdSJimmy Vetayases {
14377ff178cdSJimmy Vetayases apic_cpus_info_t *cpu_infop;
14387ff178cdSJimmy Vetayases
14397ff178cdSJimmy Vetayases cpu_infop = &apic_cpus[cpuid];
14407ff178cdSJimmy Vetayases
14417ff178cdSJimmy Vetayases if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0)
14427ff178cdSJimmy Vetayases return (B_FALSE);
14437ff178cdSJimmy Vetayases
14447ff178cdSJimmy Vetayases return (B_TRUE);
14457ff178cdSJimmy Vetayases }
14467ff178cdSJimmy Vetayases
14477ff178cdSJimmy Vetayases /*
14487ff178cdSJimmy Vetayases * Must be called with apix_lock held. This function can be
14497ff178cdSJimmy Vetayases * called from above lock level by apix_intr_redistribute().
14507ff178cdSJimmy Vetayases *
14517ff178cdSJimmy Vetayases * Arguments:
14527ff178cdSJimmy Vetayases * vecp : Vector to be rebound
14537ff178cdSJimmy Vetayases * tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid.
14547ff178cdSJimmy Vetayases * count : Number of continuous vectors
14557ff178cdSJimmy Vetayases *
14567ff178cdSJimmy Vetayases * Return new vector being bound to
14577ff178cdSJimmy Vetayases */
14587ff178cdSJimmy Vetayases apix_vector_t *
apix_rebind(apix_vector_t * vecp,processorid_t newcpu,int count)14597ff178cdSJimmy Vetayases apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count)
14607ff178cdSJimmy Vetayases {
14617ff178cdSJimmy Vetayases apix_vector_t *newp, *oldp;
14627ff178cdSJimmy Vetayases processorid_t oldcpu = vecp->v_cpuid;
14637ff178cdSJimmy Vetayases uchar_t newvec, oldvec = vecp->v_vector;
14647ff178cdSJimmy Vetayases int i;
14657ff178cdSJimmy Vetayases
14667ff178cdSJimmy Vetayases ASSERT(LOCK_HELD(&apix_lock) && count > 0);
14677ff178cdSJimmy Vetayases
14687ff178cdSJimmy Vetayases if (!apix_is_cpu_enabled(newcpu))
14697ff178cdSJimmy Vetayases return (NULL);
14707ff178cdSJimmy Vetayases
14717ff178cdSJimmy Vetayases if (vecp->v_cpuid == newcpu) /* rebind to the same cpu */
14727ff178cdSJimmy Vetayases return (vecp);
14737ff178cdSJimmy Vetayases
14747ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(oldcpu);
14757ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(newcpu);
14767ff178cdSJimmy Vetayases
14777ff178cdSJimmy Vetayases /* allocate vector */
14787ff178cdSJimmy Vetayases if (count == 1)
14797ff178cdSJimmy Vetayases newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type);
14807ff178cdSJimmy Vetayases else {
14817ff178cdSJimmy Vetayases ASSERT(vecp->v_type == APIX_TYPE_MSI);
14827ff178cdSJimmy Vetayases newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count,
14837ff178cdSJimmy Vetayases vecp->v_type);
14847ff178cdSJimmy Vetayases }
14857ff178cdSJimmy Vetayases if (newp == NULL) {
14867ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(newcpu);
14877ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(oldcpu);
14887ff178cdSJimmy Vetayases return (NULL);
14897ff178cdSJimmy Vetayases }
14907ff178cdSJimmy Vetayases
14917ff178cdSJimmy Vetayases newvec = newp->v_vector;
14927ff178cdSJimmy Vetayases apix_dup_vectors(vecp, newp, count);
14937ff178cdSJimmy Vetayases
14947ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(newcpu);
14957ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(oldcpu);
14967ff178cdSJimmy Vetayases
14977ff178cdSJimmy Vetayases if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) {
14987ff178cdSJimmy Vetayases ASSERT(count == 1);
14997ff178cdSJimmy Vetayases if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) {
15007ff178cdSJimmy Vetayases struct autovec *avp;
15017ff178cdSJimmy Vetayases int inum;
15027ff178cdSJimmy Vetayases
15037ff178cdSJimmy Vetayases /* undo duplication */
15047ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(oldcpu);
15057ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(newcpu);
15067ff178cdSJimmy Vetayases for (avp = newp->v_autovect; avp != NULL;
15077ff178cdSJimmy Vetayases avp = avp->av_link) {
15087ff178cdSJimmy Vetayases if (avp->av_dip != NULL) {
15097ff178cdSJimmy Vetayases inum = GET_INTR_INUM(avp->av_intr_id);
15107ff178cdSJimmy Vetayases apix_set_dev_map(vecp, avp->av_dip,
15117ff178cdSJimmy Vetayases inum);
15127ff178cdSJimmy Vetayases }
15137ff178cdSJimmy Vetayases apix_remove_av(newp, avp);
15147ff178cdSJimmy Vetayases }
15157ff178cdSJimmy Vetayases apix_cleanup_vector(newp);
15167ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(newcpu);
15177ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(oldcpu);
15187ff178cdSJimmy Vetayases APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed "
15197ff178cdSJimmy Vetayases "interrupt 0x%x to cpu %d failed\n",
15207ff178cdSJimmy Vetayases vecp->v_inum, newcpu));
15217ff178cdSJimmy Vetayases return (NULL);
15227ff178cdSJimmy Vetayases }
15237ff178cdSJimmy Vetayases
15247ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(oldcpu);
15257ff178cdSJimmy Vetayases (void) apix_obsolete_vector(vecp);
15267ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(oldcpu);
15277ff178cdSJimmy Vetayases APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt"
15287ff178cdSJimmy Vetayases " 0x%x/0x%x to 0x%x/0x%x\n",
15297ff178cdSJimmy Vetayases oldcpu, oldvec, newcpu, newvec));
15307ff178cdSJimmy Vetayases return (newp);
15317ff178cdSJimmy Vetayases }
15327ff178cdSJimmy Vetayases
15337ff178cdSJimmy Vetayases for (i = 0; i < count; i++) {
15347ff178cdSJimmy Vetayases oldp = xv_vector(oldcpu, oldvec + i);
15357ff178cdSJimmy Vetayases newp = xv_vector(newcpu, newvec + i);
15367ff178cdSJimmy Vetayases
15377ff178cdSJimmy Vetayases if (newp->v_share > 0) {
15387ff178cdSJimmy Vetayases APIX_SET_REBIND_INFO(oldp, newp);
15397ff178cdSJimmy Vetayases
15407ff178cdSJimmy Vetayases apix_enable_vector(newp);
15417ff178cdSJimmy Vetayases
15427ff178cdSJimmy Vetayases APIX_CLR_REBIND_INFO();
15437ff178cdSJimmy Vetayases }
15447ff178cdSJimmy Vetayases
15457ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(oldcpu);
15467ff178cdSJimmy Vetayases (void) apix_obsolete_vector(oldp);
15477ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(oldcpu);
15487ff178cdSJimmy Vetayases }
15497ff178cdSJimmy Vetayases APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x "
15507ff178cdSJimmy Vetayases "to 0x%x/0x%x, count=%d\n",
15517ff178cdSJimmy Vetayases oldcpu, oldvec, newcpu, newvec, count));
15527ff178cdSJimmy Vetayases
15537ff178cdSJimmy Vetayases return (xv_vector(newcpu, newvec));
15547ff178cdSJimmy Vetayases }
15557ff178cdSJimmy Vetayases
15567ff178cdSJimmy Vetayases /*
15577ff178cdSJimmy Vetayases * Senarios include:
15587ff178cdSJimmy Vetayases * a. add_avintr() is called before irqp initialized (legacy)
15597ff178cdSJimmy Vetayases * b. irqp is initialized, vector is not allocated (fixed interrupts)
15607ff178cdSJimmy Vetayases * c. irqp is initialized, vector is allocated (shared interrupts)
15617ff178cdSJimmy Vetayases */
15627ff178cdSJimmy Vetayases apix_vector_t *
apix_alloc_intx(dev_info_t * dip,int inum,int irqno)15637ff178cdSJimmy Vetayases apix_alloc_intx(dev_info_t *dip, int inum, int irqno)
15647ff178cdSJimmy Vetayases {
15657ff178cdSJimmy Vetayases apic_irq_t *irqp;
15667ff178cdSJimmy Vetayases apix_vector_t *vecp;
15677ff178cdSJimmy Vetayases
15687ff178cdSJimmy Vetayases /*
15697ff178cdSJimmy Vetayases * Allocate IRQ. Caller is later responsible for the
15707ff178cdSJimmy Vetayases * initialization
15717ff178cdSJimmy Vetayases */
15727ff178cdSJimmy Vetayases mutex_enter(&airq_mutex);
15737ff178cdSJimmy Vetayases if ((irqp = apic_irq_table[irqno]) == NULL) {
15747ff178cdSJimmy Vetayases /* allocate irq */
15757ff178cdSJimmy Vetayases irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
15767ff178cdSJimmy Vetayases irqp->airq_mps_intr_index = FREE_INDEX;
15777ff178cdSJimmy Vetayases apic_irq_table[irqno] = irqp;
15787ff178cdSJimmy Vetayases }
15797ff178cdSJimmy Vetayases if (irqp->airq_mps_intr_index == FREE_INDEX) {
15807ff178cdSJimmy Vetayases irqp->airq_mps_intr_index = DEFAULT_INDEX;
15817ff178cdSJimmy Vetayases irqp->airq_cpu = IRQ_UNINIT;
15827ff178cdSJimmy Vetayases irqp->airq_origirq = (uchar_t)irqno;
15837ff178cdSJimmy Vetayases }
15847ff178cdSJimmy Vetayases
15857ff178cdSJimmy Vetayases mutex_exit(&airq_mutex);
15867ff178cdSJimmy Vetayases
15877ff178cdSJimmy Vetayases /*
15887ff178cdSJimmy Vetayases * allocate vector
15897ff178cdSJimmy Vetayases */
15907ff178cdSJimmy Vetayases if (irqp->airq_cpu == IRQ_UNINIT) {
15917ff178cdSJimmy Vetayases uint32_t bindcpu, cpuid;
15927ff178cdSJimmy Vetayases
15937ff178cdSJimmy Vetayases /* select cpu by system policy */
15947ff178cdSJimmy Vetayases bindcpu = apix_bind_cpu(dip);
15957ff178cdSJimmy Vetayases cpuid = bindcpu & ~IRQ_USER_BOUND;
15967ff178cdSJimmy Vetayases
15977ff178cdSJimmy Vetayases /* allocate vector */
15987ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpuid);
15997ff178cdSJimmy Vetayases
16007ff178cdSJimmy Vetayases if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum,
16017ff178cdSJimmy Vetayases APIX_TYPE_FIXED)) == NULL) {
16027ff178cdSJimmy Vetayases cmn_err(CE_WARN, "No interrupt vector for irq %x",
16037ff178cdSJimmy Vetayases irqno);
16047ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
16057ff178cdSJimmy Vetayases return (NULL);
16067ff178cdSJimmy Vetayases }
16077ff178cdSJimmy Vetayases vecp->v_inum = irqno;
16087ff178cdSJimmy Vetayases vecp->v_flags |= APIX_VECT_MASKABLE;
16097ff178cdSJimmy Vetayases
16107ff178cdSJimmy Vetayases apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector);
16117ff178cdSJimmy Vetayases
16127ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
16137ff178cdSJimmy Vetayases } else {
16147ff178cdSJimmy Vetayases vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
16157ff178cdSJimmy Vetayases ASSERT(!IS_VECT_FREE(vecp));
16167ff178cdSJimmy Vetayases
16177ff178cdSJimmy Vetayases if (dip != NULL)
16187ff178cdSJimmy Vetayases apix_set_dev_map(vecp, dip, inum);
16197ff178cdSJimmy Vetayases }
16207ff178cdSJimmy Vetayases
16217ff178cdSJimmy Vetayases if ((dip != NULL) &&
16227ff178cdSJimmy Vetayases (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
16237ff178cdSJimmy Vetayases ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
16247ff178cdSJimmy Vetayases apix_set_dev_binding(dip, vecp->v_cpuid);
16257ff178cdSJimmy Vetayases
16267ff178cdSJimmy Vetayases apix_dprint_vector(vecp, dip, 1);
16277ff178cdSJimmy Vetayases
16287ff178cdSJimmy Vetayases return (vecp);
16297ff178cdSJimmy Vetayases }
16307ff178cdSJimmy Vetayases
16317ff178cdSJimmy Vetayases int
apix_alloc_msi(dev_info_t * dip,int inum,int count,int behavior)16327ff178cdSJimmy Vetayases apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior)
16337ff178cdSJimmy Vetayases {
16347ff178cdSJimmy Vetayases int i, cap_ptr, rcount = count;
16357ff178cdSJimmy Vetayases apix_vector_t *vecp;
16367ff178cdSJimmy Vetayases processorid_t bindcpu, cpuid;
16377ff178cdSJimmy Vetayases ushort_t msi_ctrl;
16387ff178cdSJimmy Vetayases ddi_acc_handle_t handle;
16397ff178cdSJimmy Vetayases
16407ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p "
16417ff178cdSJimmy Vetayases "inum=0x%x count=0x%x behavior=%d\n",
16427ff178cdSJimmy Vetayases (void *)dip, inum, count, behavior));
16437ff178cdSJimmy Vetayases
16447ff178cdSJimmy Vetayases if (count > 1) {
16457ff178cdSJimmy Vetayases if (behavior == DDI_INTR_ALLOC_STRICT &&
16467ff178cdSJimmy Vetayases apic_multi_msi_enable == 0)
16477ff178cdSJimmy Vetayases return (0);
16487ff178cdSJimmy Vetayases if (apic_multi_msi_enable == 0)
16497ff178cdSJimmy Vetayases count = 1;
16507ff178cdSJimmy Vetayases }
16517ff178cdSJimmy Vetayases
16527ff178cdSJimmy Vetayases /* Check whether it supports per-vector masking */
16537ff178cdSJimmy Vetayases cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip);
16547ff178cdSJimmy Vetayases handle = i_ddi_get_pci_config_handle(dip);
16557ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
16567ff178cdSJimmy Vetayases
16577ff178cdSJimmy Vetayases /* bind to cpu */
16587ff178cdSJimmy Vetayases bindcpu = apix_bind_cpu(dip);
16597ff178cdSJimmy Vetayases cpuid = bindcpu & ~IRQ_USER_BOUND;
16607ff178cdSJimmy Vetayases
16617ff178cdSJimmy Vetayases /* if not ISP2, then round it down */
16627ff178cdSJimmy Vetayases if (!ISP2(rcount))
16637ff178cdSJimmy Vetayases rcount = 1 << (highbit(rcount) - 1);
16647ff178cdSJimmy Vetayases
16657ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpuid);
16667ff178cdSJimmy Vetayases for (vecp = NULL; rcount > 0; rcount >>= 1) {
16677ff178cdSJimmy Vetayases vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount,
16687ff178cdSJimmy Vetayases APIX_TYPE_MSI);
16697ff178cdSJimmy Vetayases if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT)
16707ff178cdSJimmy Vetayases break;
16717ff178cdSJimmy Vetayases }
16727ff178cdSJimmy Vetayases for (i = 0; vecp && i < rcount; i++)
16737ff178cdSJimmy Vetayases xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |=
16747ff178cdSJimmy Vetayases (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0;
16757ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
16767ff178cdSJimmy Vetayases if (vecp == NULL) {
16777ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT,
16787ff178cdSJimmy Vetayases "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n",
16797ff178cdSJimmy Vetayases count, bindcpu));
16807ff178cdSJimmy Vetayases return (0);
16817ff178cdSJimmy Vetayases }
16827ff178cdSJimmy Vetayases
16837ff178cdSJimmy Vetayases /* major to cpu binding */
16847ff178cdSJimmy Vetayases if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
16857ff178cdSJimmy Vetayases ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
16867ff178cdSJimmy Vetayases apix_set_dev_binding(dip, vecp->v_cpuid);
16877ff178cdSJimmy Vetayases
16887ff178cdSJimmy Vetayases apix_dprint_vector(vecp, dip, rcount);
16897ff178cdSJimmy Vetayases
16907ff178cdSJimmy Vetayases return (rcount);
16917ff178cdSJimmy Vetayases }
16927ff178cdSJimmy Vetayases
16937ff178cdSJimmy Vetayases int
apix_alloc_msix(dev_info_t * dip,int inum,int count,int behavior)16947ff178cdSJimmy Vetayases apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior)
16957ff178cdSJimmy Vetayases {
16967ff178cdSJimmy Vetayases apix_vector_t *vecp;
16977ff178cdSJimmy Vetayases processorid_t bindcpu, cpuid;
16987ff178cdSJimmy Vetayases int i;
16997ff178cdSJimmy Vetayases
17007ff178cdSJimmy Vetayases for (i = 0; i < count; i++) {
17017ff178cdSJimmy Vetayases /* select cpu by system policy */
17027ff178cdSJimmy Vetayases bindcpu = apix_bind_cpu(dip);
17037ff178cdSJimmy Vetayases cpuid = bindcpu & ~IRQ_USER_BOUND;
17047ff178cdSJimmy Vetayases
17057ff178cdSJimmy Vetayases /* allocate vector */
17067ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(cpuid);
17077ff178cdSJimmy Vetayases if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i,
17087ff178cdSJimmy Vetayases APIX_TYPE_MSIX)) == NULL) {
17097ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
17107ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: "
17117ff178cdSJimmy Vetayases "allocate msix for device dip=%p, inum=%d on"
17127ff178cdSJimmy Vetayases " cpu %d failed", (void *)dip, inum + i, bindcpu));
17137ff178cdSJimmy Vetayases break;
17147ff178cdSJimmy Vetayases }
17157ff178cdSJimmy Vetayases vecp->v_flags |= APIX_VECT_MASKABLE;
17167ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
17177ff178cdSJimmy Vetayases
17187ff178cdSJimmy Vetayases /* major to cpu mapping */
17197ff178cdSJimmy Vetayases if ((i == 0) &&
17207ff178cdSJimmy Vetayases (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) &&
17217ff178cdSJimmy Vetayases ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0))
17227ff178cdSJimmy Vetayases apix_set_dev_binding(dip, vecp->v_cpuid);
17237ff178cdSJimmy Vetayases
17247ff178cdSJimmy Vetayases apix_dprint_vector(vecp, dip, 1);
17257ff178cdSJimmy Vetayases }
17267ff178cdSJimmy Vetayases
17277ff178cdSJimmy Vetayases if (i < count && behavior == DDI_INTR_ALLOC_STRICT) {
17287ff178cdSJimmy Vetayases APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: "
17297ff178cdSJimmy Vetayases "strictly allocate %d vectors failed, got %d\n",
17307ff178cdSJimmy Vetayases count, i));
17317ff178cdSJimmy Vetayases apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX);
17327ff178cdSJimmy Vetayases i = 0;
17337ff178cdSJimmy Vetayases }
17347ff178cdSJimmy Vetayases
17357ff178cdSJimmy Vetayases return (i);
17367ff178cdSJimmy Vetayases }
17377ff178cdSJimmy Vetayases
17387ff178cdSJimmy Vetayases /*
17397ff178cdSJimmy Vetayases * A rollback free for vectors allocated by apix_alloc_xxx().
17407ff178cdSJimmy Vetayases */
17417ff178cdSJimmy Vetayases void
apix_free_vectors(dev_info_t * dip,int inum,int count,int type)17427ff178cdSJimmy Vetayases apix_free_vectors(dev_info_t *dip, int inum, int count, int type)
17437ff178cdSJimmy Vetayases {
17447ff178cdSJimmy Vetayases int i, cpuid;
17457ff178cdSJimmy Vetayases apix_vector_t *vecp;
17467ff178cdSJimmy Vetayases
17477ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x "
17487ff178cdSJimmy Vetayases "count: %x type: %x\n",
17497ff178cdSJimmy Vetayases (void *)dip, inum, count, type));
17507ff178cdSJimmy Vetayases
17517ff178cdSJimmy Vetayases lock_set(&apix_lock);
17527ff178cdSJimmy Vetayases
17537ff178cdSJimmy Vetayases for (i = 0; i < count; i++, inum++) {
17547ff178cdSJimmy Vetayases if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) {
17557ff178cdSJimmy Vetayases lock_clear(&apix_lock);
17567ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
17577ff178cdSJimmy Vetayases "dip=0x%p inum=0x%x type=0x%x apix_find_intr() "
17587ff178cdSJimmy Vetayases "failed\n", (void *)dip, inum, type));
17597ff178cdSJimmy Vetayases continue;
17607ff178cdSJimmy Vetayases }
17617ff178cdSJimmy Vetayases
17627ff178cdSJimmy Vetayases APIX_ENTER_CPU_LOCK(vecp->v_cpuid);
17637ff178cdSJimmy Vetayases cpuid = vecp->v_cpuid;
17647ff178cdSJimmy Vetayases
17657ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: "
17667ff178cdSJimmy Vetayases "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n",
17677ff178cdSJimmy Vetayases (void *)dip, inum, type, vecp->v_vector, vecp->v_share));
17687ff178cdSJimmy Vetayases
17697ff178cdSJimmy Vetayases /* tear down device interrupt to vector mapping */
17707ff178cdSJimmy Vetayases apix_clear_dev_map(dip, inum, type);
17717ff178cdSJimmy Vetayases
17727ff178cdSJimmy Vetayases if (vecp->v_type == APIX_TYPE_FIXED) {
17737ff178cdSJimmy Vetayases if (vecp->v_share > 0) { /* share IRQ line */
17747ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
17757ff178cdSJimmy Vetayases continue;
17767ff178cdSJimmy Vetayases }
17777ff178cdSJimmy Vetayases
17787ff178cdSJimmy Vetayases /* Free apic_irq_table entry */
17797ff178cdSJimmy Vetayases apix_intx_free(vecp->v_inum);
17807ff178cdSJimmy Vetayases }
17817ff178cdSJimmy Vetayases
17827ff178cdSJimmy Vetayases /* free vector */
17837ff178cdSJimmy Vetayases apix_cleanup_vector(vecp);
17847ff178cdSJimmy Vetayases
17857ff178cdSJimmy Vetayases APIX_LEAVE_CPU_LOCK(cpuid);
17867ff178cdSJimmy Vetayases }
17877ff178cdSJimmy Vetayases
17887ff178cdSJimmy Vetayases lock_clear(&apix_lock);
17897ff178cdSJimmy Vetayases }
17907ff178cdSJimmy Vetayases
17917ff178cdSJimmy Vetayases /*
17927ff178cdSJimmy Vetayases * Must be called with apix_lock held
17937ff178cdSJimmy Vetayases */
17947ff178cdSJimmy Vetayases apix_vector_t *
apix_setup_io_intr(apix_vector_t * vecp)17957ff178cdSJimmy Vetayases apix_setup_io_intr(apix_vector_t *vecp)
17967ff178cdSJimmy Vetayases {
17977ff178cdSJimmy Vetayases processorid_t bindcpu;
17987ff178cdSJimmy Vetayases int ret;
17997ff178cdSJimmy Vetayases
18007ff178cdSJimmy Vetayases ASSERT(LOCK_HELD(&apix_lock));
18017ff178cdSJimmy Vetayases
18027ff178cdSJimmy Vetayases /*
18037ff178cdSJimmy Vetayases * Interrupts are enabled on the CPU, programme IOAPIC RDT
18047ff178cdSJimmy Vetayases * entry or MSI/X address/data to enable the interrupt.
18057ff178cdSJimmy Vetayases */
18067ff178cdSJimmy Vetayases if (apix_is_cpu_enabled(vecp->v_cpuid)) {
18077ff178cdSJimmy Vetayases apix_enable_vector(vecp);
18087ff178cdSJimmy Vetayases return (vecp);
18097ff178cdSJimmy Vetayases }
18107ff178cdSJimmy Vetayases
18117ff178cdSJimmy Vetayases /*
18127ff178cdSJimmy Vetayases * CPU is not up or interrupts are disabled. Fall back to the
18137ff178cdSJimmy Vetayases * first avialable CPU.
18147ff178cdSJimmy Vetayases */
18157ff178cdSJimmy Vetayases bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE);
18167ff178cdSJimmy Vetayases
18177ff178cdSJimmy Vetayases if (vecp->v_type == APIX_TYPE_MSI)
18187ff178cdSJimmy Vetayases return (apix_grp_set_cpu(vecp, bindcpu, &ret));
18197ff178cdSJimmy Vetayases
18207ff178cdSJimmy Vetayases return (apix_set_cpu(vecp, bindcpu, &ret));
18217ff178cdSJimmy Vetayases }
18227ff178cdSJimmy Vetayases
18237ff178cdSJimmy Vetayases /*
18247ff178cdSJimmy Vetayases * For interrupts which call add_avintr() before apic is initialized.
18257ff178cdSJimmy Vetayases * ioapix_setup_intr() will
18267ff178cdSJimmy Vetayases * - allocate vector
18277ff178cdSJimmy Vetayases * - copy over ISR
18287ff178cdSJimmy Vetayases */
18297ff178cdSJimmy Vetayases static void
ioapix_setup_intr(int irqno,iflag_t * flagp)18307ff178cdSJimmy Vetayases ioapix_setup_intr(int irqno, iflag_t *flagp)
18317ff178cdSJimmy Vetayases {
18327ff178cdSJimmy Vetayases extern struct av_head autovect[];
18337ff178cdSJimmy Vetayases apix_vector_t *vecp;
18347ff178cdSJimmy Vetayases apic_irq_t *irqp;
18357ff178cdSJimmy Vetayases uchar_t ioapicindex, ipin;
18367ff178cdSJimmy Vetayases ulong_t iflag;
18377ff178cdSJimmy Vetayases struct autovec *avp;
18387ff178cdSJimmy Vetayases
18397ff178cdSJimmy Vetayases ioapicindex = acpi_find_ioapic(irqno);
18407ff178cdSJimmy Vetayases ASSERT(ioapicindex != 0xFF);
18417ff178cdSJimmy Vetayases ipin = irqno - apic_io_vectbase[ioapicindex];
18427ff178cdSJimmy Vetayases
1843584d084aSHans Rosenfeld mutex_enter(&airq_mutex);
1844584d084aSHans Rosenfeld irqp = apic_irq_table[irqno];
1845584d084aSHans Rosenfeld
1846584d084aSHans Rosenfeld /*
1847584d084aSHans Rosenfeld * The irq table entry shouldn't exist unless the interrupts are shared.
1848584d084aSHans Rosenfeld * In that case, make sure it matches what we would initialize it to.
1849584d084aSHans Rosenfeld */
1850584d084aSHans Rosenfeld if (irqp != NULL) {
1851584d084aSHans Rosenfeld ASSERT(irqp->airq_mps_intr_index == ACPI_INDEX);
18527ff178cdSJimmy Vetayases ASSERT(irqp->airq_intin_no == ipin &&
18537ff178cdSJimmy Vetayases irqp->airq_ioapicindex == ioapicindex);
18547ff178cdSJimmy Vetayases vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector);
18557ff178cdSJimmy Vetayases ASSERT(!IS_VECT_FREE(vecp));
1856584d084aSHans Rosenfeld mutex_exit(&airq_mutex);
18577ff178cdSJimmy Vetayases } else {
1858584d084aSHans Rosenfeld irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP);
18597ff178cdSJimmy Vetayases
1860584d084aSHans Rosenfeld irqp->airq_cpu = IRQ_UNINIT;
1861584d084aSHans Rosenfeld irqp->airq_origirq = (uchar_t)irqno;
18627ff178cdSJimmy Vetayases irqp->airq_mps_intr_index = ACPI_INDEX;
18637ff178cdSJimmy Vetayases irqp->airq_ioapicindex = ioapicindex;
18647ff178cdSJimmy Vetayases irqp->airq_intin_no = ipin;
18657ff178cdSJimmy Vetayases irqp->airq_iflag = *flagp;
18667ff178cdSJimmy Vetayases irqp->airq_share++;
1867584d084aSHans Rosenfeld
1868584d084aSHans Rosenfeld apic_irq_table[irqno] = irqp;
1869584d084aSHans Rosenfeld mutex_exit(&airq_mutex);
1870584d084aSHans Rosenfeld
1871584d084aSHans Rosenfeld vecp = apix_alloc_intx(NULL, 0, irqno);
18727ff178cdSJimmy Vetayases }
18737ff178cdSJimmy Vetayases
18747ff178cdSJimmy Vetayases /* copy over autovect */
18757ff178cdSJimmy Vetayases for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link)
18767ff178cdSJimmy Vetayases apix_insert_av(vecp, avp->av_intr_id, avp->av_vector,
18777ff178cdSJimmy Vetayases avp->av_intarg1, avp->av_intarg2, avp->av_ticksp,
18787ff178cdSJimmy Vetayases avp->av_prilevel, avp->av_dip);
18797ff178cdSJimmy Vetayases
18807ff178cdSJimmy Vetayases /* Program I/O APIC */
18817ff178cdSJimmy Vetayases iflag = intr_clear();
18827ff178cdSJimmy Vetayases lock_set(&apix_lock);
18837ff178cdSJimmy Vetayases
18847ff178cdSJimmy Vetayases (void) apix_setup_io_intr(vecp);
18857ff178cdSJimmy Vetayases
18867ff178cdSJimmy Vetayases lock_clear(&apix_lock);
18877ff178cdSJimmy Vetayases intr_restore(iflag);
18887ff178cdSJimmy Vetayases
18897ff178cdSJimmy Vetayases APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x "
18907ff178cdSJimmy Vetayases "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n",
18917ff178cdSJimmy Vetayases irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector));
18927ff178cdSJimmy Vetayases }
18937ff178cdSJimmy Vetayases
18947ff178cdSJimmy Vetayases void
ioapix_init_intr(int mask_apic)18957ff178cdSJimmy Vetayases ioapix_init_intr(int mask_apic)
18967ff178cdSJimmy Vetayases {
18977ff178cdSJimmy Vetayases int ioapicindex;
18987ff178cdSJimmy Vetayases int i, j;
18997ff178cdSJimmy Vetayases
19007ff178cdSJimmy Vetayases /* mask interrupt vectors */
19017ff178cdSJimmy Vetayases for (j = 0; j < apic_io_max && mask_apic; j++) {
19027ff178cdSJimmy Vetayases int intin_max;
19037ff178cdSJimmy Vetayases
19047ff178cdSJimmy Vetayases ioapicindex = j;
19057ff178cdSJimmy Vetayases /* Bits 23-16 define the maximum redirection entries */
19067ff178cdSJimmy Vetayases intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16)
19077ff178cdSJimmy Vetayases & 0xff;
19087ff178cdSJimmy Vetayases for (i = 0; i <= intin_max; i++)
19097ff178cdSJimmy Vetayases ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i,
19107ff178cdSJimmy Vetayases AV_MASK);
19117ff178cdSJimmy Vetayases }
19127ff178cdSJimmy Vetayases
19137ff178cdSJimmy Vetayases /*
19147ff178cdSJimmy Vetayases * Hack alert: deal with ACPI SCI interrupt chicken/egg here
19157ff178cdSJimmy Vetayases */
19167ff178cdSJimmy Vetayases if (apic_sci_vect > 0)
19177ff178cdSJimmy Vetayases ioapix_setup_intr(apic_sci_vect, &apic_sci_flags);
19187ff178cdSJimmy Vetayases
19197ff178cdSJimmy Vetayases /*
19207ff178cdSJimmy Vetayases * Hack alert: deal with ACPI HPET interrupt chicken/egg here.
19217ff178cdSJimmy Vetayases */
19227ff178cdSJimmy Vetayases if (apic_hpet_vect > 0)
19237ff178cdSJimmy Vetayases ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags);
19247ff178cdSJimmy Vetayases }
1925