]> xenbits.xen.org Git - xenclient/kernel.git/commitdiff
Host S3 changes - a) Backport dom0 xen-unstable changeset 736 & 750. b) Fix netback...
authorroot <root@localhost.localdomain>
Mon, 19 Jan 2009 19:43:08 +0000 (14:43 -0500)
committerroot <root@localhost.localdomain>
Mon, 19 Jan 2009 19:43:08 +0000 (14:43 -0500)
drivers/pci/msi-xen.c
drivers/xen/netback/netback.c

index 22e7669cbf75b76090a71007aba7dfd530fb1d7a..4e4592529ca5eecc2a7577e10971d56944dc7112 100644 (file)
@@ -42,12 +42,20 @@ struct msi_dev_list {
        struct list_head list;
        spinlock_t pirq_list_lock;
        struct list_head pirq_list_head;
+       /* Used for saving/restoring MSI-X tables */
+       void __iomem *mask_base;
 };
 
 struct msi_pirq_entry {
        struct list_head list;
        int pirq;
        int entry_nr;
+#ifdef CONFIG_PM
+       /* PM save area for MSIX address/data */
+       u32     address_hi_save;
+       u32     address_lo_save;
+       u32     data_save;
+#endif
 };
 
 static struct msi_dev_list *get_msi_dev_pirq_list(struct pci_dev *dev)
@@ -285,104 +293,169 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
 #ifdef CONFIG_PM
 int pci_save_msi_state(struct pci_dev *dev)
 {
-       int pos;
+       int pos, i = 0;
+       u16 control;
+       struct pci_cap_saved_state *save_state;
+       u32 *cap;
 
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        if (pos <= 0 || dev->no_msi)
                return 0;
 
-       if (!dev->msi_enabled)
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       if (!(control & PCI_MSI_FLAGS_ENABLE))
                return 0;
 
-       /* Restore dev->irq to its default pin-assertion vector */
-       msi_unmap_pirq(dev, dev->irq);
-       /* Disable MSI mode */
-       disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
-       /* Set the flags for use of restore */
-       dev->msi_enabled = 1;
+       save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5,
+               GFP_KERNEL);
+       if (!save_state) {
+               printk(KERN_ERR "Out of memory in pci_save_msi_state\n");
+               return -ENOMEM;
+       }
+       cap = &save_state->data[0];
+
+       pci_read_config_dword(dev, pos, &cap[i++]);
+       control = cap[0] >> 16;
+       pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]);
+       if (control & PCI_MSI_FLAGS_64BIT) {
+               pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]);
+               pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]);
+       } else
+               pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]);
+       if (control & PCI_MSI_FLAGS_MASKBIT)
+               pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]);
+       save_state->cap_nr = PCI_CAP_ID_MSI;
+       pci_add_saved_cap(dev, save_state);
        return 0;
 }
 
 void pci_restore_msi_state(struct pci_dev *dev)
 {
-       int pos, pirq;
+       int i = 0, pos;
+       u16 control;
+       struct pci_cap_saved_state *save_state;
+       u32 *cap;
 
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI);
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       if (pos <= 0)
-               return;
-
-       if (!dev->msi_enabled)
-               return;
-
-       pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 0);
-       if (pirq < 0)
+       if (!save_state || pos <= 0)
                return;
+       cap = &save_state->data[0];
+
+       control = cap[i++] >> 16;
+       pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]);
+       if (control & PCI_MSI_FLAGS_64BIT) {
+               pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]);
+               pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]);
+       } else
+               pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]);
+       if (control & PCI_MSI_FLAGS_MASKBIT)
+               pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]);
+       pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+       pci_remove_saved_cap(save_state);
+       kfree(save_state);
 }
 
 int pci_save_msix_state(struct pci_dev *dev)
 {
        int pos;
+       u16 control;
+       struct pci_cap_saved_state *save_state;
        unsigned long flags;
        struct msi_dev_list *msi_dev_entry;
-       struct msi_pirq_entry *pirq_entry, *tmp;
+       struct msi_pirq_entry *pirq_entry;
+       void __iomem *base;
 
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
        if (pos <= 0 || dev->no_msi)
                return 0;
 
        /* save the capability */
-       if (!dev->msix_enabled)
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       if (!(control & PCI_MSIX_FLAGS_ENABLE))
                return 0;
 
        msi_dev_entry = get_msi_dev_pirq_list(dev);
+       /* If we failed to map the MSI-X table at pci_enable_msix,
+        * We could not support saving them here.
+        */
+       if (!(base = msi_dev_entry->mask_base))
+               return -ENOMEM;
+
+       save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
+               GFP_KERNEL);
+       if (!save_state) {
+               printk(KERN_ERR "Out of memory in pci_save_msix_state\n");
+               return -ENOMEM;
+       }
+       *((u16 *)&save_state->data[0]) = control;
 
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
-        list_for_each_entry_safe(pirq_entry, tmp,
-                                 &msi_dev_entry->pirq_list_head, list)
-               msi_unmap_pirq(dev, pirq_entry->pirq);
+       list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+               int j;
+
+               /* save the table */
+               j = pirq_entry->entry_nr;
+               pirq_entry->address_lo_save =
+                       readl(base + j * PCI_MSIX_ENTRY_SIZE +
+                             PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               pirq_entry->address_hi_save =
+                       readl(base + j * PCI_MSIX_ENTRY_SIZE +
+                             PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               pirq_entry->data_save =
+                       readl(base + j * PCI_MSIX_ENTRY_SIZE +
+                             PCI_MSIX_ENTRY_DATA_OFFSET);
+       }
        spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
 
-       disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
-       /* Set the flags for use of restore */
-       dev->msix_enabled = 1;
-
+       save_state->cap_nr = PCI_CAP_ID_MSIX;
+       pci_add_saved_cap(dev, save_state);
        return 0;
 }
 
 void pci_restore_msix_state(struct pci_dev *dev)
 {
-       int pos;
+       u16 save;
+       int pos, j;
+       void __iomem *base;
+       struct pci_cap_saved_state *save_state;
        unsigned long flags;
-       u64 table_base;
        struct msi_dev_list *msi_dev_entry;
-       struct msi_pirq_entry *pirq_entry, *tmp;
+       struct msi_pirq_entry *pirq_entry;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos <= 0)
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
+       if (!save_state)
                return;
 
-       if (!dev->msix_enabled)
+       save = *((u16 *)&save_state->data[0]);
+       pci_remove_saved_cap(save_state);
+       kfree(save_state);
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+       if (pos <= 0)
                return;
 
        msi_dev_entry = get_msi_dev_pirq_list(dev);
-       table_base = find_table_base(dev, pos);
-       if (!table_base)
-               return;
+       base = msi_dev_entry->mask_base;
 
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
-       list_for_each_entry_safe(pirq_entry, tmp,
-                                &msi_dev_entry->pirq_list_head, list) {
-               int rc = msi_map_pirq_to_vector(dev, pirq_entry->pirq,
-                                               pirq_entry->entry_nr, table_base);
-               if (rc < 0)
-                       printk(KERN_WARNING
-                              "%s: re-mapping irq #%d (pirq%d) failed: %d\n",
-                              pci_name(dev), pirq_entry->entry_nr,
-                              pirq_entry->pirq, rc);
+       list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+               /* route the table */
+               j = pirq_entry->entry_nr;
+               writel(pirq_entry->address_lo_save,
+                       base + j * PCI_MSIX_ENTRY_SIZE +
+                       PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+               writel(pirq_entry->address_hi_save,
+                       base + j * PCI_MSIX_ENTRY_SIZE +
+                       PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+               writel(pirq_entry->data_save,
+                       base + j * PCI_MSIX_ENTRY_SIZE +
+                       PCI_MSIX_ENTRY_DATA_OFFSET);
        }
        spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
 
+       pci_write_config_word(dev, msi_control_reg(pos), save);
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 }
 #endif
@@ -430,7 +503,8 @@ static int msix_capability_init(struct pci_dev *dev,
                                struct msix_entry *entries, int nvec)
 {
        u64 table_base;
-       int pirq, i, j, mapped, pos;
+       u16 control;
+       int pirq, i, j, mapped, pos, nr_entries;
        struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
        struct msi_pirq_entry *pirq_entry;
 
@@ -442,6 +516,12 @@ static int msix_capability_init(struct pci_dev *dev,
        if (!table_base)
                return -ENODEV;
 
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       nr_entries = multi_msix_capable(control);
+       if (!msi_dev_entry->mask_base)
+               msi_dev_entry->mask_base = 
+                       ioremap_nocache(table_base, nr_entries * PCI_MSIX_ENTRY_SIZE);
+
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
                mapped = 0;
@@ -729,18 +809,15 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
 
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
        if (!list_empty(&msi_dev_entry->pirq_list_head))
-       {
-               printk(KERN_WARNING "msix pirqs for dev %02x:%02x:%01x are not freed \
-                      before acquire again.\n", dev->bus->number, PCI_SLOT(dev->devfn),
-                          PCI_FUNC(dev->devfn));
                list_for_each_entry_safe(pirq_entry, tmp,
                                         &msi_dev_entry->pirq_list_head, list) {
                        msi_unmap_pirq(dev, pirq_entry->pirq);
                        list_del(&pirq_entry->list);
                        kfree(pirq_entry);
                }
-       }
        spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+       iounmap(msi_dev_entry->mask_base);
+       msi_dev_entry->mask_base = NULL;
        dev->irq = dev->irq_old;
 }
 
index 11518632765b6bc7ac15f6c28ce4faca50e9d07a..36a3a834bef2efb436dc9841c8771ee431a43c1e 100644 (file)
@@ -1682,6 +1682,9 @@ static netif_rx_response_t *make_rx_response(netif_t *netif,
 static int netbk_action_thread(void *unused)
 {
        while (1) {
+                if (try_to_freeze())
+                        continue;
+
                wait_event_interruptible(netbk_action_wq,
                        net_rx_action_work_to_do() || net_tx_action_work_to_do());
                cond_resched();