Skip to content

Commit

Permalink
[PATCH] PCI: acpi tg3 ethernet not coming back properly after S3 susp…
Browse files Browse the repository at this point in the history
…endon DellM70

This patch, is based on kernel 2.6.12, provides a fix for PCIe
port bus driver suspend/resume.

Signed-off-by: T. Long Nguyen <tom.l.nguyen@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
long authored and Greg Kroah-Hartman committed Jul 1, 2005
1 parent a00db37 commit 5823d10
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
5 changes: 5 additions & 0 deletions drivers/pci/pcie/portdrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@

#define get_descriptor_id(type, service) (((type - 4) << 4) | service)

struct pcie_port_device_ext {
int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */
unsigned int saved_msi_config_space[5];
};

extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_probe(struct pci_dev *dev);
extern int pcie_port_device_register(struct pci_dev *dev);
Expand Down
8 changes: 8 additions & 0 deletions drivers/pci/pcie/portdrv_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,17 @@ int pcie_port_device_probe(struct pci_dev *dev)

int pcie_port_device_register(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext;
int status, type, capabilities, irq_mode, i;
int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
u16 reg16;

/* Allocate port device extension */
if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL)))
return -ENOMEM;

pci_set_drvdata(dev, p_ext);

/* Get port type */
pci_read_config_word(dev,
pci_find_capability(dev, PCI_CAP_ID_EXP) +
Expand All @@ -288,6 +295,7 @@ int pcie_port_device_register(struct pci_dev *dev)
/* Now get port services */
capabilities = get_port_device_capability(dev);
irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
p_ext->interrupt_mode = irq_mode;

/* Allocate child services if any */
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
Expand Down
79 changes: 78 additions & 1 deletion drivers/pci/pcie/portdrv_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,78 @@ MODULE_LICENSE("GPL");
/* global data */
static const char device_name[] = "pcieport-driver";

static void pci_save_msi_state(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
int i = 0, pos;
u16 control;

if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0)
return;

pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]);
control = p_ext->saved_msi_config_space[0] >> 16;
pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
&p_ext->saved_msi_config_space[i++]);
if (control & PCI_MSI_FLAGS_64BIT) {
pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
&p_ext->saved_msi_config_space[i++]);
pci_read_config_dword(dev, pos + PCI_MSI_DATA_64,
&p_ext->saved_msi_config_space[i++]);
} else
pci_read_config_dword(dev, pos + PCI_MSI_DATA_32,
&p_ext->saved_msi_config_space[i++]);
if (control & PCI_MSI_FLAGS_MASKBIT)
pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT,
&p_ext->saved_msi_config_space[i++]);
}

static void pci_restore_msi_state(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
int i = 0, pos;
u16 control;

if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0)
return;

control = p_ext->saved_msi_config_space[i++] >> 16;
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
p_ext->saved_msi_config_space[i++]);
if (control & PCI_MSI_FLAGS_64BIT) {
pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
p_ext->saved_msi_config_space[i++]);
pci_write_config_dword(dev, pos + PCI_MSI_DATA_64,
p_ext->saved_msi_config_space[i++]);
} else
pci_write_config_dword(dev, pos + PCI_MSI_DATA_32,
p_ext->saved_msi_config_space[i++]);
if (control & PCI_MSI_FLAGS_MASKBIT)
pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT,
p_ext->saved_msi_config_space[i++]);
}

static void pcie_portdrv_save_config(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);

pci_save_state(dev);
if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE)
pci_save_msi_state(dev);
}

static void pcie_portdrv_restore_config(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);

pci_restore_state(dev);
if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE)
pci_restore_msi_state(dev);
pci_enable_device(dev);
pci_set_master(dev);
}

/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
Expand Down Expand Up @@ -64,16 +136,21 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
static void pcie_portdrv_remove (struct pci_dev *dev)
{
pcie_port_device_remove(dev);
kfree(pci_get_drvdata(dev));
}

#ifdef CONFIG_PM
static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
{
return pcie_port_device_suspend(dev, state);
int ret = pcie_port_device_suspend(dev, state);

pcie_portdrv_save_config(dev);
return ret;
}

static int pcie_portdrv_resume (struct pci_dev *dev)
{
pcie_portdrv_restore_config(dev);
return pcie_port_device_resume(dev);
}
#endif
Expand Down

0 comments on commit 5823d10

Please sign in to comment.