Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci Enable PCIe's interrupt as much as possilbe in p...



details:   https://anonhg.NetBSD.org/src/rev/7b0eee966e72
branches:  trunk
changeset: 823282:7b0eee966e72
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Tue Apr 18 05:21:34 2017 +0000

description:
Enable PCIe's interrupt as much as possilbe in ppb(4) to detect and count
status change event. HotPlug function itself have not implemented yet.

 - Interrupt and each event are counted by evcnt(9). Example:

   ppb0 Interrupt                                                0    0 intr
   ppb0 Attention Button Pressed                                 0    0 misc
   ppb0 Power Fault Detected                                     0    0 misc
   ppb0 MRL Sensor Changed                                       0    0 misc
   ppb0 Presence Detect Changed                                  0    0 misc
   ppb0 Command Completed                                        0    0 misc
   ppb0 Data Link Layer State Changed                            0    0 misc

 - Print message if ppb_printevent is not zero. The default vaule is 0.
   The output messages:

   Attention Button Pressed
   Power Fault Detected
   MRL Sensor Changed
   Presence Detect Changed
   Command Completed
   Data Link Layer State Changed

 - Remove workaround code to disable interrupt (ppb.c rev. 1.35).

 Tested with Dell Latitude 2120 without if_bge.c rev. 1.304's workaround.
dmesg when bge's device timeout occured:

   ppb3: Presence Detect Changed
   ppb3: Data Link Layer State Changed
   ppb3: Presence Detect Changed

vmstat -e |grep ppb

   ppb3 Interrupt                                             2    0 intr
   ppb3 Presence Detect Changed                               2    0 misc
   ppb3 Data Link Layer State Changed                         1    0 misc

diffstat:

 sys/dev/pci/ppb.c    |  203 +++++++++++++++++++++++++++++++++++++++++++++-----
 sys/dev/pci/ppbvar.h |   15 +++-
 2 files changed, 196 insertions(+), 22 deletions(-)

diffs (truncated from 331 to 300 lines):

diff -r ea31dcc36ddf -r 7b0eee966e72 sys/dev/pci/ppb.c
--- a/sys/dev/pci/ppb.c Tue Apr 18 04:35:18 2017 +0000
+++ b/sys/dev/pci/ppb.c Tue Apr 18 05:21:34 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ppb.c,v 1.56 2017/04/05 03:51:36 msaitoh Exp $ */
+/*     $NetBSD: ppb.c,v 1.57 2017/04/18 05:21:34 msaitoh Exp $ */
 
 /*
  * Copyright (c) 1996, 1998 Christopher G. Demetriou.  All rights reserved.
@@ -31,12 +31,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.56 2017/04/05 03:51:36 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.57 2017/04/18 05:21:34 msaitoh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/device.h>
+#include <sys/evcnt.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -52,8 +53,19 @@
        "1.25", "2.5", "5.0", "8.0",
 };
 
-static bool            ppb_resume(device_t, const pmf_qual_t *);
-static bool            ppb_suspend(device_t, const pmf_qual_t *);
+int    ppb_printevent = 0; /* Print event type if the value is not 0 */
+
+static int     ppbmatch(device_t, cfdata_t, void *);
+static void    ppbattach(device_t, device_t, void *);
+static int     ppbdetach(device_t, int);
+static void    ppbchilddet(device_t, device_t);
+static int     ppb_intr(void *);
+static bool    ppb_resume(device_t, const pmf_qual_t *);
+static bool    ppb_suspend(device_t, const pmf_qual_t *);
+
+CFATTACH_DECL3_NEW(ppb, sizeof(struct ppb_softc),
+    ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet,
+    DVF_DETACH_SHUTDOWN);
 
 static int
 ppbmatch(device_t parent, cfdata_t match, void *aux)
@@ -91,7 +103,7 @@
 }
 
 static void
-ppb_fix_pcie(device_t self)
+ppb_print_pcie(device_t self)
 {
        struct ppb_softc *sc = device_private(self);
        pcireg_t reg;
@@ -181,14 +193,6 @@
                aprint_normal(">\n");
                break;
        }
-
-       reg = pci_conf_read(sc->sc_pc, sc->sc_tag, off + 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,
-                   off + PCIE_SLCSR, reg);
-       }
 }
 
 static void
@@ -198,7 +202,9 @@
        struct pci_attach_args *pa = aux;
        pci_chipset_tag_t pc = pa->pa_pc;
        struct pcibus_attach_args pba;
-       pcireg_t busdata;
+       char const *intrstr;
+       char intrbuf[PCI_INTRSTR_LEN];
+       pcireg_t busdata, reg;
 
        pci_aprint_devinfo(pa, NULL);
 
@@ -213,7 +219,7 @@
                return;
        }
 
-       ppb_fix_pcie(self);
+       ppb_print_pcie(self);
 
 #if 0
        /*
@@ -227,6 +233,78 @@
                    pa->pa_bus, PPB_BUSINFO_PRIMARY(busdata));
 #endif
 
+       /* 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)) {
+#if 0
+               /*
+                * XXX Initialize workqueue or something else for
+                * HotPlug support.
+                */
+#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,
+                           device_xname(sc->sc_dev));
+
+               if (sc->sc_intrhand) {
+                       pcireg_t slcap, slcsr, val;
+
+                       intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf,
+                           sizeof(intrbuf));
+                       aprint_normal_dev(self, "%s\n", intrstr);
+
+                       /* Clear any pending events */
+                       slcsr = pci_conf_read(pc, pa->pa_tag,
+                           sc->sc_pciecapoff + PCIE_SLCSR);
+                       pci_conf_write(pc, pa->pa_tag,
+                           sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
+
+                       /* Enable interrupt. */
+                       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 ((slcap & PCIE_SLCAP_NCCS) == 0)
+                               val |= PCIE_SLCSR_CCE;
+                       /* Attention indicator off by default */
+                       if (slcap & PCIE_SLCAP_AIP) {
+                               val |= __SHIFTIN(PCIE_SLCSR_IND_OFF,
+                                   PCIE_SLCSR_AIC);
+                       }
+                       /* Power indicator */
+                       if (slcap & PCIE_SLCAP_PIP) {
+                               /*
+                                * Indicator off:
+                                *  a) card not present
+                                *  b) power fault
+                                *  c) MRL sensor off
+                                */
+                               if (((slcsr & PCIE_SLCSR_PDS) == 0)
+                                   || ((slcsr & PCIE_SLCSR_PFD) != 0)
+                                   || (((slcap & PCIE_SLCAP_MSP) != 0)
+                                       && ((slcsr & PCIE_SLCSR_MS) != 0)))
+                                       val |= __SHIFTIN(PCIE_SLCSR_IND_OFF,
+                                           PCIE_SLCSR_PIC);
+                               else
+                                       val |= __SHIFTIN(PCIE_SLCSR_IND_ON,
+                                           PCIE_SLCSR_PIC);
+                       }
+
+                       val |= PCIE_SLCSR_DLLSCE | PCIE_SLCSR_HPE
+                           | PCIE_SLCSR_PDE;
+                       slcsr = val;
+                       pci_conf_write(pc, pa->pa_tag,
+                           sc->sc_pciecapoff + PCIE_SLCSR, slcsr);
+               }
+       }
+
        if (!pmf_device_register(self, ppb_suspend, ppb_resume))
                aprint_error_dev(self, "couldn't establish power handler\n");
 
@@ -248,14 +326,40 @@
        pba.pba_intrswiz = pa->pa_intrswiz;
        pba.pba_intrtag = pa->pa_intrtag;
 
+       /* Attach event counters */
+       evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, NULL,
+           device_xname(sc->sc_dev), "Interrupt");
+       evcnt_attach_dynamic(&sc->sc_ev_abp, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "Attention Button Pressed");
+       evcnt_attach_dynamic(&sc->sc_ev_pfd, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "Power Fault Detected");
+       evcnt_attach_dynamic(&sc->sc_ev_msc, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "MRL Sensor Changed");
+       evcnt_attach_dynamic(&sc->sc_ev_pdc, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "Presence Detect Changed");
+       evcnt_attach_dynamic(&sc->sc_ev_cc, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "Command Completed");
+       evcnt_attach_dynamic(&sc->sc_ev_lacs, EVCNT_TYPE_MISC, NULL,
+           device_xname(sc->sc_dev), "Data Link Layer State Changed");
+
        config_found_ia(self, "pcibus", &pba, pcibusprint);
 }
 
 static int
 ppbdetach(device_t self, int flags)
 {
+       struct ppb_softc *sc = device_private(self);
        int rc;
 
+       /* Detach event counters */
+       evcnt_detach(&sc->sc_ev_intr);
+       evcnt_detach(&sc->sc_ev_abp);
+       evcnt_detach(&sc->sc_ev_pfd);
+       evcnt_detach(&sc->sc_ev_msc);
+       evcnt_detach(&sc->sc_ev_pdc);
+       evcnt_detach(&sc->sc_ev_cc);
+       evcnt_detach(&sc->sc_ev_lacs);
+
        if ((rc = config_detach_children(self, flags)) != 0)
                return rc;
        pmf_device_deregister(self);
@@ -276,8 +380,6 @@
                            sc->sc_pciconfext[(off - 0x40)/4]);
        }
 
-       ppb_fix_pcie(dv);
-
        return true;
 }
 
@@ -300,6 +402,67 @@
        /* we keep no references to child devices, so do nothing */
 }
 
-CFATTACH_DECL3_NEW(ppb, sizeof(struct ppb_softc),
-    ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet,
-    DVF_DETACH_SHUTDOWN);
+static int
+ppb_intr(void *arg)
+{
+       struct ppb_softc *sc = arg;
+       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);
+
+       /* Clear interrupts. */
+       pci_conf_write(sc->sc_pc, sc->sc_tag,
+           sc->sc_pciecapoff + PCIE_SLCSR, reg);
+
+       /* Attention Button Pressed */
+       if (reg & PCIE_SLCSR_ABP) {
+               sc->sc_ev_abp.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "Attention Button Pressed\n");
+       }
+
+       /* Power Fault Detected */
+       if (reg & PCIE_SLCSR_PFD) {
+               sc->sc_ev_pfd.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "Power Fault Detected\n");
+       }
+
+       /* MRL Sensor Changed */
+       if (reg & PCIE_SLCSR_MSC) {
+               sc->sc_ev_msc.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "MRL Sensor Changed\n");
+       }
+
+       /* Presence Detect Changed */
+       if (reg & PCIE_SLCSR_PDC) {
+               sc->sc_ev_pdc.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "Presence Detect Changed\n");
+               if (reg & PCIE_SLCSR_PDS) {
+                       /* XXX Insert */
+               } else {
+                       /* XXX Remove */
+               }
+       }
+
+       /* Command Completed */
+       if (reg & PCIE_SLCSR_CC) {
+               sc->sc_ev_cc.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "Command Completed\n");
+       }
+
+       /* Data Link Layer State Changed */
+       if (reg & PCIE_SLCSR_LACS) {
+               sc->sc_ev_lacs.ev_count++;
+               if (ppb_printevent)
+                       device_printf(dev, "Data Link Layer State Changed\n");
+       }
+
+       return 0;
+}
diff -r ea31dcc36ddf -r 7b0eee966e72 sys/dev/pci/ppbvar.h
--- a/sys/dev/pci/ppbvar.h      Tue Apr 18 04:35:18 2017 +0000
+++ b/sys/dev/pci/ppbvar.h      Tue Apr 18 05:21:34 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ppbvar.h,v 1.1 2017/04/05 03:51:36 msaitoh Exp $       */
+/*     $NetBSD: ppbvar.h,v 1.2 2017/04/18 05:21:34 msaitoh Exp $       */
 
 /*
  * Copyright (c) 1996, 1998 Christopher G. Demetriou.  All rights reserved.
@@ -31,12 +31,13 @@



Home | Main Index | Thread Index | Old Index