Subject: kern/30431: lost interrupts with siside on 963 chipset (and others)
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <garbageout@sbcglobal.net>
List: netbsd-bugs
Date: 06/05/2005 06:30:00
>Number:         30431
>Category:       kern
>Synopsis:       lost interrupts with siside on 963 chipset (and others)
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 05 06:30:00 +0000 2005
>Originator:     Robert W. Fuller
>Release:        2.0.2 on amd64
>Organization:
>Environment:
2.0.2 on amd64
>Description:
System hangs on boot with missing interrupt messages when using SIS96x controller that is hidden by the BIOS as an incompatible device, a SIS503.

>How-To-Repeat:
Boot netbsd 2.0.2 amd64 on an afflicted system.  In this case, an Averatec 6235-EE1
>Fix:
--- siside.c	Sun Jun  5 01:15:38 2005
+++ siside_new.c	Sun Jun  5 01:16:54 2005
@@ -146,6 +146,30 @@ static struct sis_hostbr_type {
 	{PCI_PRODUCT_SIS_963,   0x00, 6, "963", SIS_TYPE_133NEW},
 };
 
+static int
+sis_hostbr_quirk(struct pci_attach_args *pa)
+{
+    pcireg_t id, reg;
+
+	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS ||
+        PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_SIS_85C503) {
+		return 0;
+    }
+
+    reg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40);
+    pci_conf_write(pa->pa_pc, pa->pa_tag, 0x40, reg | (1 << 6));
+    id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
+    if (((PCI_PRODUCT(id) & 0xfff0) != 0x0960)
+        && (PCI_PRODUCT(id) != 0x0018)) {
+        pci_conf_write(pa->pa_pc, pa->pa_tag, 0x40, reg);
+        return 0;
+    }
+
+    aprint_normal("hidden ");
+    pa->pa_id = id;
+    return 1;
+}
+
 static struct sis_hostbr_type *sis_hostbr_type_match;
 
 static int
@@ -190,6 +214,7 @@ sis_chip_map(struct pciide_softc *sc, st
 
 	aprint_normal("%s: Silicon Integrated System ",
 	    sc->sc_wdcdev.sc_dev.dv_xname);
+	pci_find_device(NULL, sis_hostbr_quirk);
 	pci_find_device(NULL, sis_hostbr_match);
 	if (sis_hostbr_type_match) {
 		if (sis_hostbr_type_match->type == SIS_TYPE_SOUTH) {