ia64/linux-2.6.18-xen.hg

annotate drivers/pci/msi-altix.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * This file is subject to the terms and conditions of the GNU General Public
ian@0 3 * License. See the file "COPYING" in the main directory of this archive
ian@0 4 * for more details.
ian@0 5 *
ian@0 6 * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved.
ian@0 7 */
ian@0 8
ian@0 9 #include <linux/types.h>
ian@0 10 #include <linux/pci.h>
ian@0 11 #include <linux/cpumask.h>
ian@0 12
ian@0 13 #include <asm/sn/addrs.h>
ian@0 14 #include <asm/sn/intr.h>
ian@0 15 #include <asm/sn/pcibus_provider_defs.h>
ian@0 16 #include <asm/sn/pcidev.h>
ian@0 17 #include <asm/sn/nodepda.h>
ian@0 18
ian@0 19 #include "msi.h"
ian@0 20
ian@0 21 struct sn_msi_info {
ian@0 22 u64 pci_addr;
ian@0 23 struct sn_irq_info *sn_irq_info;
ian@0 24 };
ian@0 25
ian@0 26 static struct sn_msi_info *sn_msi_info;
ian@0 27
ian@0 28 static void
ian@0 29 sn_msi_teardown(unsigned int vector)
ian@0 30 {
ian@0 31 nasid_t nasid;
ian@0 32 int widget;
ian@0 33 struct pci_dev *pdev;
ian@0 34 struct pcidev_info *sn_pdev;
ian@0 35 struct sn_irq_info *sn_irq_info;
ian@0 36 struct pcibus_bussoft *bussoft;
ian@0 37 struct sn_pcibus_provider *provider;
ian@0 38
ian@0 39 sn_irq_info = sn_msi_info[vector].sn_irq_info;
ian@0 40 if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
ian@0 41 return;
ian@0 42
ian@0 43 sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
ian@0 44 pdev = sn_pdev->pdi_linux_pcidev;
ian@0 45 provider = SN_PCIDEV_BUSPROVIDER(pdev);
ian@0 46
ian@0 47 (*provider->dma_unmap)(pdev,
ian@0 48 sn_msi_info[vector].pci_addr,
ian@0 49 PCI_DMA_FROMDEVICE);
ian@0 50 sn_msi_info[vector].pci_addr = 0;
ian@0 51
ian@0 52 bussoft = SN_PCIDEV_BUSSOFT(pdev);
ian@0 53 nasid = NASID_GET(bussoft->bs_base);
ian@0 54 widget = (nasid & 1) ?
ian@0 55 TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
ian@0 56 SWIN_WIDGETNUM(bussoft->bs_base);
ian@0 57
ian@0 58 sn_intr_free(nasid, widget, sn_irq_info);
ian@0 59 sn_msi_info[vector].sn_irq_info = NULL;
ian@0 60
ian@0 61 return;
ian@0 62 }
ian@0 63
ian@0 64 int
ian@0 65 sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
ian@0 66 u32 *addr_hi, u32 *addr_lo, u32 *data)
ian@0 67 {
ian@0 68 int widget;
ian@0 69 int status;
ian@0 70 nasid_t nasid;
ian@0 71 u64 bus_addr;
ian@0 72 struct sn_irq_info *sn_irq_info;
ian@0 73 struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
ian@0 74 struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
ian@0 75
ian@0 76 if (bussoft == NULL)
ian@0 77 return -EINVAL;
ian@0 78
ian@0 79 if (provider == NULL || provider->dma_map_consistent == NULL)
ian@0 80 return -EINVAL;
ian@0 81
ian@0 82 /*
ian@0 83 * Set up the vector plumbing. Let the prom (via sn_intr_alloc)
ian@0 84 * decide which cpu to direct this msi at by default.
ian@0 85 */
ian@0 86
ian@0 87 nasid = NASID_GET(bussoft->bs_base);
ian@0 88 widget = (nasid & 1) ?
ian@0 89 TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
ian@0 90 SWIN_WIDGETNUM(bussoft->bs_base);
ian@0 91
ian@0 92 sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
ian@0 93 if (! sn_irq_info)
ian@0 94 return -ENOMEM;
ian@0 95
ian@0 96 status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
ian@0 97 if (status) {
ian@0 98 kfree(sn_irq_info);
ian@0 99 return -ENOMEM;
ian@0 100 }
ian@0 101
ian@0 102 sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */
ian@0 103 sn_irq_fixup(pdev, sn_irq_info);
ian@0 104
ian@0 105 /* Prom probably should fill these in, but doesn't ... */
ian@0 106 sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
ian@0 107 sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
ian@0 108
ian@0 109 /*
ian@0 110 * Map the xio address into bus space
ian@0 111 */
ian@0 112 bus_addr = (*provider->dma_map_consistent)(pdev,
ian@0 113 sn_irq_info->irq_xtalkaddr,
ian@0 114 sizeof(sn_irq_info->irq_xtalkaddr),
ian@0 115 SN_DMA_MSI|SN_DMA_ADDR_XIO);
ian@0 116 if (! bus_addr) {
ian@0 117 sn_intr_free(nasid, widget, sn_irq_info);
ian@0 118 kfree(sn_irq_info);
ian@0 119 return -ENOMEM;
ian@0 120 }
ian@0 121
ian@0 122 sn_msi_info[vector].sn_irq_info = sn_irq_info;
ian@0 123 sn_msi_info[vector].pci_addr = bus_addr;
ian@0 124
ian@0 125 *addr_hi = (u32)(bus_addr >> 32);
ian@0 126 *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
ian@0 127
ian@0 128 /*
ian@0 129 * In the SN platform, bit 16 is a "send vector" bit which
ian@0 130 * must be present in order to move the vector through the system.
ian@0 131 */
ian@0 132 *data = 0x100 + (unsigned int)vector;
ian@0 133
ian@0 134 #ifdef CONFIG_SMP
ian@0 135 set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
ian@0 136 #endif
ian@0 137
ian@0 138 return 0;
ian@0 139 }
ian@0 140
ian@0 141 static void
ian@0 142 sn_msi_target(unsigned int vector, unsigned int cpu,
ian@0 143 u32 *addr_hi, u32 *addr_lo)
ian@0 144 {
ian@0 145 int slice;
ian@0 146 nasid_t nasid;
ian@0 147 u64 bus_addr;
ian@0 148 struct pci_dev *pdev;
ian@0 149 struct pcidev_info *sn_pdev;
ian@0 150 struct sn_irq_info *sn_irq_info;
ian@0 151 struct sn_irq_info *new_irq_info;
ian@0 152 struct sn_pcibus_provider *provider;
ian@0 153
ian@0 154 sn_irq_info = sn_msi_info[vector].sn_irq_info;
ian@0 155 if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
ian@0 156 return;
ian@0 157
ian@0 158 /*
ian@0 159 * Release XIO resources for the old MSI PCI address
ian@0 160 */
ian@0 161
ian@0 162 sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
ian@0 163 pdev = sn_pdev->pdi_linux_pcidev;
ian@0 164 provider = SN_PCIDEV_BUSPROVIDER(pdev);
ian@0 165
ian@0 166 bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
ian@0 167 (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
ian@0 168 sn_msi_info[vector].pci_addr = 0;
ian@0 169
ian@0 170 nasid = cpuid_to_nasid(cpu);
ian@0 171 slice = cpuid_to_slice(cpu);
ian@0 172
ian@0 173 new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
ian@0 174 sn_msi_info[vector].sn_irq_info = new_irq_info;
ian@0 175 if (new_irq_info == NULL)
ian@0 176 return;
ian@0 177
ian@0 178 /*
ian@0 179 * Map the xio address into bus space
ian@0 180 */
ian@0 181
ian@0 182 bus_addr = (*provider->dma_map_consistent)(pdev,
ian@0 183 new_irq_info->irq_xtalkaddr,
ian@0 184 sizeof(new_irq_info->irq_xtalkaddr),
ian@0 185 SN_DMA_MSI|SN_DMA_ADDR_XIO);
ian@0 186
ian@0 187 sn_msi_info[vector].pci_addr = bus_addr;
ian@0 188 *addr_hi = (u32)(bus_addr >> 32);
ian@0 189 *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
ian@0 190 }
ian@0 191
ian@0 192 struct msi_ops sn_msi_ops = {
ian@0 193 .setup = sn_msi_setup,
ian@0 194 .teardown = sn_msi_teardown,
ian@0 195 #ifdef CONFIG_SMP
ian@0 196 .target = sn_msi_target,
ian@0 197 #endif
ian@0 198 };
ian@0 199
ian@0 200 int
ian@0 201 sn_msi_init(void)
ian@0 202 {
ian@0 203 sn_msi_info =
ian@0 204 kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
ian@0 205 if (! sn_msi_info)
ian@0 206 return -ENOMEM;
ian@0 207
ian@0 208 msi_register(&sn_msi_ops);
ian@0 209 return 0;
ian@0 210 }