From: root Date: Mon, 19 Jan 2009 19:43:08 +0000 (-0500) Subject: Host S3 changes - a) Backport dom0 xen-unstable changeset 736 & 750. b) Fix netback... X-Git-Url: http://xenbits.xen.org/gitweb?a=commitdiff_plain;h=2e2ff55e5f79f2bfeda80b97d12c60d4e7f333c5;p=xenclient%2Fkernel.git Host S3 changes - a) Backport dom0 xen-unstable changeset 736 & 750. b) Fix netback code impeding host S3. --- diff --git a/drivers/pci/msi-xen.c b/drivers/pci/msi-xen.c index 22e7669c..4e459252 100644 --- a/drivers/pci/msi-xen.c +++ b/drivers/pci/msi-xen.c @@ -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; } diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c index 11518632..36a3a834 100644 --- a/drivers/xen/netback/netback.c +++ b/drivers/xen/netback/netback.c @@ -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();