4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 #include <sys/mutex.h>
29 #include <sys/types.h>
31 #include <sys/machlock.h>
32 #include <sys/smp_impldefs.h>
33 #include <sys/uadmin.h>
34 #include <sys/promif.h>
38 #include <sys/psm_common.h>
39 #include <sys/atomic.h>
40 #include <sys/archsystm.h>
42 #define NSEC_IN_SEC 1000000000
45 * Local Function Prototypes
47 static void uppc_softinit(void);
48 static void uppc_picinit();
49 static int uppc_post_cpu_start(void);
50 static int uppc_clkinit(int);
51 static int uppc_addspl(int irqno
, int ipl
, int min_ipl
, int max_ipl
);
52 static int uppc_delspl(int irqno
, int ipl
, int min_ipl
, int max_ipl
);
53 static processorid_t
uppc_get_next_processorid(processorid_t cpu_id
);
54 static int uppc_get_clockirq(int ipl
);
55 static int uppc_probe(void);
56 static int uppc_translate_irq(dev_info_t
*dip
, int irqno
);
57 static void uppc_shutdown(int cmd
, int fcn
);
58 static void uppc_preshutdown(int cmd
, int fcn
);
59 static int uppc_state(psm_state_request_t
*request
);
60 static int uppc_init_acpi(void);
61 static void uppc_setspl(int);
62 static int uppc_intr_enter(int, int *);
63 static void uppc_intr_exit(int, int);
64 static hrtime_t
uppc_gethrtime();
66 static int uppc_acpi_irq_configure(acpi_psm_lnk_t
*acpipsmlnkp
, dev_info_t
*dip
,
67 int *pci_irqp
, iflag_t
*intr_flagp
);
72 static struct standard_pic pics0
;
73 int uppc_use_acpi
= 1; /* Use ACPI by default */
74 int uppc_enable_acpi
= 0;
78 * For interrupt link devices, if uppc_unconditional_srs is set, an irq resource
79 * will be assigned (via _SRS). If it is not set, use the current
80 * irq setting (via _CRS), but only if that irq is in the set of possible
81 * irqs (returned by _PRS) for the device.
83 int uppc_unconditional_srs
= 1;
86 * For interrupt link devices, if uppc_prefer_crs is set when we are
87 * assigning an IRQ resource to a device, prefer the current IRQ setting
88 * over other possible irq settings under same conditions.
90 int uppc_prefer_crs
= 1;
94 /* flag definitions for uppc_verbose */
95 #define UPPC_VERBOSE_IRQ_FLAG 0x00000001
96 #define UPPC_VERBOSE_POWEROFF_FLAG 0x00000002
97 #define UPPC_VERBOSE_POWEROFF_PAUSE_FLAG 0x00000004
100 #define UPPC_VERBOSE_IRQ(fmt) \
101 if (uppc_verbose & UPPC_VERBOSE_IRQ_FLAG) \
104 #define UPPC_VERBOSE_POWEROFF(fmt) \
105 if (uppc_verbose & UPPC_VERBOSE_POWEROFF_FLAG) \
108 uchar_t uppc_reserved_irqlist
[MAX_ISA_IRQ
+ 1];
110 static uint16_t uppc_irq_shared_table
[MAX_ISA_IRQ
+ 1];
113 * Contains SCI irqno from FADT after initialization
115 static int uppc_sci
= -1;
121 static lock_t uppc_gethrtime_lock
;
122 static hrtime_t uppc_lasthrtime
;
128 static int uppc_debug
= 0;
134 static struct psm_ops uppc_ops
= {
135 uppc_probe
, /* psm_probe */
137 uppc_softinit
, /* psm_init */
138 uppc_picinit
, /* psm_picinit */
139 uppc_intr_enter
, /* psm_intr_enter */
140 uppc_intr_exit
, /* psm_intr_exit */
141 uppc_setspl
, /* psm_setspl */
142 uppc_addspl
, /* psm_addspl */
143 uppc_delspl
, /* psm_delspl */
144 (int (*)(processorid_t
))NULL
, /* psm_disable_intr */
145 (void (*)(processorid_t
))NULL
, /* psm_enable_intr */
146 (int (*)(int))NULL
, /* psm_softlvl_to_irq */
147 (void (*)(int))NULL
, /* psm_set_softintr */
148 (void (*)(processorid_t
))NULL
, /* psm_set_idlecpu */
149 (void (*)(processorid_t
))NULL
, /* psm_unset_idlecpu */
151 uppc_clkinit
, /* psm_clkinit */
152 uppc_get_clockirq
, /* psm_get_clockirq */
153 (void (*)(void))NULL
, /* psm_hrtimeinit */
154 uppc_gethrtime
, /* psm_gethrtime */
156 uppc_get_next_processorid
, /* psm_get_next_processorid */
157 (int (*)(processorid_t
, caddr_t
))NULL
, /* psm_cpu_start */
158 uppc_post_cpu_start
, /* psm_post_cpu_start */
159 uppc_shutdown
, /* psm_shutdown */
160 (int (*)(int, int))NULL
, /* psm_get_ipivect */
161 (void (*)(processorid_t
, int))NULL
, /* psm_send_ipi */
163 uppc_translate_irq
, /* psm_translate_irq */
165 (void (*)(int, char *))NULL
, /* psm_notify_error */
166 (void (*)(int msg
))NULL
, /* psm_notify_func */
167 (void (*)(hrtime_t time
))NULL
, /* psm_timer_reprogram */
168 (void (*)(void))NULL
, /* psm_timer_enable */
169 (void (*)(void))NULL
, /* psm_timer_disable */
170 (void (*)(void *arg
))NULL
, /* psm_post_cyclic_setup */
171 uppc_preshutdown
, /* psm_preshutdown */
173 (int (*)(dev_info_t
*, ddi_intr_handle_impl_t
*,
174 psm_intr_op_t
, int *))NULL
, /* psm_intr_ops */
176 uppc_state
, /* psm_state */
177 (int (*)(psm_cpu_request_t
*))NULL
/* psm_cpu_ops */
181 static struct psm_info uppc_info
= {
182 PSM_INFO_VER01_7
, /* version */
183 PSM_OWN_SYS_DEFAULT
, /* ownership */
184 (struct psm_ops
*)&uppc_ops
, /* operation */
185 "uppc", /* machine name */
186 "UniProcessor PC", /* machine descriptions */
194 * This is the loadable module wrapper.
196 #include <sys/modctl.h>
198 static void *uppc_hdlp
;
203 return (psm_mod_init(&uppc_hdlp
, &uppc_info
));
209 return (psm_mod_fini(&uppc_hdlp
, &uppc_info
));
213 _info(struct modinfo
*modinfop
)
215 return (psm_mod_info(&uppc_hdlp
, &uppc_info
, modinfop
));
219 * Autoconfiguration Routines
227 return (PSM_SUCCESS
);
233 struct standard_pic
*pp
;
239 if (uppc_use_acpi
&& uppc_init_acpi()) {
240 build_reserved_irqlist((uchar_t
*)uppc_reserved_irqlist
);
241 for (i
= 0; i
<= MAX_ISA_IRQ
; i
++)
242 uppc_irq_shared_table
[i
] = 0;
243 uppc_enable_acpi
= 1;
247 * initialize the ipl mask
249 for (i
= 0; i
< (MAXIPL
<< 1); i
+= 2) {
250 /* enable slave lines on master */
251 pp
->c_iplmask
[i
] = 0xff;
252 pp
->c_iplmask
[i
+1] = (0xff & ~(1 << MASTERLINE
));
258 uppc_clkinit(int hertz
)
260 ulong_t clkticks
= PIT_HZ
/ hz
;
263 return (0); /* One shot mode not supported */
268 outb(PITCTL_PORT
, (PIT_C0
|PIT_NDIVMODE
|PIT_READMODE
));
269 outb(PITCTR0_PORT
, (uchar_t
)clkticks
);
270 outb(PITCTR0_PORT
, (uchar_t
)(clkticks
>>8));
272 return (NSEC_IN_SEC
/ hertz
);
281 * If a valid SCI is present, manually addspl()
282 * since we're not set-up early enough in boot
283 * to do it "conventionally" (via add_avintr)
286 (void) uppc_addspl(uppc_sci
, SCI_IPL
, SCI_IPL
, SCI_IPL
);
290 uppc_post_cpu_start(void)
293 * On uppc machines psm_post_cpu_start is called during S3 resume
294 * on the boot cpu from assembly, using the ap_mlsetup vector.
298 * Init master and slave pic
305 (void) uppc_clkinit(hz
);
307 return (PSM_SUCCESS
);
312 uppc_addspl(int irqno
, int ipl
, int min_ipl
, int max_ipl
)
314 struct standard_pic
*pp
;
319 if (irqno
<= MAX_ISA_IRQ
)
320 atomic_inc_16(&uppc_irq_shared_table
[irqno
]);
326 vectmask
= 1 << (irqno
- 8);
327 startidx
= (ipl
<< 1);
329 vectmask
= 1 << irqno
;
330 startidx
= (ipl
<< 1) + 1;
334 * mask intr same or above ipl
335 * level MAXIPL has all intr off as init. default
338 for (i
= startidx
; i
< (MAXIPL
<< 1); i
+= 2) {
339 if (pp
->c_iplmask
[i
] & vectmask
)
341 pp
->c_iplmask
[i
] |= vectmask
;
345 * unmask intr below ipl
347 for (i
= startidx
-2; i
>= 0; i
-= 2) {
348 if (!(pp
->c_iplmask
[i
] & vectmask
))
350 pp
->c_iplmask
[i
] &= ~vectmask
;
356 uppc_delspl(int irqno
, int ipl
, int min_ipl
, int max_ipl
)
358 struct standard_pic
*pp
;
362 if (irqno
<= MAX_ISA_IRQ
)
363 atomic_dec_16(&uppc_irq_shared_table
[irqno
]);
366 * skip if we are not deleting the last handler
367 * and the ipl is higher than minimum
369 if ((max_ipl
!= PSM_INVALID_IPL
) && (ipl
>= min_ipl
))
373 vectmask
= 1 << (irqno
- 8);
376 vectmask
= 1 << irqno
;
383 * check any handlers left for this irqno
385 if (max_ipl
!= PSM_INVALID_IPL
) {
387 * unmasks all levels below the lowest priority
389 i
+= ((min_ipl
- 1) << 1);
390 for (; i
>= 0; i
-= 2) {
391 if (!(pp
->c_iplmask
[i
] & vectmask
))
393 pp
->c_iplmask
[i
] &= ~vectmask
;
397 * set mask to all levels
399 for (; i
< (MAXIPL
<< 1); i
+= 2) {
400 if (pp
->c_iplmask
[i
] & vectmask
)
402 pp
->c_iplmask
[i
] |= vectmask
;
409 uppc_get_next_processorid(processorid_t cpu_id
)
418 uppc_get_clockirq(int ipl
)
420 return (CLOCK_VECTOR
);
427 int verboseflags
= 0;
432 * Process SCI configuration here; this may return
433 * an error if acpi-user-options has specified
434 * legacy mode (use ACPI without ACPI mode or SCI)
436 if (acpica_get_sci(&sci
, &sci_flags
) != AE_OK
)
440 * Initialize sub-system - if error is returns, ACPI is not
443 if (acpica_init() != AE_OK
)
447 * uppc implies system is in PIC mode; set edge/level
448 * via ELCR based on return value from get_sci; this
449 * will default to level/low if no override present,
450 * as recommended by Intel ACPI CA team.
453 ASSERT((sci_flags
.intr_el
== INTR_EL_LEVEL
) ||
454 (sci_flags
.intr_el
== INTR_EL_EDGE
));
456 psm_set_elcr(sci
, sci_flags
.intr_el
== INTR_EL_LEVEL
);
460 * Remember SCI for later use
464 if (uppc_verbose
& UPPC_VERBOSE_IRQ_FLAG
)
465 verboseflags
|= PSM_VERBOSE_IRQ_FLAG
;
467 if (uppc_verbose
& UPPC_VERBOSE_POWEROFF_FLAG
)
468 verboseflags
|= PSM_VERBOSE_POWEROFF_FLAG
;
470 if (uppc_verbose
& UPPC_VERBOSE_POWEROFF_PAUSE_FLAG
)
471 verboseflags
|= PSM_VERBOSE_POWEROFF_PAUSE_FLAG
;
473 if (acpi_psm_init(uppc_info
.p_mach_idstring
, verboseflags
) ==
483 uppc_preshutdown(int cmd
, int fcn
)
485 UPPC_VERBOSE_POWEROFF(("uppc_preshutdown(%d,%d);\n", cmd
, fcn
));
490 uppc_shutdown(int cmd
, int fcn
)
492 UPPC_VERBOSE_POWEROFF(("uppc_shutdown(%d,%d);\n", cmd
, fcn
));
495 * Return if passed a command other than A_SHUTDOWN or
496 * if we're not using ACPI.
498 if ((cmd
!= A_SHUTDOWN
) || (!uppc_enable_acpi
))
502 * Switch system back into Legacy-Mode if using ACPI and
503 * not powering-off. Some BIOSes need to remain in ACPI-mode
504 * for power-off to succeed (Dell Dimension 4600)
506 if (fcn
!= AD_POWEROFF
) {
507 (void) AcpiDisable();
511 (void) acpi_poweroff();
516 uppc_acpi_enter_picmode(void)
518 ACPI_OBJECT_LIST arglist
;
522 /* Setup parameter object */
524 arglist
.Pointer
= &arg
;
525 arg
.Type
= ACPI_TYPE_INTEGER
;
526 arg
.Integer
.Value
= ACPI_PIC_MODE
;
528 status
= AcpiEvaluateObject(NULL
, "\\_PIC", &arglist
, NULL
);
529 if (ACPI_FAILURE(status
))
530 return (PSM_FAILURE
);
532 return (PSM_SUCCESS
);
544 pic_save_state(struct pic_state
*sp
)
546 struct standard_pic
*pp
;
550 * Only the PIC masks and the ELCR can be saved;
551 * other 8259 state is write-only
555 * save current master and slave interrupt mask
558 sp
->smask
= pp
->c_curmask
[0];
559 sp
->mmask
= pp
->c_curmask
[1];
562 * save edge/level configuration for isa interrupts
565 for (vecno
= 0; vecno
<= MAX_ISA_IRQ
; vecno
++)
566 sp
->elcr
|= psm_get_elcr(vecno
) << vecno
;
570 pic_restore_state(struct pic_state
*sp
)
574 /* Restore master and slave interrupt masks */
575 outb(SIMR_PORT
, sp
->smask
);
576 outb(MIMR_PORT
, sp
->mmask
);
578 /* Read master to allow pics to settle */
579 (void) inb(MIMR_PORT
);
581 /* Restore edge/level configuration for isa interupts */
582 for (vecno
= 0; vecno
<= MAX_ISA_IRQ
; vecno
++)
583 psm_set_elcr(vecno
, sp
->elcr
& (1 << vecno
));
585 /* Reenter PIC mode before restoring LNK devices */
586 (void) uppc_acpi_enter_picmode();
588 /* Restore ACPI link device mappings */
589 acpi_restore_link_devices();
593 uppc_state(psm_state_request_t
*rp
)
595 switch (rp
->psr_cmd
) {
596 case PSM_STATE_ALLOC
:
597 rp
->req
.psm_state_req
.psr_state
=
598 kmem_zalloc(sizeof (struct pic_state
), KM_NOSLEEP
);
599 if (rp
->req
.psm_state_req
.psr_state
== NULL
)
601 rp
->req
.psm_state_req
.psr_state_size
=
602 sizeof (struct pic_state
);
605 kmem_free(rp
->req
.psm_state_req
.psr_state
,
606 rp
->req
.psm_state_req
.psr_state_size
);
609 pic_save_state(rp
->req
.psm_state_req
.psr_state
);
611 case PSM_STATE_RESTORE
:
612 pic_restore_state(rp
->req
.psm_state_req
.psr_state
);
621 uppc_acpi_translate_pci_irq(dev_info_t
*dip
, int busid
, int devid
,
622 int ipin
, int *pci_irqp
, iflag_t
*intr_flagp
)
625 acpi_psm_lnk_t acpipsmlnk
;
627 if ((status
= acpi_get_irq_cache_ent(busid
, devid
, ipin
, pci_irqp
,
628 intr_flagp
)) == ACPI_PSM_SUCCESS
) {
629 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: Found irqno %d "
630 "from cache for device %s, instance #%d\n", *pci_irqp
,
631 ddi_get_name(dip
), ddi_get_instance(dip
)));
635 bzero(&acpipsmlnk
, sizeof (acpi_psm_lnk_t
));
637 if ((status
= acpi_translate_pci_irq(dip
, ipin
, pci_irqp
,
638 intr_flagp
, &acpipsmlnk
)) == ACPI_PSM_FAILURE
) {
639 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: "
640 " acpi_translate_pci_irq failed for device %s, instance"
641 " #%d\n", ddi_get_name(dip
), ddi_get_instance(dip
)));
646 if (status
== ACPI_PSM_PARTIAL
&& acpipsmlnk
.lnkobj
!= NULL
) {
647 status
= uppc_acpi_irq_configure(&acpipsmlnk
, dip
, pci_irqp
,
649 if (status
!= ACPI_PSM_SUCCESS
) {
650 status
= acpi_get_current_irq_resource(&acpipsmlnk
,
651 pci_irqp
, intr_flagp
);
655 if (status
== ACPI_PSM_SUCCESS
) {
656 acpi_new_irq_cache_ent(busid
, devid
, ipin
, *pci_irqp
,
657 intr_flagp
, &acpipsmlnk
);
658 psm_set_elcr(*pci_irqp
, 1); /* set IRQ to PCI mode */
660 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: [ACPI] "
661 "new irq %d for device %s, instance #%d\n",
662 *pci_irqp
, ddi_get_name(dip
), ddi_get_instance(dip
)));
669 * Configures the irq for the interrupt link device identified by
672 * Gets the current and the list of possible irq settings for the
673 * device. If uppc_unconditional_srs is not set, and the current
674 * resource setting is in the list of possible irq settings,
675 * current irq resource setting is passed to the caller.
677 * Otherwise, picks an irq number from the list of possible irq
678 * settings, and sets the irq of the device to this value.
679 * If prefer_crs is set, among a set of irq numbers in the list that have
680 * the least number of devices sharing the interrupt, we pick current irq
681 * resource setting if it is a member of this set.
683 * Passes the irq number in the value pointed to by pci_irqp, and
684 * polarity and sensitivity in the structure pointed to by dipintrflagp
687 * Note that if setting the irq resource failed, but successfuly obtained
688 * the current irq resource settings, passes the current irq resources
689 * and considers it a success.
692 * ACPI_PSM_SUCCESS on success.
694 * ACPI_PSM_FAILURE if an error occured during the configuration or
695 * if a suitable irq was not found for this device, or if setting the
696 * irq resource and obtaining the current resource fails.
700 uppc_acpi_irq_configure(acpi_psm_lnk_t
*acpipsmlnkp
, dev_info_t
*dip
,
701 int *pci_irqp
, iflag_t
*dipintr_flagp
)
703 int i
, min_share
, foundnow
, done
= 0;
705 int32_t share_irq
= -1;
706 int32_t chosen_irq
= -1;
708 acpi_irqlist_t
*irqlistp
;
709 acpi_irqlist_t
*irqlistent
;
711 if ((acpi_get_possible_irq_resources(acpipsmlnkp
, &irqlistp
))
712 == ACPI_PSM_FAILURE
) {
713 UPPC_VERBOSE_IRQ((CE_WARN
, "!uppc: Unable to determine "
714 "or assign IRQ for device %s, instance #%d: The system was "
715 "unable to get the list of potential IRQs from ACPI.",
716 ddi_get_name(dip
), ddi_get_instance(dip
)));
718 return (ACPI_PSM_FAILURE
);
721 if ((acpi_get_current_irq_resource(acpipsmlnkp
, &cur_irq
,
722 dipintr_flagp
) == ACPI_PSM_SUCCESS
) && (!uppc_unconditional_srs
) &&
725 if (acpi_irqlist_find_irq(irqlistp
, cur_irq
, NULL
)
726 == ACPI_PSM_SUCCESS
) {
728 acpi_free_irqlist(irqlistp
);
729 ASSERT(pci_irqp
!= NULL
);
731 return (ACPI_PSM_SUCCESS
);
733 UPPC_VERBOSE_IRQ((CE_WARN
, "!uppc: Could not find the "
734 "current irq %d for device %s, instance #%d in ACPI's "
735 "list of possible irqs for this device. Picking one from "
736 " the latter list.", cur_irq
, ddi_get_name(dip
),
737 ddi_get_instance(dip
)));
741 irqlistent
= irqlistp
;
744 while (irqlistent
!= NULL
) {
746 for (foundnow
= 0, i
= 0; i
< irqlistent
->num_irqs
; i
++) {
748 irq
= irqlistp
->irqs
[i
];
750 if ((irq
> MAX_ISA_IRQ
) ||
751 (irqlistent
->intr_flags
.intr_el
== INTR_EL_EDGE
) ||
755 if (uppc_reserved_irqlist
[irq
])
758 if (uppc_irq_shared_table
[irq
] == 0) {
761 if (!(uppc_prefer_crs
) || (irq
== cur_irq
)) {
767 if ((uppc_irq_shared_table
[irq
] < min_share
) ||
768 ((uppc_irq_shared_table
[irq
] == min_share
) &&
769 (cur_irq
== irq
) && (uppc_prefer_crs
))) {
770 min_share
= uppc_irq_shared_table
[irq
];
776 /* If we found an IRQ in the inner loop, save the details */
777 if (foundnow
&& ((chosen_irq
!= -1) || (share_irq
!= -1))) {
779 * Copy the acpi_prs_private_t and flags from this
780 * irq list entry, since we found an irq from this
783 acpipsmlnkp
->acpi_prs_prv
= irqlistent
->acpi_prs_prv
;
784 *dipintr_flagp
= irqlistent
->intr_flags
;
790 /* Load the next entry in the irqlist */
791 irqlistent
= irqlistent
->next
;
794 acpi_free_irqlist(irqlistp
);
796 if (chosen_irq
!= -1)
798 else if (share_irq
!= -1)
801 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: Could not find a "
802 "suitable irq from the list of possible irqs for device "
803 "%s, instance #%d in ACPI's list of possible\n",
804 ddi_get_name(dip
), ddi_get_instance(dip
)));
806 return (ACPI_PSM_FAILURE
);
810 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: Setting irq %d for device %s "
811 "instance #%d\n", irq
, ddi_get_name(dip
), ddi_get_instance(dip
)));
813 if ((acpi_set_irq_resource(acpipsmlnkp
, irq
)) == ACPI_PSM_SUCCESS
) {
815 * setting irq was successful, check to make sure CRS
816 * reflects that. If CRS does not agree with what we
817 * set, return the irq that was set.
820 if (acpi_get_current_irq_resource(acpipsmlnkp
, &cur_irq
,
821 dipintr_flagp
) == ACPI_PSM_SUCCESS
) {
824 UPPC_VERBOSE_IRQ((CE_WARN
, "!uppc: "
825 "IRQ resource set (irqno %d) for device %s "
826 "instance #%d, differs from current "
828 irq
, ddi_get_name(dip
),
829 ddi_get_instance(dip
), cur_irq
));
832 * return the irq that was set, and not what CRS reports,
833 * since CRS has been seen to be bogus on some systems
837 UPPC_VERBOSE_IRQ((CE_WARN
, "!uppc: set resource irq %d "
838 "failed for device %s instance #%d",
839 irq
, ddi_get_name(dip
), ddi_get_instance(dip
)));
841 return (ACPI_PSM_FAILURE
);
844 ASSERT(pci_irqp
!= NULL
);
846 return (ACPI_PSM_SUCCESS
);
852 uppc_translate_irq(dev_info_t
*dip
, int irqno
)
855 int dev_len
, pci_irq
, devid
, busid
;
856 ddi_acc_handle_t cfg_handle
;
861 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: irqno = %d"
862 " dip = NULL\n", irqno
));
866 if (!uppc_enable_acpi
) {
870 dev_len
= sizeof (dev_type
);
871 if (ddi_getlongprop_buf(DDI_DEV_T_ANY
, ddi_get_parent(dip
),
872 DDI_PROP_DONTPASS
, "device_type", (caddr_t
)dev_type
,
873 &dev_len
) != DDI_PROP_SUCCESS
) {
874 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: irqno %d"
875 "device %s instance %d no device_type\n", irqno
,
876 ddi_get_name(dip
), ddi_get_instance(dip
)));
880 if ((strcmp(dev_type
, "pci") == 0) ||
881 (strcmp(dev_type
, "pciex") == 0)) {
884 if (acpica_get_bdf(dip
, &busid
, &devid
, NULL
) != 0)
887 if (pci_config_setup(dip
, &cfg_handle
) != DDI_SUCCESS
)
890 ipin
= pci_config_get8(cfg_handle
, PCI_CONF_IPIN
) - PCI_INTA
;
891 iline
= pci_config_get8(cfg_handle
, PCI_CONF_ILINE
);
892 if (uppc_acpi_translate_pci_irq(dip
, busid
, devid
,
893 ipin
, &pci_irq
, &intr_flag
) == ACPI_PSM_SUCCESS
) {
895 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: [ACPI] new irq "
896 "%d old irq %d device %s, instance %d\n", pci_irq
,
897 irqno
, ddi_get_name(dip
), ddi_get_instance(dip
)));
900 * Make sure pci_irq is within range.
901 * Otherwise, fall through and return irqno.
903 if (pci_irq
<= MAX_ISA_IRQ
) {
904 if (iline
!= pci_irq
) {
906 * Update the device's ILINE byte,
907 * in case uppc_acpi_translate_pci_irq
908 * has choosen a different pci_irq
909 * than the BIOS has configured.
910 * Some chipsets use the value in
911 * ILINE to control interrupt routing,
912 * in conflict with the PCI spec.
914 pci_config_put8(cfg_handle
,
915 PCI_CONF_ILINE
, pci_irq
);
917 pci_config_teardown(&cfg_handle
);
921 pci_config_teardown(&cfg_handle
);
923 /* FALLTHRU to common case - returning irqno */
925 /* non-PCI; assumes ISA-style edge-triggered */
926 psm_set_elcr(irqno
, 0); /* set IRQ to ISA mode */
928 UPPC_VERBOSE_IRQ((CE_CONT
, "!uppc: non-pci,"
929 "irqno %d device %s instance %d\n", irqno
,
930 ddi_get_name(dip
), ddi_get_instance(dip
)));
937 * uppc_intr_enter() raises the ipl to the level of the current interrupt,
938 * and sends EOI to the pics.
939 * If interrupt is 7 or 15 and not spurious interrupt, send specific EOI
940 * else send non-specific EOI
941 * uppc_intr_enter() returns the new priority level,
942 * or -1 for spurious interrupt
945 uppc_intr_enter(int ipl
, int *vector
)
954 newipl
= autovect
[intno
].avh_hi_pri
;
957 * During wait_till_seen() periods when interrupt vector is being
958 * removed in remove_av(), the removed hardware interrupt could
959 * trigger and got here with newipl 0. It has to send EOI
960 * as usual but no need to call setspl and returns -1 like spurious.
962 if ((intno
& 7) != 7) {
965 outb(MCMD_PORT
, PIC_NSEOI
);
967 outb(SCMD_PORT
, PIC_NSEOI
);
969 } else { /* int was 7 or 15 */
970 if (newipl
&& newipl
<= ipl
) { /* Check for spurious int */
972 outb(MCMD_PORT
, PIC_NSEOI
);
973 return (-1); /* Spurious int */
978 outb(MCMD_PORT
, PIC_NSEOI
);
979 outb(SCMD_PORT
, PIC_SEOI_LVL7
);
981 outb(MCMD_PORT
, PIC_SEOI_LVL7
);
989 return (-1); /* not real spurious int */
993 * uppc_intr_exit() restores the old interrupt
994 * priority level after processing an interrupt.
995 * It is called with interrupts disabled, and does not enable interrupts.
999 uppc_intr_exit(int ipl
, int vector
)
1005 * uppc_setspl() loads new interrupt masks into the pics
1006 * based on input ipl.
1010 uppc_setspl(int ipl
)
1012 struct standard_pic
*pp
;
1013 uint8_t smask
, mmask
;
1014 uint8_t cursmask
, curmmask
;
1017 smask
= pp
->c_iplmask
[ipl
* 2];
1018 mmask
= pp
->c_iplmask
[ipl
* 2 + 1];
1019 cursmask
= pp
->c_curmask
[0];
1020 curmmask
= pp
->c_curmask
[1];
1021 if (cursmask
== smask
&& curmmask
== mmask
)
1023 pp
->c_curmask
[0] = smask
;
1024 pp
->c_curmask
[1] = mmask
;
1026 if (cursmask
!= smask
) {
1028 * program new slave pic mask
1030 outb(SIMR_PORT
, smask
);
1032 if (curmmask
!= mmask
) {
1034 * program new master pic mask
1036 outb(MIMR_PORT
, mmask
);
1039 * read master to allow pics to settle
1041 (void) inb(MIMR_PORT
);
1045 * uppc_gethrtime() returns high resolution timer value
1050 hrtime_t timeval
, temp
;
1054 oflags
= intr_clear(); /* disable ints */
1055 lock_set(&uppc_gethrtime_lock
);
1058 outb(PITCTL_PORT
, 0); /* latch counter 0 */
1062 ctr0
= inb(PITCTR0_PORT
);
1063 ctr0
|= inb(PITCTR0_PORT
) << 8;
1064 timeval
= (hrtime_t
)ctr0
* (NANOSEC
/ PIT_HZ
);
1065 if (temp
!= hrtime_base
)
1068 if (timeval
< uppc_lasthrtime
)
1069 timeval
= uppc_lasthrtime
;
1070 uppc_lasthrtime
= timeval
;
1071 lock_clear(&uppc_gethrtime_lock
);
1072 intr_restore(oflags
);