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>