mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 20:53:53 +08:00
PCI/DPC: Save and restore config state
This patch provides DPC save and restore capabilities. This is necessary for the driver to observe DPC events in the event the configuration space needs to be restored after a reset. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Sinan Kaya <okaya@kernel.org>
This commit is contained in:
parent
874b325111
commit
4f802170a8
@ -1284,6 +1284,7 @@ int pci_save_state(struct pci_dev *dev)
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
pci_save_dpc_state(dev);
|
||||
return pci_save_vc_state(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_save_state);
|
||||
@ -1378,6 +1379,7 @@ void pci_restore_state(struct pci_dev *dev)
|
||||
pci_restore_ats_state(dev);
|
||||
pci_restore_vc_state(dev);
|
||||
pci_restore_rebar_state(dev);
|
||||
pci_restore_dpc_state(dev);
|
||||
|
||||
pci_cleanup_aer_error_status_regs(dev);
|
||||
|
||||
|
@ -346,6 +346,14 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
|
||||
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
||||
#endif /* CONFIG_PCIEAER */
|
||||
|
||||
#ifdef CONFIG_PCIE_DPC
|
||||
void pci_save_dpc_state(struct pci_dev *dev);
|
||||
void pci_restore_dpc_state(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pci_save_dpc_state(struct pci_dev *dev) {}
|
||||
static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_ATS
|
||||
void pci_restore_ats_state(struct pci_dev *dev);
|
||||
#else
|
||||
|
@ -44,6 +44,58 @@ static const char * const rp_pio_error_string[] = {
|
||||
"Memory Request Completion Timeout", /* Bit Position 18 */
|
||||
};
|
||||
|
||||
static struct dpc_dev *to_dpc_dev(struct pci_dev *dev)
|
||||
{
|
||||
struct device *device;
|
||||
|
||||
device = pcie_port_find_device(dev, PCIE_PORT_SERVICE_DPC);
|
||||
if (!device)
|
||||
return NULL;
|
||||
return get_service_data(to_pcie_device(device));
|
||||
}
|
||||
|
||||
void pci_save_dpc_state(struct pci_dev *dev)
|
||||
{
|
||||
struct dpc_dev *dpc;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
dpc = to_dpc_dev(dev);
|
||||
if (!dpc)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
cap = (u16 *)&save_state->cap.data[0];
|
||||
pci_read_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, cap);
|
||||
}
|
||||
|
||||
void pci_restore_dpc_state(struct pci_dev *dev)
|
||||
{
|
||||
struct dpc_dev *dpc;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
dpc = to_dpc_dev(dev);
|
||||
if (!dpc)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
cap = (u16 *)&save_state->cap.data[0];
|
||||
pci_write_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, *cap);
|
||||
}
|
||||
|
||||
static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
|
||||
{
|
||||
unsigned long timeout = jiffies + HZ;
|
||||
@ -67,18 +119,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
|
||||
static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
|
||||
{
|
||||
struct dpc_dev *dpc;
|
||||
struct pcie_device *pciedev;
|
||||
struct device *devdpc;
|
||||
|
||||
u16 cap;
|
||||
|
||||
/*
|
||||
* DPC disables the Link automatically in hardware, so it has
|
||||
* already been reset by the time we get here.
|
||||
*/
|
||||
devdpc = pcie_port_find_device(pdev, PCIE_PORT_SERVICE_DPC);
|
||||
pciedev = to_pcie_device(devdpc);
|
||||
dpc = get_service_data(pciedev);
|
||||
dpc = to_dpc_dev(pdev);
|
||||
cap = dpc->cap_pos;
|
||||
|
||||
/*
|
||||
@ -259,6 +306,8 @@ static int dpc_probe(struct pcie_device *dev)
|
||||
FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
|
||||
FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size,
|
||||
FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
|
||||
|
||||
pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DPC, sizeof(u16));
|
||||
return status;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user