ia64/linux-2.6.18-xen.hg

annotate drivers/pci/setup-res.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 dfd2adc58740
children
rev   line source
ian@0 1 /*
ian@0 2 * drivers/pci/setup-res.c
ian@0 3 *
ian@0 4 * Extruded from code written by
ian@0 5 * Dave Rusling (david.rusling@reo.mts.dec.com)
ian@0 6 * David Mosberger (davidm@cs.arizona.edu)
ian@0 7 * David Miller (davem@redhat.com)
ian@0 8 *
ian@0 9 * Support routines for initializing a PCI subsystem.
ian@0 10 */
ian@0 11
ian@0 12 /* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
ian@0 13
ian@0 14 /*
ian@0 15 * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
ian@0 16 * Resource sorting
ian@0 17 */
ian@0 18
ian@0 19 #include <linux/init.h>
ian@0 20 #include <linux/kernel.h>
ian@0 21 #include <linux/pci.h>
ian@0 22 #include <linux/errno.h>
ian@0 23 #include <linux/ioport.h>
ian@0 24 #include <linux/cache.h>
ian@0 25 #include <linux/slab.h>
ian@0 26 #include "pci.h"
ian@0 27
ian@0 28
ian@0 29 void
keir@815 30 pci_update_resource(struct pci_dev *dev, int resno)
ian@0 31 {
ian@0 32 struct pci_bus_region region;
ian@0 33 u32 new, check, mask;
ian@0 34 int reg;
keir@818 35 enum pci_bar_type type;
keir@815 36 struct resource *res = dev->resource + resno;
ian@0 37
ian@0 38 /* Ignore resources for unimplemented BARs and unused resource slots
ian@0 39 for 64 bit BARs. */
ian@0 40 if (!res->flags)
ian@0 41 return;
ian@0 42
ian@0 43 pcibios_resource_to_bus(dev, &region, res);
ian@0 44
ian@0 45 pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
ian@0 46 "BAR %d of %s\n", (unsigned long long)res->start,
ian@0 47 (unsigned long long)res->end,
ian@0 48 region.start, region.end, res->flags, resno, pci_name(dev));
ian@0 49
ian@0 50 new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
ian@0 51 if (res->flags & IORESOURCE_IO)
ian@0 52 mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
ian@0 53 else
ian@0 54 mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
ian@0 55
keir@818 56 reg = pci_resource_bar(dev, resno, &type);
keir@818 57 if (!reg)
keir@818 58 return;
keir@818 59 if (type != pci_bar_unknown) {
ian@0 60 if (!(res->flags & IORESOURCE_ROM_ENABLE))
ian@0 61 return;
ian@0 62 new |= PCI_ROM_ADDRESS_ENABLE;
ian@0 63 }
ian@0 64
ian@0 65 pci_write_config_dword(dev, reg, new);
ian@0 66 pci_read_config_dword(dev, reg, &check);
ian@0 67
ian@0 68 if ((new ^ check) & mask) {
ian@0 69 printk(KERN_ERR "PCI: Error while updating region "
ian@0 70 "%s/%d (%08x != %08x)\n", pci_name(dev), resno,
ian@0 71 new, check);
ian@0 72 }
ian@0 73
ian@0 74 if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
ian@0 75 (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
ian@0 76 new = region.start >> 16 >> 16;
ian@0 77 pci_write_config_dword(dev, reg + 4, new);
ian@0 78 pci_read_config_dword(dev, reg + 4, &check);
ian@0 79 if (check != new) {
ian@0 80 printk(KERN_ERR "PCI: Error updating region "
ian@0 81 "%s/%d (high %08x != %08x)\n",
ian@0 82 pci_name(dev), resno, new, check);
ian@0 83 }
ian@0 84 }
ian@0 85 res->flags &= ~IORESOURCE_UNSET;
ian@0 86 pr_debug("PCI: moved device %s resource %d (%lx) to %x\n",
ian@0 87 pci_name(dev), resno, res->flags,
ian@0 88 new & ~PCI_REGION_FLAG_MASK);
ian@0 89 }
ian@0 90
ian@0 91 int __devinit
ian@0 92 pci_claim_resource(struct pci_dev *dev, int resource)
ian@0 93 {
ian@0 94 struct resource *res = &dev->resource[resource];
ian@0 95 struct resource *root = NULL;
ian@0 96 char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
ian@0 97 int err;
ian@0 98
ian@0 99 root = pcibios_select_root(dev, res);
ian@0 100
ian@0 101 err = -EINVAL;
ian@0 102 if (root != NULL)
ian@0 103 err = insert_resource(root, res);
ian@0 104
ian@0 105 if (err) {
ian@0 106 printk(KERN_ERR "PCI: %s region %d of %s %s [%llx:%llx]\n",
ian@0 107 root ? "Address space collision on" :
ian@0 108 "No parent found for",
ian@0 109 resource, dtype, pci_name(dev),
ian@0 110 (unsigned long long)res->start,
ian@0 111 (unsigned long long)res->end);
ian@0 112 }
ian@0 113
ian@0 114 return err;
ian@0 115 }
ian@0 116 EXPORT_SYMBOL_GPL(pci_claim_resource);
ian@0 117
keir@701 118 #ifdef CONFIG_PCI_REASSIGN
keir@702 119 void pci_disable_bridge_window(struct pci_dev *dev)
keir@696 120 {
keir@702 121 printk(KERN_DEBUG "PCI: Disable bridge window on %s\n", pci_name(dev));
keir@702 122
keir@702 123 /* MMIO Base/Limit */
keir@702 124 pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
keir@702 125
keir@702 126 /* Prefetchable MMIO Base/Limit */
keir@702 127 pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
keir@702 128 pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
keir@702 129 pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
keir@696 130 }
keir@701 131 #endif
keir@696 132
ian@0 133 int pci_assign_resource(struct pci_dev *dev, int resno)
ian@0 134 {
ian@0 135 struct pci_bus *bus = dev->bus;
ian@0 136 struct resource *res = dev->resource + resno;
ian@0 137 resource_size_t size, min, align;
ian@0 138 int ret;
keir@771 139 int reassigndev = pci_is_reassigndev(dev);
ian@0 140
ian@0 141 size = res->end - res->start + 1;
ian@0 142 min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
ian@0 143 /* The bridge resources are special, as their
ian@0 144 size != alignment. Sizing routines return
ian@0 145 required alignment in the "start" field. */
keir@696 146 if (resno < PCI_BRIDGE_RESOURCES) {
keir@696 147 align = size;
keir@696 148 if ((reassigndev) &&
keir@696 149 (res->flags & IORESOURCE_MEM)) {
keir@701 150 align = ALIGN(align, PAGE_SIZE);
keir@696 151 }
keir@696 152 } else {
keir@696 153 align = res->start;
keir@696 154 }
ian@0 155
ian@0 156 /* First, try exact prefetching match.. */
ian@0 157 ret = pci_bus_alloc_resource(bus, res, size, align, min,
ian@0 158 IORESOURCE_PREFETCH,
ian@0 159 pcibios_align_resource, dev);
ian@0 160
ian@0 161 if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
ian@0 162 /*
ian@0 163 * That failed.
ian@0 164 *
ian@0 165 * But a prefetching area can handle a non-prefetching
ian@0 166 * window (it will just not perform as well).
ian@0 167 */
ian@0 168 ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
ian@0 169 pcibios_align_resource, dev);
ian@0 170 }
ian@0 171
ian@0 172 if (ret) {
ian@0 173 printk(KERN_ERR "PCI: Failed to allocate %s resource "
ian@0 174 "#%d:%llx@%llx for %s\n",
ian@0 175 res->flags & IORESOURCE_IO ? "I/O" : "mem",
ian@0 176 resno, (unsigned long long)size,
ian@0 177 (unsigned long long)res->start, pci_name(dev));
ian@0 178 } else if (resno < PCI_BRIDGE_RESOURCES) {
keir@703 179 if (reassigndev)
keir@701 180 printk(KERN_DEBUG "PCI: Assign resource(%d) on %s "
keir@701 181 "%016llx - %016llx\n", resno, pci_name(dev),
keir@701 182 (unsigned long long)res->start,
keir@701 183 (unsigned long long)res->end);
keir@815 184 pci_update_resource(dev, resno);
ian@0 185 }
ian@0 186
ian@0 187 return ret;
ian@0 188 }
ian@0 189
ian@0 190 #ifdef CONFIG_EMBEDDED
ian@0 191 int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
ian@0 192 {
ian@0 193 struct pci_bus *bus = dev->bus;
ian@0 194 struct resource *res = dev->resource + resno;
ian@0 195 unsigned int type_mask;
ian@0 196 int i, ret = -EBUSY;
ian@0 197
ian@0 198 type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH;
ian@0 199
ian@0 200 for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
ian@0 201 struct resource *r = bus->resource[i];
ian@0 202 if (!r)
ian@0 203 continue;
ian@0 204
ian@0 205 /* type_mask must match */
ian@0 206 if ((res->flags ^ r->flags) & type_mask)
ian@0 207 continue;
ian@0 208
ian@0 209 ret = request_resource(r, res);
ian@0 210
ian@0 211 if (ret == 0)
ian@0 212 break;
ian@0 213 }
ian@0 214
ian@0 215 if (ret) {
ian@0 216 printk(KERN_ERR "PCI: Failed to allocate %s resource "
ian@0 217 "#%d:%llx@%llx for %s\n",
ian@0 218 res->flags & IORESOURCE_IO ? "I/O" : "mem",
ian@0 219 resno, (unsigned long long)(res->end - res->start + 1),
ian@0 220 (unsigned long long)res->start, pci_name(dev));
ian@0 221 } else if (resno < PCI_BRIDGE_RESOURCES) {
keir@815 222 pci_update_resource(dev, resno);
ian@0 223 }
ian@0 224
ian@0 225 return ret;
ian@0 226 }
ian@0 227 EXPORT_SYMBOL_GPL(pci_assign_resource_fixed);
ian@0 228 #endif
ian@0 229
ian@0 230 /* Sort resources by alignment */
ian@0 231 void __devinit
ian@0 232 pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
ian@0 233 {
ian@0 234 int i;
keir@771 235 int reassigndev = pci_is_reassigndev(dev);
ian@0 236
ian@0 237 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
ian@0 238 struct resource *r;
ian@0 239 struct resource_list *list, *tmp;
ian@0 240 resource_size_t r_align;
ian@0 241
ian@0 242 r = &dev->resource[i];
ian@0 243 r_align = r->end - r->start;
ian@0 244
ian@0 245 if (!(r->flags) || r->parent)
ian@0 246 continue;
keir@746 247
ian@0 248 if (!r_align) {
ian@0 249 printk(KERN_WARNING "PCI: Ignore bogus resource %d "
ian@0 250 "[%llx:%llx] of %s\n",
ian@0 251 i, (unsigned long long)r->start,
ian@0 252 (unsigned long long)r->end, pci_name(dev));
ian@0 253 continue;
ian@0 254 }
ian@0 255 r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
keir@862 256
keir@862 257 if (i < PCI_BRIDGE_RESOURCES && (r->flags & IORESOURCE_MEM) &&
keir@862 258 reassigndev)
keir@862 259 r_align = ALIGN(r_align, PAGE_SIZE);
keir@862 260
ian@0 261 for (list = head; ; list = list->next) {
ian@0 262 resource_size_t align = 0;
ian@0 263 struct resource_list *ln = list->next;
ian@0 264 int idx;
ian@0 265
ian@0 266 if (ln) {
ian@0 267 idx = ln->res - &ln->dev->resource[0];
ian@0 268 align = (idx < PCI_BRIDGE_RESOURCES) ?
ian@0 269 ln->res->end - ln->res->start + 1 :
ian@0 270 ln->res->start;
keir@746 271 if ((idx < PCI_BRIDGE_RESOURCES) &&
keir@746 272 (ln->res->flags & IORESOURCE_MEM) &&
keir@771 273 pci_is_reassigndev(ln->dev))
keir@746 274 align = ALIGN(align, PAGE_SIZE);
ian@0 275 }
ian@0 276 if (r_align > align) {
ian@0 277 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
ian@0 278 if (!tmp)
ian@0 279 panic("pdev_sort_resources(): "
ian@0 280 "kmalloc() failed!\n");
ian@0 281 tmp->next = ln;
ian@0 282 tmp->res = r;
ian@0 283 tmp->dev = dev;
ian@0 284 list->next = tmp;
ian@0 285 break;
ian@0 286 }
ian@0 287 }
ian@0 288 }
ian@0 289 }