Skip to content

Commit

Permalink
[PATCH] pci: Repair pci_save/restore_state so we can restore one save…
Browse files Browse the repository at this point in the history
… many times.

Because we do not reserve space for the pci-x and pci-e state in struct
pci dev we need to dynamically allocate it.  However because we need
to support restore being called multiple times after a single save
it is never safe to free the buffers we have allocated to hold the
state.

So this patch modifies the save routines to first check to see
if we have already allocated a state buffer before allocating
a new one.  Then the restore routines are modified to not free
the state after restoring it.  Simple and it fixes some subtle
error path handling bugs, that are hard to test for.

Signed-off-by: Eric W. Biederman <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Acked-by: Auke Kok <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
ebiederm authored and Linus Torvalds committed Mar 12, 2007
1 parent 392ee1e commit 9f35575
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 11 deletions.
12 changes: 6 additions & 6 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
if (pos <= 0)
return 0;

save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state)
save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
Expand Down Expand Up @@ -582,8 +584,6 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
pci_remove_saved_cap(save_state);
kfree(save_state);
}


Expand All @@ -597,7 +597,9 @@ static int pci_save_pcix_state(struct pci_dev *dev)
if (pos <= 0)
return 0;

save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state)
save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
Expand All @@ -622,8 +624,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
cap = (u16 *)&save_state->data[0];

pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
pci_remove_saved_cap(save_state);
kfree(save_state);
}


Expand Down
5 changes: 0 additions & 5 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,6 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
}

static inline void pci_remove_saved_cap(struct pci_cap_saved_state *cap)
{
hlist_del(&cap->next);
}

/*
* For PCI devices, the region numbers are assigned this way:
*
Expand Down

0 comments on commit 9f35575

Please sign in to comment.