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
This commit is contained in:
parent
f8fecfb833
commit
4ea9702d06
@ -723,6 +723,7 @@ pci_read_cap(device_t pcib, pcicfgregs *cfg)
|
||||
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, void *arg)
|
||||
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_devinfo *dinfo)
|
||||
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_devinfo *dinfo)
|
||||
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_devinfo *dinfo, int setstate)
|
||||
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.
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
Loading…
Reference in New Issue
Block a user