Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Make ppb(4) interrupt support stable:



details:   https://anonhg.NetBSD.org/src/rev/a415f7c04f03
branches:  trunk
changeset: 823580:a415f7c04f03
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Thu Apr 27 04:44:02 2017 +0000

description:
Make ppb(4) interrupt support stable:
- Disable all interrupts in the beginning of attach. Without this, interrupt
  storm occurs while cold == 1 on some environment.
- Disable command complete interrput for a while to prevent hangup on some
  enviroment. I'm sorry, I don't know what this bit is :-|
- Check all status bits and return 0 if an interrupt is not for me. It's
  required for INTx. Tested on XEN3_DOM0 because it doesn't support MSI yet.
- Return 1 when a interrupt is processed.

diffstat:

 sys/dev/pci/ppb.c |  57 ++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 38 insertions(+), 19 deletions(-)

diffs (146 lines):

diff -r c45ef32fe6ba -r a415f7c04f03 sys/dev/pci/ppb.c
--- a/sys/dev/pci/ppb.c Thu Apr 27 04:26:12 2017 +0000
+++ b/sys/dev/pci/ppb.c Thu Apr 27 04:44:02 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ppb.c,v 1.60 2017/04/26 08:00:03 msaitoh Exp $ */
+/*     $NetBSD: ppb.c,v 1.61 2017/04/27 04:44:02 msaitoh Exp $ */
 
 /*
  * Copyright (c) 1996, 1998 Christopher G. Demetriou.  All rights reserved.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.60 2017/04/26 08:00:03 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.61 2017/04/27 04:44:02 msaitoh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -45,11 +45,15 @@
 #include <dev/pci/ppbvar.h>
 #include <dev/pci/pcidevs.h>
 
-#define        PCIE_SLCSR_NOTIFY_MASK                                  \
+#define        PCIE_SLCSR_ENABLE_MASK                                  \
        (PCIE_SLCSR_ABE | PCIE_SLCSR_PFE | PCIE_SLCSR_MSE |     \
         PCIE_SLCSR_PDE | PCIE_SLCSR_CCE | PCIE_SLCSR_HPE |     \
         PCIE_SLCSR_DLLSCE)
 
+#define        PCIE_SLCSR_STATCHG_MASK                                 \
+       (PCIE_SLCSR_ABP | PCIE_SLCSR_PFD | PCIE_SLCSR_MSC |     \
+        PCIE_SLCSR_PDC | PCIE_SLCSR_CC | PCIE_SLCSR_LACS)
+
 static const char pcie_linkspeed_strings[4][5] = {
        "1.25", "2.5", "5.0", "8.0",
 };
@@ -241,14 +245,24 @@
        /* Check for PCI Express capabilities and setup hotplug support. */
        if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
            &sc->sc_pciecapoff, &reg) && (reg & PCIE_XCAP_SI)) {
+               /*
+                * First, disable all interrupts because BIOS might
+                * enable them.
+                */
+               reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
+                   sc->sc_pciecapoff + PCIE_SLCSR);
+               if (reg & PCIE_SLCSR_ENABLE_MASK) {
+                       reg &= ~PCIE_SLCSR_ENABLE_MASK;
+                       pci_conf_write(sc->sc_pc, sc->sc_tag,
+                           sc->sc_pciecapoff + PCIE_SLCSR, reg);
+               }
 #ifdef PPB_USEINTR
 #if 0
                /*
                 * XXX Initialize workqueue or something else for
                 * HotPlug support.
                 */
-#endif
-
+#endif 
                if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0)
                        sc->sc_intrhand = pci_intr_establish_xname(pc,
                            sc->sc_pihp[0], IPL_BIO, ppb_intr, sc,
@@ -268,17 +282,24 @@
                            sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
 
                        /* Enable interrupt. */
+                       val = 0;
                        slcap = pci_conf_read(pc, pa->pa_tag,
                            sc->sc_pciecapoff + PCIE_SLCAP);
-                       val = 0;
                        if (slcap & PCIE_SLCAP_ABP)
                                val |= PCIE_SLCSR_ABE;
                        if (slcap & PCIE_SLCAP_PCP)
                                val |= PCIE_SLCSR_PFE;
                        if (slcap & PCIE_SLCAP_MSP)
                                val |= PCIE_SLCSR_MSE;
+#if 0
+                       /*
+                        * XXX Disable for a while because setting
+                        * PCIE_SLCSR_CCE makes break device access on
+                        * some environment.
+                        */
                        if ((slcap & PCIE_SLCAP_NCCS) == 0)
                                val |= PCIE_SLCSR_CCE;
+#endif
                        /* Attention indicator off by default */
                        if (slcap & PCIE_SLCAP_AIP) {
                                val |= __SHIFTIN(PCIE_SLCSR_IND_OFF,
@@ -309,16 +330,6 @@
                        pci_conf_write(pc, pa->pa_tag,
                            sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
                }
-#else
-               reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
-                   sc->sc_pciecapoff + PCIE_SLCSR);
-               if (reg & PCIE_SLCSR_NOTIFY_MASK) {
-                       aprint_debug_dev(self,
-                           "disabling notification events\n");
-                       reg &= ~PCIE_SLCSR_NOTIFY_MASK;
-                       pci_conf_write(sc->sc_pc, sc->sc_tag,
-                           sc->sc_pciecapoff + PCIE_SLCSR, reg);
-               }
 #endif /* PPB_USEINTR */
        }
 
@@ -389,7 +400,7 @@
        /* Clear any pending events and disable interrupt */
        slcsr = pci_conf_read(sc->sc_pc, sc->sc_tag,
              sc->sc_pciecapoff + PCIE_SLCSR);
-       slcsr &= ~PCIE_SLCSR_NOTIFY_MASK;
+       slcsr &= ~PCIE_SLCSR_ENABLE_MASK;
        pci_conf_write(sc->sc_pc, sc->sc_tag,
                sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
 
@@ -448,14 +459,22 @@
        device_t dev = sc->sc_dev;
        pcireg_t reg;
 
-       sc->sc_ev_intr.ev_count++;
        reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
            sc->sc_pciecapoff + PCIE_SLCSR);
 
+       /*
+        * Not me. This check is only required for INTx.
+        * ppb_intr() would be spilted int ppb_intr_legacy() and ppb_intr_msi()
+        */
+       if ((reg & PCIE_SLCSR_STATCHG_MASK) == 0)
+               return 0;
+               
        /* Clear interrupts. */
        pci_conf_write(sc->sc_pc, sc->sc_tag,
            sc->sc_pciecapoff + PCIE_SLCSR, reg);
 
+       sc->sc_ev_intr.ev_count++;
+
        /* Attention Button Pressed */
        if (reg & PCIE_SLCSR_ABP) {
                sc->sc_ev_abp.ev_count++;
@@ -503,6 +522,6 @@
                        device_printf(dev, "Data Link Layer State Changed\n");
        }
 
-       return 0;
+       return 1;
 }
 #endif /* PPB_USEINTR */



Home | Main Index | Thread Index | Old Index