Category
kernel
Sub-Category
arch-x86
Description
usr/src/uts/i86pc/io/psm/uppc.c, function uppc_acpi_irq_configure() uses acpi
to configure an irq for a pci device. uppc_acpi_irq_configure might change
the interrupt assignments that have been setup by the system's bios.
Problem: when changing the interrupt assignments done by the system's bios
for a pci device, the changes are not reflected in the devices's pci
configuration space, offset 0x3c / PCI_CONF_ILINE.
With certain hardware (ASUS A7V mainboard, VIA VT82C686A chipset), apparently
it is important to update PCI_CONF_ILINE when changing the interrupt
vector for a pci device integrated into the chipset, otherwise the device
continues to interrupt on the old vector assigned by the bios.
Test case: Booting snv_b19 on an ASUS A7V mainboard hangs during boot.
========================================================================
This is how the problem was found:
Booting snv_b19 on an ASUS A7V mainboard hangs during boot.
Booting with moddebug = 0x80000000 reveals that the last driver loaded
is uhci. Single stepping through uhci`uhci_attach() hangs somewhere
after uhci interrupts are enabled in the hardware:
/*
* Set HcInterruptEnable to enable all interrupts except Root
* Hub Status change and SOF interrupts.
*/
Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
/* Test the SOF interrupt */
if (uhci_wait_for_sof(uhcip) != USB_SUCCESS) {
USB_DPRINTF_L0(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
"No SOF interrupts have been received, this USB UHCI host"
" controller is unusable");
mutex_exit(&uhcip->uhci_int_mutex);
goto fail;
}
While it is possible to single step into the uhci_wait_for_sof()
function call, it it not possible to "::step over" the complete
uhci_wait_for_sof() function call.
Workaround: Boot the kernel with "-B acpi-user-options=2". When acpi is
disabled, snv_b19 is able to boot into single user mode from the 1/4 CD.
Or boot the kernel with "-B acpi-user-options=8".
------------------------------------------------------------------------
This appears to be an interrupt problem. A breakpoint in
uhci_intr is not reached.
With Solaris 10 x86, several devices share the uhci device's interrupt vector
(vector 9) in this system:
uhci (2x)
ohci
iprb
audioens
With snv_19, acpi_wrapper_isr() is installed as interrupt handler for vector 9.
When uhci attaches, the uhci device's current irq on vector 9 is already in use,
so irq vector 10 is used instead; vector 10 is not yet in use.
uppc_acpi_irq_configure() is called to configure the device for irq 10; this
calls acpi_set_irq_resource(). This returns a "SUCCESS" error status.
uhci_intr is installed as an interrupt handler for vector 10 in the
autovect interrupt handler array.
But: as soon as hardware interrupts are enabled, intr_thread starts receiving
interrupts on vector 9. Although acpi_set_irq_resource() has returned a success
return status, it seems the uhci device is still interrupting on the vector that
was setup by the bios.
New workaround: Do not set acpi-user-options, but set "uppc_unconditional_srs=0"
system boots into single user without hanging, uhci uses the vector 9 that was
configured by the bios, and uhci_intr() shares vector 9 with acpi_wrapper_isr().
Frequency
Always
Regression
Solaris 10
Steps to Reproduce
Boot snv_b19 on an ASUS A7V mainboard. It hangs during boot
Expected Result
Kernel should boot without hanging.
Actual Result
Boot snv_b19 on an ASUS A7V mainboard. It hangs during boot.
Error Message(s)
Test Case
Workaround
Workaround #1:
Boot the kernel with "-B acpi-user-options=2". When acpi is disabled,
snv_b19 is able to boot into single user mode from the 1/4 CD.
Or boot the kernel with "-B acpi-user-options=8".
Workaround #2:
Boot with kmdb and a delayed breakpoint in the uppc module, and change the
variable "uppc_unconditional_srs" in module uppc to a value of 0
Workaround #3:
Manually change the interrupt assigment for Slot 4/5 in the system's bios
setup:
"Advanced" -> "PCI Configuration" -> "Slot 4/5 IRQ": change from AUTO to IRQ10
Suggested fix: Make sure the ILINE byte in pci configuation space is updated,
in case the new interrupt vector selected by uppc_acpi_translate_pci_irq()
is not equal to the old ILINE configured by bios.
--- usr/src/uts/i86pc/io/psm/uppc.c~ Tue Jul 5 00:49:26 2005
+++ usr/src/uts/i86pc/io/psm/uppc.c Mon Aug 15 01:27:47 2005
@@ -741,6 +741,7 @@
int dev_len, pci_irq, devid, busid;
ddi_acc_handle_t cfg_handle;
uchar_t ipin;
+ uchar_t iline;
iflag_t intr_flag;
if (dip == NULL) {
@@ -772,8 +773,8 @@
if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
return (irqno);
+ iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE);
ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
- pci_config_teardown(&cfg_handle);
if (uppc_acpi_translate_pci_irq(dip, busid, devid,
ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) {
@@ -785,9 +786,26 @@
* Make sure pci_irq is within range.
* Otherwise, fall through and return irqno.
*/
- if (pci_irq <= MAX_ISA_IRQ)
+ if (pci_irq <= MAX_ISA_IRQ) {
+ if (iline != pci_irq) {
+ /*
+ * Update the device's ILINE byte,
+ * in case uppc_acpi_translate_pci_irq
+ * has choosen a different pci_irq
+ * than the bios has configured.
+ * Some chipsets need this so that
+ * interrupt routing for integrated
+ * pci devices works with the new
+ * interrupt vector.
+ */
+ pci_config_put8(cfg_handle,
+ PCI_CONF_ILINE, pci_irq);
+ }
+ pci_config_teardown(&cfg_handle);
return (pci_irq);
+ }
}
+ pci_config_teardown(&cfg_handle);
/* FALLTHRU to common case - returning irqno */
} else {
Submitter wants to work on bug
No
Additional configuration information
ASUS A7V mainboard, VIA VT82C686A chipset.
No interrupt vector assignment forced in system's BIOS.
All interrupts are setup to be "AUTO" assigned by the BIOS.
Work Around
Workaround #1:
Boot the kernel with "-B acpi-user-options=2". When acpi is disabled,
snv_b19 is able to boot into single user mode from the 1/4 CD.
Or boot the kernel with "-B acpi-user-options=8".
Workaround #2:
Boot with kmdb and a delayed breakpoint in the uppc module, and change the
variable "uppc_unconditional_srs" in module uppc to a value of 0
Workaround #3:
Manually change the interrupt assigment for Slot 4/5 in the system's bios
setup:
"Advanced" -> "PCI Configuration" -> "Slot 4/5 IRQ": change from AUTO to IRQ10
Suggested fix: Make sure the ILINE byte in pci configuation space is updated,
in case the new interrupt vector selected by uppc_acpi_translate_pci_irq()
is not equal to the old ILINE configured by bios.
--- usr/src/uts/i86pc/io/psm/uppc.c~ Tue Jul 5 00:49:26 2005
+++ usr/src/uts/i86pc/io/psm/uppc.c Mon Aug 15 01:27:47 2005
@@ -741,6 +741,7 @@
int dev_len, pci_irq, devid, busid;
ddi_acc_handle_t cfg_handle;
uchar_t ipin;
+ uchar_t iline;
iflag_t intr_flag;
if (dip == NULL) {
@@ -772,8 +773,8 @@
if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
return (irqno);
+ iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE);
ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
- pci_config_teardown(&cfg_handle);
if (uppc_acpi_translate_pci_irq(dip, busid, devid,
ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) {
@@ -785,9 +786,26 @@
* Make sure pci_irq is within range.
* Otherwise, fall through and return irqno.
*/
- if (pci_irq <= MAX_ISA_IRQ)
+ if (pci_irq <= MAX_ISA_IRQ) {
+ if (iline != pci_irq) {
+ /*
+ * Update the device's ILINE byte,
+ * in case uppc_acpi_translate_pci_irq
+ * has choosen a different pci_irq
+ * than the bios has configured.
+ * Some chipsets need this so that
+ * interrupt routing for integrated
+ * pci devices works with the new
+ * interrupt vector.
+ */
+ pci_config_put8(cfg_handle,
+ PCI_CONF_ILINE, pci_irq);
+ }
+ pci_config_teardown(&cfg_handle);
return (pci_irq);
+ }
}
+ pci_config_teardown(&cfg_handle);
/* FALLTHRU to common case - returning irqno */
} else {