ia64/linux-2.6.18-xen.hg

annotate drivers/mca/mca-legacy.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 /* -*- mode: c; c-basic-offset: 8 -*- */
ian@0 2
ian@0 3 /*
ian@0 4 * MCA bus support functions for legacy (2.4) API.
ian@0 5 *
ian@0 6 * Legacy API means the API that operates in terms of MCA slot number
ian@0 7 *
ian@0 8 * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
ian@0 9 *
ian@0 10 **-----------------------------------------------------------------------------
ian@0 11 **
ian@0 12 ** This program is free software; you can redistribute it and/or modify
ian@0 13 ** it under the terms of the GNU General Public License as published by
ian@0 14 ** the Free Software Foundation; either version 2 of the License, or
ian@0 15 ** (at your option) any later version.
ian@0 16 **
ian@0 17 ** This program is distributed in the hope that it will be useful,
ian@0 18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
ian@0 19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ian@0 20 ** GNU General Public License for more details.
ian@0 21 **
ian@0 22 ** You should have received a copy of the GNU General Public License
ian@0 23 ** along with this program; if not, write to the Free Software
ian@0 24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
ian@0 25 **
ian@0 26 **-----------------------------------------------------------------------------
ian@0 27 */
ian@0 28
ian@0 29 #include <linux/module.h>
ian@0 30 #include <linux/device.h>
ian@0 31 #include <linux/mca-legacy.h>
ian@0 32 #include <asm/io.h>
ian@0 33
ian@0 34 /* NOTE: This structure is stack allocated */
ian@0 35 struct mca_find_adapter_info {
ian@0 36 int id;
ian@0 37 int slot;
ian@0 38 struct mca_device *mca_dev;
ian@0 39 };
ian@0 40
ian@0 41 /* The purpose of this iterator is to loop over all the devices and
ian@0 42 * find the one with the smallest slot number that's just greater than
ian@0 43 * or equal to the required slot with a matching id */
ian@0 44 static int mca_find_adapter_callback(struct device *dev, void *data)
ian@0 45 {
ian@0 46 struct mca_find_adapter_info *info = data;
ian@0 47 struct mca_device *mca_dev = to_mca_device(dev);
ian@0 48
ian@0 49 if(mca_dev->pos_id != info->id)
ian@0 50 return 0;
ian@0 51
ian@0 52 if(mca_dev->slot < info->slot)
ian@0 53 return 0;
ian@0 54
ian@0 55 if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
ian@0 56 info->mca_dev = mca_dev;
ian@0 57
ian@0 58 return 0;
ian@0 59 }
ian@0 60
ian@0 61 /**
ian@0 62 * mca_find_adapter - scan for adapters
ian@0 63 * @id: MCA identification to search for
ian@0 64 * @start: starting slot
ian@0 65 *
ian@0 66 * Search the MCA configuration for adapters matching the 16bit
ian@0 67 * ID given. The first time it should be called with start as zero
ian@0 68 * and then further calls made passing the return value of the
ian@0 69 * previous call until %MCA_NOTFOUND is returned.
ian@0 70 *
ian@0 71 * Disabled adapters are not reported.
ian@0 72 */
ian@0 73
ian@0 74 int mca_find_adapter(int id, int start)
ian@0 75 {
ian@0 76 struct mca_find_adapter_info info;
ian@0 77
ian@0 78 if(id == 0xffff)
ian@0 79 return MCA_NOTFOUND;
ian@0 80
ian@0 81 info.slot = start;
ian@0 82 info.id = id;
ian@0 83 info.mca_dev = NULL;
ian@0 84
ian@0 85 for(;;) {
ian@0 86 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
ian@0 87
ian@0 88 if(info.mca_dev == NULL)
ian@0 89 return MCA_NOTFOUND;
ian@0 90
ian@0 91 if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
ian@0 92 break;
ian@0 93
ian@0 94 /* OK, found adapter but it was disabled. Go around
ian@0 95 * again, excluding the slot we just found */
ian@0 96
ian@0 97 info.slot = info.mca_dev->slot + 1;
ian@0 98 info.mca_dev = NULL;
ian@0 99 }
ian@0 100
ian@0 101 return info.mca_dev->slot;
ian@0 102 }
ian@0 103 EXPORT_SYMBOL(mca_find_adapter);
ian@0 104
ian@0 105 /*--------------------------------------------------------------------*/
ian@0 106
ian@0 107 /**
ian@0 108 * mca_find_unused_adapter - scan for unused adapters
ian@0 109 * @id: MCA identification to search for
ian@0 110 * @start: starting slot
ian@0 111 *
ian@0 112 * Search the MCA configuration for adapters matching the 16bit
ian@0 113 * ID given. The first time it should be called with start as zero
ian@0 114 * and then further calls made passing the return value of the
ian@0 115 * previous call until %MCA_NOTFOUND is returned.
ian@0 116 *
ian@0 117 * Adapters that have been claimed by drivers and those that
ian@0 118 * are disabled are not reported. This function thus allows a driver
ian@0 119 * to scan for further cards when some may already be driven.
ian@0 120 */
ian@0 121
ian@0 122 int mca_find_unused_adapter(int id, int start)
ian@0 123 {
ian@0 124 struct mca_find_adapter_info info = { 0 };
ian@0 125
ian@0 126 if (!MCA_bus || id == 0xffff)
ian@0 127 return MCA_NOTFOUND;
ian@0 128
ian@0 129 info.slot = start;
ian@0 130 info.id = id;
ian@0 131 info.mca_dev = NULL;
ian@0 132
ian@0 133 for(;;) {
ian@0 134 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
ian@0 135
ian@0 136 if(info.mca_dev == NULL)
ian@0 137 return MCA_NOTFOUND;
ian@0 138
ian@0 139 if(info.mca_dev->status != MCA_ADAPTER_DISABLED
ian@0 140 && !info.mca_dev->driver_loaded)
ian@0 141 break;
ian@0 142
ian@0 143 /* OK, found adapter but it was disabled or already in
ian@0 144 * use. Go around again, excluding the slot we just
ian@0 145 * found */
ian@0 146
ian@0 147 info.slot = info.mca_dev->slot + 1;
ian@0 148 info.mca_dev = NULL;
ian@0 149 }
ian@0 150
ian@0 151 return info.mca_dev->slot;
ian@0 152 }
ian@0 153 EXPORT_SYMBOL(mca_find_unused_adapter);
ian@0 154
ian@0 155 /* NOTE: stack allocated structure */
ian@0 156 struct mca_find_device_by_slot_info {
ian@0 157 int slot;
ian@0 158 struct mca_device *mca_dev;
ian@0 159 };
ian@0 160
ian@0 161 static int mca_find_device_by_slot_callback(struct device *dev, void *data)
ian@0 162 {
ian@0 163 struct mca_find_device_by_slot_info *info = data;
ian@0 164 struct mca_device *mca_dev = to_mca_device(dev);
ian@0 165
ian@0 166 if(mca_dev->slot == info->slot)
ian@0 167 info->mca_dev = mca_dev;
ian@0 168
ian@0 169 return 0;
ian@0 170 }
ian@0 171
ian@0 172 struct mca_device *mca_find_device_by_slot(int slot)
ian@0 173 {
ian@0 174 struct mca_find_device_by_slot_info info;
ian@0 175
ian@0 176 info.slot = slot;
ian@0 177 info.mca_dev = NULL;
ian@0 178
ian@0 179 bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
ian@0 180
ian@0 181 return info.mca_dev;
ian@0 182 }
ian@0 183
ian@0 184 /**
ian@0 185 * mca_read_stored_pos - read POS register from boot data
ian@0 186 * @slot: slot number to read from
ian@0 187 * @reg: register to read from
ian@0 188 *
ian@0 189 * Fetch a POS value that was stored at boot time by the kernel
ian@0 190 * when it scanned the MCA space. The register value is returned.
ian@0 191 * Missing or invalid registers report 0.
ian@0 192 */
ian@0 193 unsigned char mca_read_stored_pos(int slot, int reg)
ian@0 194 {
ian@0 195 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 196
ian@0 197 if(!mca_dev)
ian@0 198 return 0;
ian@0 199
ian@0 200 return mca_device_read_stored_pos(mca_dev, reg);
ian@0 201 }
ian@0 202 EXPORT_SYMBOL(mca_read_stored_pos);
ian@0 203
ian@0 204
ian@0 205 /**
ian@0 206 * mca_read_pos - read POS register from card
ian@0 207 * @slot: slot number to read from
ian@0 208 * @reg: register to read from
ian@0 209 *
ian@0 210 * Fetch a POS value directly from the hardware to obtain the
ian@0 211 * current value. This is much slower than mca_read_stored_pos and
ian@0 212 * may not be invoked from interrupt context. It handles the
ian@0 213 * deep magic required for onboard devices transparently.
ian@0 214 */
ian@0 215
ian@0 216 unsigned char mca_read_pos(int slot, int reg)
ian@0 217 {
ian@0 218 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 219
ian@0 220 if(!mca_dev)
ian@0 221 return 0;
ian@0 222
ian@0 223 return mca_device_read_pos(mca_dev, reg);
ian@0 224 }
ian@0 225 EXPORT_SYMBOL(mca_read_pos);
ian@0 226
ian@0 227
ian@0 228 /**
ian@0 229 * mca_write_pos - read POS register from card
ian@0 230 * @slot: slot number to read from
ian@0 231 * @reg: register to read from
ian@0 232 * @byte: byte to write to the POS registers
ian@0 233 *
ian@0 234 * Store a POS value directly from the hardware. You should not
ian@0 235 * normally need to use this function and should have a very good
ian@0 236 * knowledge of MCA bus before you do so. Doing this wrongly can
ian@0 237 * damage the hardware.
ian@0 238 *
ian@0 239 * This function may not be used from interrupt context.
ian@0 240 *
ian@0 241 * Note that this a technically a Bad Thing, as IBM tech stuff says
ian@0 242 * you should only set POS values through their utilities.
ian@0 243 * However, some devices such as the 3c523 recommend that you write
ian@0 244 * back some data to make sure the configuration is consistent.
ian@0 245 * I'd say that IBM is right, but I like my drivers to work.
ian@0 246 *
ian@0 247 * This function can't do checks to see if multiple devices end up
ian@0 248 * with the same resources, so you might see magic smoke if someone
ian@0 249 * screws up.
ian@0 250 */
ian@0 251
ian@0 252 void mca_write_pos(int slot, int reg, unsigned char byte)
ian@0 253 {
ian@0 254 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 255
ian@0 256 if(!mca_dev)
ian@0 257 return;
ian@0 258
ian@0 259 mca_device_write_pos(mca_dev, reg, byte);
ian@0 260 }
ian@0 261 EXPORT_SYMBOL(mca_write_pos);
ian@0 262
ian@0 263 /**
ian@0 264 * mca_set_adapter_name - Set the description of the card
ian@0 265 * @slot: slot to name
ian@0 266 * @name: text string for the namen
ian@0 267 *
ian@0 268 * This function sets the name reported via /proc for this
ian@0 269 * adapter slot. This is for user information only. Setting a
ian@0 270 * name deletes any previous name.
ian@0 271 */
ian@0 272
ian@0 273 void mca_set_adapter_name(int slot, char* name)
ian@0 274 {
ian@0 275 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 276
ian@0 277 if(!mca_dev)
ian@0 278 return;
ian@0 279
ian@0 280 mca_device_set_name(mca_dev, name);
ian@0 281 }
ian@0 282 EXPORT_SYMBOL(mca_set_adapter_name);
ian@0 283
ian@0 284 /**
ian@0 285 * mca_is_adapter_used - check if claimed by driver
ian@0 286 * @slot: slot to check
ian@0 287 *
ian@0 288 * Returns 1 if the slot has been claimed by a driver
ian@0 289 */
ian@0 290
ian@0 291 int mca_is_adapter_used(int slot)
ian@0 292 {
ian@0 293 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 294
ian@0 295 if(!mca_dev)
ian@0 296 return 0;
ian@0 297
ian@0 298 return mca_device_claimed(mca_dev);
ian@0 299 }
ian@0 300 EXPORT_SYMBOL(mca_is_adapter_used);
ian@0 301
ian@0 302 /**
ian@0 303 * mca_mark_as_used - claim an MCA device
ian@0 304 * @slot: slot to claim
ian@0 305 * FIXME: should we make this threadsafe
ian@0 306 *
ian@0 307 * Claim an MCA slot for a device driver. If the
ian@0 308 * slot is already taken the function returns 1,
ian@0 309 * if it is not taken it is claimed and 0 is
ian@0 310 * returned.
ian@0 311 */
ian@0 312
ian@0 313 int mca_mark_as_used(int slot)
ian@0 314 {
ian@0 315 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 316
ian@0 317 if(!mca_dev)
ian@0 318 /* FIXME: this is actually a severe error */
ian@0 319 return 1;
ian@0 320
ian@0 321 if(mca_device_claimed(mca_dev))
ian@0 322 return 1;
ian@0 323
ian@0 324 mca_device_set_claim(mca_dev, 1);
ian@0 325
ian@0 326 return 0;
ian@0 327 }
ian@0 328 EXPORT_SYMBOL(mca_mark_as_used);
ian@0 329
ian@0 330 /**
ian@0 331 * mca_mark_as_unused - release an MCA device
ian@0 332 * @slot: slot to claim
ian@0 333 *
ian@0 334 * Release the slot for other drives to use.
ian@0 335 */
ian@0 336
ian@0 337 void mca_mark_as_unused(int slot)
ian@0 338 {
ian@0 339 struct mca_device *mca_dev = mca_find_device_by_slot(slot);
ian@0 340
ian@0 341 if(!mca_dev)
ian@0 342 return;
ian@0 343
ian@0 344 mca_device_set_claim(mca_dev, 0);
ian@0 345 }
ian@0 346 EXPORT_SYMBOL(mca_mark_as_unused);
ian@0 347