97 static void apix_post_cyclic_setup(void *);
98 static int apix_post_cpu_start();
99 static int apix_intr_ops(dev_info_t *, ddi_intr_handle_impl_t *,
100 psm_intr_op_t, int *);
101
102 /*
103 * Helper functions for apix_intr_ops()
104 */
105 static void apix_redistribute_compute(void);
106 static int apix_get_pending(apix_vector_t *);
107 static apix_vector_t *apix_get_req_vector(ddi_intr_handle_impl_t *, ushort_t);
108 static int apix_get_intr_info(ddi_intr_handle_impl_t *, apic_get_intr_t *);
109 static char *apix_get_apic_type(void);
110 static int apix_intx_get_pending(int);
111 static void apix_intx_set_mask(int irqno);
112 static void apix_intx_clear_mask(int irqno);
113 static int apix_intx_get_shared(int irqno);
114 static void apix_intx_set_shared(int irqno, int delta);
115 static apix_vector_t *apix_intx_xlate_vector(dev_info_t *, int,
116 struct intrspec *);
117 static int apix_intx_alloc_vector(dev_info_t *, int, struct intrspec *);
118
119 extern int apic_clkinit(int);
120
121 /* IRM initialization for APIX PSM module */
122 extern void apix_irm_init(void);
123
124 extern int irm_enable;
125
126 /*
127 * Local static data
128 */
129 static struct psm_ops apix_ops = {
130 apix_probe,
131
132 apix_init,
133 apix_picinit,
134 apix_intr_enter,
135 apix_intr_exit,
136 apix_setspl,
137 apix_addspl,
244 int
245 _fini(void)
246 {
247 return (psm_mod_fini(&apix_hdlp, &apix_psm_info));
248 }
249
250 int
251 _info(struct modinfo *modinfop)
252 {
253 return (psm_mod_info(&apix_hdlp, &apix_psm_info, modinfop));
254 }
255
256 static int
257 apix_probe()
258 {
259 int rval;
260
261 if (apix_enable == 0)
262 return (PSM_FAILURE);
263
264 /*
265 * FIXME Temporarily disable apix module on Xen HVM platform due to
266 * known hang during boot (see #3605).
267 *
268 * Please remove when/if the issue is resolved.
269 */
270 if (get_hwenv() == HW_XEN_HVM)
271 return (PSM_FAILURE);
272
273 /* check for hw features if specified */
274 if (apix_hw_chk_enable) {
275 /* check if x2APIC mode is supported */
276 if ((apix_supported_hw & APIX_SUPPORT_X2APIC) ==
277 APIX_SUPPORT_X2APIC) {
278 if (apic_local_mode() == LOCAL_X2APIC) {
279 /* x2APIC mode activated by BIOS, switch ops */
280 apic_mode = LOCAL_X2APIC;
281 apic_change_ops();
282 } else if (!apic_detect_x2apic()) {
283 /* x2APIC mode is not supported in the hw */
284 apix_enable = 0;
285 }
286 }
287 if (apix_enable == 0)
288 return (PSM_FAILURE);
289 }
290
291 rval = apic_probe_common(apix_psm_info.p_mach_idstring);
292 if (rval == PSM_SUCCESS)
1167 case PSM_INTR_OP_ALLOC_VECTORS:
1168 switch (hdlp->ih_type) {
1169 case DDI_INTR_TYPE_MSI:
1170 /* allocate MSI vectors */
1171 *result = apix_alloc_msi(dip, hdlp->ih_inum,
1172 hdlp->ih_scratch1,
1173 (int)(uintptr_t)hdlp->ih_scratch2);
1174 break;
1175 case DDI_INTR_TYPE_MSIX:
1176 /* allocate MSI-X vectors */
1177 *result = apix_alloc_msix(dip, hdlp->ih_inum,
1178 hdlp->ih_scratch1,
1179 (int)(uintptr_t)hdlp->ih_scratch2);
1180 break;
1181 case DDI_INTR_TYPE_FIXED:
1182 /* allocate or share vector for fixed */
1183 if ((ihdl_plat_t *)hdlp->ih_private == NULL) {
1184 return (PSM_FAILURE);
1185 }
1186 ispec = ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp;
1187 *result = apix_intx_alloc_vector(dip, hdlp->ih_inum,
1188 ispec);
1189 break;
1190 default:
1191 return (PSM_FAILURE);
1192 }
1193 break;
1194 case PSM_INTR_OP_FREE_VECTORS:
1195 apix_free_vectors(dip, hdlp->ih_inum, hdlp->ih_scratch1,
1196 hdlp->ih_type);
1197 break;
1198 case PSM_INTR_OP_XLATE_VECTOR:
1199 /*
1200 * Vectors are allocated by ALLOC and freed by FREE.
1201 * XLATE finds and returns APIX_VIRTVEC_VECTOR(cpu, vector).
1202 */
1203 *result = APIX_INVALID_VECT;
1204 vecp = apix_get_dev_map(dip, hdlp->ih_inum, hdlp->ih_type);
1205 if (vecp != NULL) {
1206 *result = APIX_VIRTVECTOR(vecp->v_cpuid,
1207 vecp->v_vector);
1208 break;
2506 bustype = BUS_EISA;
2507
2508 nonpci:
2509 newirq = apix_intx_setup_nonpci(dip, inum, bustype, ispec);
2510 if (newirq != -1)
2511 goto done;
2512
2513 defconf:
2514 newirq = apix_intx_setup(dip, inum, irqno, NULL, ispec, NULL);
2515 if (newirq == -1) {
2516 mutex_exit(&airq_mutex);
2517 return (-1);
2518 }
2519 done:
2520 ASSERT(apic_irq_table[newirq]);
2521 mutex_exit(&airq_mutex);
2522 return (newirq);
2523 }
2524
2525 static int
2526 apix_intx_alloc_vector(dev_info_t *dip, int inum, struct intrspec *ispec)
2527 {
2528 int irqno;
2529 apix_vector_t *vecp;
2530
2531 if ((irqno = apix_intx_xlate_irq(dip, inum, ispec)) == -1)
2532 return (0);
2533
2534 if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL)
2535 return (0);
2536
2537 DDI_INTR_IMPLDBG((CE_CONT, "apix_intx_alloc_vector: dip=0x%p name=%s "
2538 "irqno=0x%x cpuid=%d vector=0x%x\n",
2539 (void *)dip, ddi_driver_name(dip), irqno,
2540 vecp->v_cpuid, vecp->v_vector));
2541
2542 return (1);
2543 }
2544
2545 /*
2546 * Return the vector number if the translated IRQ for this device
2547 * has a vector mapping setup. If no IRQ setup exists or no vector is
2548 * allocated to it then return 0.
2549 */
2550 static apix_vector_t *
2551 apix_intx_xlate_vector(dev_info_t *dip, int inum, struct intrspec *ispec)
2552 {
2553 int irqno;
2554 apix_vector_t *vecp;
2555
2556 /* get the IRQ number */
|
97 static void apix_post_cyclic_setup(void *);
98 static int apix_post_cpu_start();
99 static int apix_intr_ops(dev_info_t *, ddi_intr_handle_impl_t *,
100 psm_intr_op_t, int *);
101
102 /*
103 * Helper functions for apix_intr_ops()
104 */
105 static void apix_redistribute_compute(void);
106 static int apix_get_pending(apix_vector_t *);
107 static apix_vector_t *apix_get_req_vector(ddi_intr_handle_impl_t *, ushort_t);
108 static int apix_get_intr_info(ddi_intr_handle_impl_t *, apic_get_intr_t *);
109 static char *apix_get_apic_type(void);
110 static int apix_intx_get_pending(int);
111 static void apix_intx_set_mask(int irqno);
112 static void apix_intx_clear_mask(int irqno);
113 static int apix_intx_get_shared(int irqno);
114 static void apix_intx_set_shared(int irqno, int delta);
115 static apix_vector_t *apix_intx_xlate_vector(dev_info_t *, int,
116 struct intrspec *);
117 static int apix_intx_alloc_vector(dev_info_t *, ddi_intr_handle_impl_t *,
118 struct intrspec *);
119
120 extern int apic_clkinit(int);
121
122 /* IRM initialization for APIX PSM module */
123 extern void apix_irm_init(void);
124
125 extern int irm_enable;
126
127 /*
128 * Local static data
129 */
130 static struct psm_ops apix_ops = {
131 apix_probe,
132
133 apix_init,
134 apix_picinit,
135 apix_intr_enter,
136 apix_intr_exit,
137 apix_setspl,
138 apix_addspl,
245 int
246 _fini(void)
247 {
248 return (psm_mod_fini(&apix_hdlp, &apix_psm_info));
249 }
250
251 int
252 _info(struct modinfo *modinfop)
253 {
254 return (psm_mod_info(&apix_hdlp, &apix_psm_info, modinfop));
255 }
256
257 static int
258 apix_probe()
259 {
260 int rval;
261
262 if (apix_enable == 0)
263 return (PSM_FAILURE);
264
265 /* check for hw features if specified */
266 if (apix_hw_chk_enable) {
267 /* check if x2APIC mode is supported */
268 if ((apix_supported_hw & APIX_SUPPORT_X2APIC) ==
269 APIX_SUPPORT_X2APIC) {
270 if (apic_local_mode() == LOCAL_X2APIC) {
271 /* x2APIC mode activated by BIOS, switch ops */
272 apic_mode = LOCAL_X2APIC;
273 apic_change_ops();
274 } else if (!apic_detect_x2apic()) {
275 /* x2APIC mode is not supported in the hw */
276 apix_enable = 0;
277 }
278 }
279 if (apix_enable == 0)
280 return (PSM_FAILURE);
281 }
282
283 rval = apic_probe_common(apix_psm_info.p_mach_idstring);
284 if (rval == PSM_SUCCESS)
1159 case PSM_INTR_OP_ALLOC_VECTORS:
1160 switch (hdlp->ih_type) {
1161 case DDI_INTR_TYPE_MSI:
1162 /* allocate MSI vectors */
1163 *result = apix_alloc_msi(dip, hdlp->ih_inum,
1164 hdlp->ih_scratch1,
1165 (int)(uintptr_t)hdlp->ih_scratch2);
1166 break;
1167 case DDI_INTR_TYPE_MSIX:
1168 /* allocate MSI-X vectors */
1169 *result = apix_alloc_msix(dip, hdlp->ih_inum,
1170 hdlp->ih_scratch1,
1171 (int)(uintptr_t)hdlp->ih_scratch2);
1172 break;
1173 case DDI_INTR_TYPE_FIXED:
1174 /* allocate or share vector for fixed */
1175 if ((ihdl_plat_t *)hdlp->ih_private == NULL) {
1176 return (PSM_FAILURE);
1177 }
1178 ispec = ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp;
1179 *result = apix_intx_alloc_vector(dip, hdlp, ispec);
1180 break;
1181 default:
1182 return (PSM_FAILURE);
1183 }
1184 break;
1185 case PSM_INTR_OP_FREE_VECTORS:
1186 apix_free_vectors(dip, hdlp->ih_inum, hdlp->ih_scratch1,
1187 hdlp->ih_type);
1188 break;
1189 case PSM_INTR_OP_XLATE_VECTOR:
1190 /*
1191 * Vectors are allocated by ALLOC and freed by FREE.
1192 * XLATE finds and returns APIX_VIRTVEC_VECTOR(cpu, vector).
1193 */
1194 *result = APIX_INVALID_VECT;
1195 vecp = apix_get_dev_map(dip, hdlp->ih_inum, hdlp->ih_type);
1196 if (vecp != NULL) {
1197 *result = APIX_VIRTVECTOR(vecp->v_cpuid,
1198 vecp->v_vector);
1199 break;
2497 bustype = BUS_EISA;
2498
2499 nonpci:
2500 newirq = apix_intx_setup_nonpci(dip, inum, bustype, ispec);
2501 if (newirq != -1)
2502 goto done;
2503
2504 defconf:
2505 newirq = apix_intx_setup(dip, inum, irqno, NULL, ispec, NULL);
2506 if (newirq == -1) {
2507 mutex_exit(&airq_mutex);
2508 return (-1);
2509 }
2510 done:
2511 ASSERT(apic_irq_table[newirq]);
2512 mutex_exit(&airq_mutex);
2513 return (newirq);
2514 }
2515
2516 static int
2517 apix_intx_alloc_vector(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp,
2518 struct intrspec *ispec)
2519 {
2520 int irqno;
2521 apix_vector_t *vecp;
2522
2523 if ((irqno = apix_intx_xlate_irq(dip, hdlp->ih_inum, ispec)) == -1)
2524 return (0);
2525
2526 if ((vecp = apix_alloc_intx(dip, hdlp->ih_inum, irqno)) == NULL)
2527 return (0);
2528
2529 hdlp->ih_irq = irqno;
2530
2531 DDI_INTR_IMPLDBG((CE_CONT, "apix_intx_alloc_vector: dip=0x%p name=%s "
2532 "irqno=0x%x cpuid=%d vector=0x%x\n",
2533 (void *)dip, ddi_driver_name(dip), irqno,
2534 vecp->v_cpuid, vecp->v_vector));
2535
2536 return (1);
2537 }
2538
2539 /*
2540 * Return the vector number if the translated IRQ for this device
2541 * has a vector mapping setup. If no IRQ setup exists or no vector is
2542 * allocated to it then return 0.
2543 */
2544 static apix_vector_t *
2545 apix_intx_xlate_vector(dev_info_t *dip, int inum, struct intrspec *ispec)
2546 {
2547 int irqno;
2548 apix_vector_t *vecp;
2549
2550 /* get the IRQ number */
|