PCI: Add support for save/restore of extended capabilities
authorAlex Williamson <alex.williamson@redhat.com>
Tue, 17 Dec 2013 23:43:45 +0000 (16:43 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 18 Dec 2013 00:38:32 +0000 (17:38 -0700)
Current save/restore is specific to standard capabilities.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pci.c
include/linux/pci.h

index bb257b975a8f795787d0552f85a06b3096ba5d57..8f2be7ec705c5bc061386d019f450cf896ba8740 100644 (file)
@@ -861,18 +861,28 @@ EXPORT_SYMBOL(pci_choose_state);
 #define PCI_EXP_SAVE_REGS      7
 
 
-static struct pci_cap_saved_state *pci_find_saved_cap(
-       struct pci_dev *pci_dev, char cap)
+static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
+                                                      u16 cap, bool extended)
 {
        struct pci_cap_saved_state *tmp;
 
        hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) {
-               if (tmp->cap.cap_nr == cap)
+               if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap)
                        return tmp;
        }
        return NULL;
 }
 
+struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap)
+{
+       return _pci_find_saved_cap(dev, cap, false);
+}
+
+struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap)
+{
+       return _pci_find_saved_cap(dev, cap, true);
+}
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
        int i = 0;
@@ -1113,7 +1123,7 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
        while (cap->size) {
                struct pci_cap_saved_state *tmp;
 
-               tmp = pci_find_saved_cap(dev, cap->cap_nr);
+               tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended);
                if (!tmp || tmp->cap.size != cap->size)
                        return -EINVAL;
 
@@ -2047,18 +2057,24 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev,
 }
 
 /**
- * pci_add_cap_save_buffer - allocate buffer for saving given capability registers
+ * _pci_add_cap_save_buffer - allocate buffer for saving given
+ *                            capability registers
  * @dev: the PCI device
  * @cap: the capability to allocate the buffer for
+ * @extended: Standard or Extended capability ID
  * @size: requested size of the buffer
  */
-static int pci_add_cap_save_buffer(
-       struct pci_dev *dev, char cap, unsigned int size)
+static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
+                                   bool extended, unsigned int size)
 {
        int pos;
        struct pci_cap_saved_state *save_state;
 
-       pos = pci_find_capability(dev, cap);
+       if (extended)
+               pos = pci_find_ext_capability(dev, cap);
+       else
+               pos = pci_find_capability(dev, cap);
+
        if (pos <= 0)
                return 0;
 
@@ -2067,12 +2083,23 @@ static int pci_add_cap_save_buffer(
                return -ENOMEM;
 
        save_state->cap.cap_nr = cap;
+       save_state->cap.cap_extended = extended;
        save_state->cap.size = size;
        pci_add_saved_cap(dev, save_state);
 
        return 0;
 }
 
+int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
+{
+       return _pci_add_cap_save_buffer(dev, cap, false, size);
+}
+
+int pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size)
+{
+       return _pci_add_cap_save_buffer(dev, cap, true, size);
+}
+
 /**
  * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
  * @dev: the PCI device
index 211ce43ba48324b8568af7c5be3d3d8fa4107344..1bb75b0c4c6fc17b90aab415ef2ef0033c3089a3 100644 (file)
@@ -224,7 +224,8 @@ enum pci_bus_speed {
 };
 
 struct pci_cap_saved_data {
-       char cap_nr;
+       u16 cap_nr;
+       bool cap_extended;
        unsigned int size;
        u32 data[0];
 };
@@ -977,6 +978,12 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev);
 int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state);
 int pci_load_and_free_saved_state(struct pci_dev *dev,
                                  struct pci_saved_state **state);
+struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap);
+struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
+                                                  u16 cap);
+int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size);
+int pci_add_ext_cap_save_buffer(struct pci_dev *dev,
+                               u16 cap, unsigned int size);
 int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);