Source-Changes-HG archive

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

[src/netbsd-8]: src/sys/dev/pci Pull up following revision(s) (requested by m...



details:   https://anonhg.NetBSD.org/src/rev/2651ab3e34f2
branches:  netbsd-8
changeset: 446475:2651ab3e34f2
user:      martin <martin%NetBSD.org@localhost>
date:      Fri Dec 07 13:27:19 2018 +0000

description:
Pull up following revision(s) (requested by msaitoh in ticket #1128):

        sys/dev/pci/pcivar.h: revision 1.113
        sys/dev/pci/pci.c: revision 1.153

  Save control registers in PCI-X, PCIe, MSI and MSI-X capability area when
suspend and restore them when resume. For PCIe capabilities register, it's
required to check the existence of each register to not to write the next area.

  This change fixes a stability of suspend/resume.

diffstat:

 sys/dev/pci/pci.c    |  144 +++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/pci/pcivar.h |   23 +++++++-
 2 files changed, 162 insertions(+), 5 deletions(-)

diffs (209 lines):

diff -r 9f37e6efd3e4 -r 2651ab3e34f2 sys/dev/pci/pci.c
--- a/sys/dev/pci/pci.c Fri Dec 07 13:23:49 2018 +0000
+++ b/sys/dev/pci/pci.c Fri Dec 07 13:27:19 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pci.c,v 1.152 2017/04/05 04:04:54 msaitoh Exp $        */
+/*     $NetBSD: pci.c,v 1.152.6.1 2018/12/07 13:27:19 martin Exp $     */
 
 /*
  * Copyright (c) 1995, 1996, 1997, 1998
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.152 2017/04/05 04:04:54 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.152.6.1 2018/12/07 13:27:19 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pci.h"
@@ -881,7 +881,70 @@
        for (off = 0; off < 16; off++)
                pcs->reg[off] = pci_conf_read(pc, tag, (off * 4));
 
-       return;
+       /* For PCI-X */
+       if (pci_get_capability(pc, tag, PCI_CAP_PCIX, &off, NULL) != 0)
+               pcs->x_csr = pci_conf_read(pc, tag, off + PCIX_CMD);
+
+       /* For PCIe */
+       if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) != 0) {
+               pcireg_t xcap = pci_conf_read(pc, tag, off + PCIE_XCAP);
+               unsigned int devtype;
+
+               devtype = PCIE_XCAP_TYPE(xcap);
+               pcs->e_dcr = (uint16_t)pci_conf_read(pc, tag, off + PCIE_DCSR);
+
+               if (PCIE_HAS_LINKREGS(devtype))
+                       pcs->e_lcr = (uint16_t)pci_conf_read(pc, tag,
+                           off + PCIE_LCSR);
+
+               if ((xcap & PCIE_XCAP_SI) != 0)
+                       pcs->e_slcr = (uint16_t)pci_conf_read(pc, tag,
+                           off + PCIE_SLCSR);
+
+               if (PCIE_HAS_ROOTREGS(devtype))
+                       pcs->e_rcr = (uint16_t)pci_conf_read(pc, tag,
+                           off + PCIE_RCR);
+
+               if (__SHIFTOUT(xcap, PCIE_XCAP_VER_MASK) >= 2) {
+                       pcs->e_dcr2 = (uint16_t)pci_conf_read(pc, tag,
+                           off + PCIE_DCSR2);
+
+                       if (PCIE_HAS_LINKREGS(devtype))
+                               pcs->e_lcr2 = (uint16_t)pci_conf_read(pc, tag,
+                           off + PCIE_LCSR2);
+
+                       /* XXX PCIE_SLCSR2 (It's reserved by the PCIe spec) */
+               }
+       }
+
+       /* For MSI */
+       if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL) != 0) {
+               bool bit64, pvmask;
+               
+               pcs->msi_ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
+
+               bit64 = pcs->msi_ctl & PCI_MSI_CTL_64BIT_ADDR;
+               pvmask = pcs->msi_ctl & PCI_MSI_CTL_PERVEC_MASK;
+
+               /* Address */
+               pcs->msi_maddr = pci_conf_read(pc, tag, off + PCI_MSI_MADDR);
+               if (bit64)
+                       pcs->msi_maddr64_hi = pci_conf_read(pc, tag,
+                           off + PCI_MSI_MADDR64_HI);
+
+               /* Data */
+               pcs->msi_mdata = pci_conf_read(pc, tag,
+                   off + (bit64 ? PCI_MSI_MDATA64 : PCI_MSI_MDATA));
+
+               /* Per-vector masking */
+               if (pvmask)
+                       pcs->msi_mask = pci_conf_read(pc, tag,
+                           off + (bit64 ? PCI_MSI_MASK64 : PCI_MSI_MASK));
+       }
+
+       /* For MSI-X */
+       if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL) != 0)
+               pcs->msix_ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
 }
 
 void
@@ -897,7 +960,80 @@
                        pci_conf_write(pc, tag, (off * 4), pcs->reg[off]);
        }
 
-       return;
+       /* For PCI-X */
+       if (pci_get_capability(pc, tag, PCI_CAP_PCIX, &off, NULL) != 0)
+               pci_conf_write(pc, tag, off + PCIX_CMD, pcs->x_csr);
+
+       /* For PCIe */
+       if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) != 0) {
+               pcireg_t xcap = pci_conf_read(pc, tag, off + PCIE_XCAP);
+               unsigned int devtype;
+
+               devtype = PCIE_XCAP_TYPE(xcap);
+               pci_conf_write(pc, tag, off + PCIE_DCSR, pcs->e_dcr);
+
+               /*
+                * PCIe capability is variable sized. To not to write the next
+                * area, check the existence of each register.
+                */
+               if (PCIE_HAS_LINKREGS(devtype))
+                       pci_conf_write(pc, tag, off + PCIE_LCSR, pcs->e_lcr);
+
+               if ((xcap & PCIE_XCAP_SI) != 0)
+                       pci_conf_write(pc, tag, off + PCIE_SLCSR, pcs->e_slcr);
+
+               if (PCIE_HAS_ROOTREGS(devtype))
+                       pci_conf_write(pc, tag, off + PCIE_RCR, pcs->e_rcr);
+
+               if (__SHIFTOUT(xcap, PCIE_XCAP_VER_MASK) >= 2) {
+                       pci_conf_write(pc, tag, off + PCIE_DCSR2, pcs->e_dcr2);
+
+                       if (PCIE_HAS_LINKREGS(devtype))
+                               pci_conf_write(pc, tag, off + PCIE_LCSR2,
+                                   pcs->e_lcr2);
+
+                       /* XXX PCIE_SLCSR2 (It's reserved by the PCIe spec) */
+               }
+       }
+
+       /* For MSI */
+       if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL) != 0) {
+               pcireg_t reg;
+               bool bit64, pvmask;
+
+               /* First, drop Enable bit in case it's already set. */
+               reg = pci_conf_read(pc, tag, off + PCI_MSI_CTL);
+               pci_conf_write(pc, tag, off + PCI_MSI_CTL,
+                   reg & ~PCI_MSI_CTL_MSI_ENABLE);
+
+               bit64 = pcs->msi_ctl & PCI_MSI_CTL_64BIT_ADDR;
+               pvmask = pcs->msi_ctl & PCI_MSI_CTL_PERVEC_MASK;
+
+               /* Address */
+               pci_conf_write(pc, tag, off + PCI_MSI_MADDR, pcs->msi_maddr);
+
+               if (bit64)
+                       pci_conf_write(pc, tag,
+                           off + PCI_MSI_MADDR64_HI, pcs->msi_maddr64_hi);
+
+               /* Data */
+               pci_conf_write(pc, tag,
+                   off + (bit64 ? PCI_MSI_MDATA64 : PCI_MSI_MDATA),
+                   pcs->msi_mdata);
+
+               /* Per-vector masking */
+               if (pvmask)
+                       pci_conf_write(pc, tag,
+                           off + (bit64 ? PCI_MSI_MASK64 : PCI_MSI_MASK),
+                           pcs->msi_mask);
+
+               /* Write CTRL register in the end */
+               pci_conf_write(pc, tag, off + PCI_MSI_CTL, pcs->msi_ctl);
+       }
+
+       /* For MSI-X */
+       if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL) != 0)
+               pci_conf_write(pc, tag, off + PCI_MSIX_CTL, pcs->msix_ctl);
 }
 
 /*
diff -r 9f37e6efd3e4 -r 2651ab3e34f2 sys/dev/pci/pcivar.h
--- a/sys/dev/pci/pcivar.h      Fri Dec 07 13:23:49 2018 +0000
+++ b/sys/dev/pci/pcivar.h      Fri Dec 07 13:27:19 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pcivar.h,v 1.109.8.1 2018/06/07 15:52:54 martin Exp $  */
+/*     $NetBSD: pcivar.h,v 1.109.8.2 2018/12/07 13:27:19 martin Exp $  */
 
 /*
  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
@@ -222,6 +222,27 @@
 
 struct pci_conf_state {
        pcireg_t reg[16];
+
+       /* For PCI-X */
+       pcireg_t x_csr;         /* Upper 16bits. Lower 16bits are read only */
+
+       /* For PCIe */
+       uint16_t e_dcr;
+       uint16_t e_lcr;
+       uint16_t e_slcr;
+       uint16_t e_rcr;
+       uint16_t e_dcr2;
+       uint16_t e_lcr2;
+
+       /* For MSI */
+       pcireg_t msi_ctl;       /* Upper 16bits. Lower 16bits are read only */
+       pcireg_t msi_maddr;
+       pcireg_t msi_maddr64_hi;
+       pcireg_t msi_mdata;
+       pcireg_t msi_mask;
+
+       /* For MSI-X */
+       pcireg_t msix_ctl;      /* Upper 16bits. Lower 16bits are read only */
 };
 
 struct pci_range {



Home | Main Index | Thread Index | Old Index