Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Mar 2012 21:09:34 +0000 (UTC)
From:      Alexander Kabaev <kan@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r232704 - head/sys/dev/pci
Message-ID:  <201203082109.q28L9YIp065017@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kan
Date: Thu Mar  8 21:09:34 2012
New Revision: 232704
URL: http://svn.freebsd.org/changeset/base/232704

Log:
  Save more of config space for PCI Express and PCI-X devices.
  
  Expand pci_save_state and pci_restore_state to save more of
  the config state for PCI Express and PCI-X devices. Various
  writable control registers are present in PCI Express that
  can potentially be lost over suspend/resume cycle.
  
  This change is modeled after similar functionality in Linux.
  
  Reviewed by: wlosh,jhb
  MFC after:  1 month

Modified:
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pcireg.h
  head/sys/dev/pci/pcivar.h

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c	Thu Mar  8 21:06:05 2012	(r232703)
+++ head/sys/dev/pci/pci.c	Thu Mar  8 21:09:34 2012	(r232704)
@@ -723,6 +723,7 @@ pci_read_cap(device_t pcib, pcicfgregs *
 			if ((cfg->hdrtype & PCIM_HDRTYPE) ==
 			    PCIM_HDRTYPE_BRIDGE)
 				pcix_chipset = 1;
+			cfg->pcix.pcix_location = ptr;
 			break;
 		case PCIY_EXPRESS:	/* PCI-express */
 			/*
@@ -4444,6 +4445,49 @@ pci_modevent(module_t mod, int what, voi
 	return (0);
 }
 
+static void
+pci_cfg_restore_pcie(device_t dev, struct pci_devinfo *dinfo)
+{
+#define	WREG(n, v)	pci_write_config(dev, pos + (n), (v), 2)
+	struct pcicfg_pcie *cfg;
+	int version, pos;
+
+	cfg = &dinfo->cfg.pcie;
+	pos = cfg->pcie_location;
+
+	version = cfg->pcie_flags & PCIM_EXP_FLAGS_VERSION;
+
+	WREG(PCIR_EXPRESS_DEVICE_CTL, cfg->pcie_device_ctl);
+
+	if (version > 1 || cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_ENDPOINT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_LEGACY_ENDPOINT)
+		WREG(PCIR_EXPRESS_LINK_CTL, cfg->pcie_link_ctl);
+
+	if (version > 1 || (cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    (cfg->pcie_type == PCIM_EXP_TYPE_DOWNSTREAM_PORT &&
+	     (cfg->pcie_flags & PCIM_EXP_FLAGS_SLOT))))
+		WREG(PCIR_EXPRESS_SLOT_CTL, cfg->pcie_slot_ctl);
+
+	if (version > 1 || cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_ROOT_EC)
+		WREG(PCIR_EXPRESS_ROOT_CTL, cfg->pcie_root_ctl);
+
+	if (version > 1) {
+		WREG(PCIR_EXPRESS_DEVICE_CTL2, cfg->pcie_device_ctl2);
+		WREG(PCIR_EXPRESS_LINK_CTL2, cfg->pcie_link_ctl2);
+		WREG(PCIR_EXPRESS_SLOT_CTL2, cfg->pcie_slot_ctl2);
+	}
+#undef WREG
+}
+
+static void
+pci_cfg_restore_pcix(device_t dev, struct pci_devinfo *dinfo)
+{
+	pci_write_config(dev, dinfo->cfg.pcix.pcix_location + PCIXR_COMMAND,
+	    dinfo->cfg.pcix.pcix_command,  2);
+}
+
 void
 pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
 {
@@ -4479,6 +4523,14 @@ pci_cfg_restore(device_t dev, struct pci
 	pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
 	pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
 
+	/*
+	 * Restore extended capabilities for PCI-Express and PCI-X
+	 */
+	if (dinfo->cfg.pcie.pcie_location != 0)
+		pci_cfg_restore_pcie(dev, dinfo);
+	if (dinfo->cfg.pcix.pcix_location != 0)
+		pci_cfg_restore_pcix(dev, dinfo);
+
 	/* Restore MSI and MSI-X configurations if they are present. */
 	if (dinfo->cfg.msi.msi_location != 0)
 		pci_resume_msi(dev);
@@ -4486,6 +4538,51 @@ pci_cfg_restore(device_t dev, struct pci
 		pci_resume_msix(dev);
 }
 
+static void
+pci_cfg_save_pcie(device_t dev, struct pci_devinfo *dinfo)
+{
+#define	RREG(n)	pci_read_config(dev, pos + (n), 2)
+	struct pcicfg_pcie *cfg;
+	int version, pos;
+
+	cfg = &dinfo->cfg.pcie;
+	pos = cfg->pcie_location;
+
+	cfg->pcie_flags = RREG(PCIR_EXPRESS_FLAGS);
+
+	version = cfg->pcie_flags & PCIM_EXP_FLAGS_VERSION;
+
+	cfg->pcie_device_ctl = RREG(PCIR_EXPRESS_DEVICE_CTL);
+
+	if (version > 1 || cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_ENDPOINT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_LEGACY_ENDPOINT)
+		cfg->pcie_link_ctl = RREG(PCIR_EXPRESS_LINK_CTL);
+
+	if (version > 1 || (cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    (cfg->pcie_type == PCIM_EXP_TYPE_DOWNSTREAM_PORT &&
+	     (cfg->pcie_flags & PCIM_EXP_FLAGS_SLOT))))
+		cfg->pcie_slot_ctl = RREG(PCIR_EXPRESS_SLOT_CTL);
+
+	if (version > 1 || cfg->pcie_type == PCIM_EXP_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIM_EXP_TYPE_ROOT_EC)
+		cfg->pcie_root_ctl = RREG(PCIR_EXPRESS_ROOT_CTL);
+
+	if (version > 1) {
+		cfg->pcie_device_ctl2 = RREG(PCIR_EXPRESS_DEVICE_CTL2);
+		cfg->pcie_link_ctl2 = RREG(PCIR_EXPRESS_LINK_CTL2);
+		cfg->pcie_slot_ctl2 = RREG(PCIR_EXPRESS_SLOT_CTL2);
+	}
+#undef RREG
+}
+
+static void
+pci_cfg_save_pcix(device_t dev, struct pci_devinfo *dinfo)
+{
+	dinfo->cfg.pcix.pcix_command = pci_read_config(dev,
+	    dinfo->cfg.pcix.pcix_location + PCIXR_COMMAND, 2);
+}
+
 void
 pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
 {
@@ -4528,6 +4625,12 @@ pci_cfg_save(device_t dev, struct pci_de
 	dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1);
 	dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1);
 
+	if (dinfo->cfg.pcie.pcie_location != 0)
+		pci_cfg_save_pcie(dev, dinfo);
+
+	if (dinfo->cfg.pcix.pcix_location != 0)
+		pci_cfg_save_pcix(dev, dinfo);
+
 	/*
 	 * don't set the state for display devices, base peripherals and
 	 * memory devices since bad things happen when they are powered down.

Modified: head/sys/dev/pci/pcireg.h
==============================================================================
--- head/sys/dev/pci/pcireg.h	Thu Mar  8 21:06:05 2012	(r232703)
+++ head/sys/dev/pci/pcireg.h	Thu Mar  8 21:09:34 2012	(r232704)
@@ -667,6 +667,16 @@
 #define	PCIR_EXPRESS_SLOT_STA	0x1a
 #define	PCIR_EXPRESS_ROOT_CTL	0x1c
 #define	PCIR_EXPRESS_ROOT_STA	0x20
+#define	PCIR_EXPRESS_DEVICE_CTL2	40
+#define	PCIM_EXPRESS_DEVICE_CTL2_ARI	0x20
+#define	PCIM_EXPRESS_ID_ORDERED_REQ_EN	0x100
+#define	PCIM_EXPRESS_ID_ORDERED_CMP_EN	0x200
+#define	PCIM_EXPRESS_LTR_ENABLE		0x400
+#define	PCIM_EXPRESS_OBFF_MSGA_ENABLE	0x2000
+#define	PCIM_EXPRESS_OBFF_MSGB_ENABLE	0x4000
+#define PCIM_EXPRESS_OBFF_WAKE_ENABLE	0x6000
+#define PCIR_EXPRESS_LINK_CTL2		48
+#define PCIR_EXPRESS_SLOT_CTL2		56
 
 /* MSI-X definitions */
 #define	PCIR_MSIX_CTRL		0x2

Modified: head/sys/dev/pci/pcivar.h
==============================================================================
--- head/sys/dev/pci/pcivar.h	Thu Mar  8 21:06:05 2012	(r232703)
+++ head/sys/dev/pci/pcivar.h	Thu Mar  8 21:09:34 2012	(r232704)
@@ -127,6 +127,19 @@ struct pcicfg_ht {
 struct pcicfg_pcie {
     uint8_t	pcie_location;	/* Offset of PCI-e capability registers. */
     uint8_t	pcie_type;	/* Device type. */
+    uint16_t	pcie_flags;	/* Device capabilities register. */
+    uint16_t	pcie_device_ctl; /* Device control register. */
+    uint16_t	pcie_link_ctl;	/* Link control register. */
+    uint16_t	pcie_slot_ctl;	/* Slot control register. */
+    uint16_t	pcie_root_ctl;	/* Root control register. */
+    uint16_t	pcie_device_ctl2; /* Second device control register. */
+    uint16_t	pcie_link_ctl2;	/* Second link control register. */
+    uint16_t	pcie_slot_ctl2;	/* Second slot control register. */
+};
+
+struct pcicfg_pcix {
+    uint16_t	pcix_command;
+    uint8_t	pcix_location;	/* Offset of PCI-X capability registers. */
 };
 
 /* config header information common to all header types */
@@ -171,6 +184,7 @@ typedef struct pcicfg {
     struct pcicfg_msix msix;	/* PCI MSI-X */
     struct pcicfg_ht ht;	/* HyperTransport */
     struct pcicfg_pcie pcie;	/* PCI Express */
+    struct pcicfg_pcix pcix;	/* PCI-X */
 } pcicfgregs;
 
 /* additional type 1 device config header information (PCI to PCI bridge) */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203082109.q28L9YIp065017>