ia64/linux-2.6.18-xen.hg

view drivers/mtd/maps/dilnetpc.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
line source
1 /* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP"
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
16 *
17 * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $
18 *
19 * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
20 * featuring the AMD Elan SC410 processor. There are two variants of this
21 * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash
22 * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs
23 * flash and 16 megs of RAM.
24 * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
25 * and http://www.ssv-embedded.de/ssv/pc104/p170.htm
26 */
28 #include <linux/module.h>
29 #include <linux/types.h>
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/string.h>
34 #include <linux/mtd/mtd.h>
35 #include <linux/mtd/map.h>
36 #include <linux/mtd/partitions.h>
37 #include <linux/mtd/concat.h>
39 #include <asm/io.h>
41 /*
42 ** The DIL/NetPC keeps its BIOS in two distinct flash blocks.
43 ** Destroying any of these blocks transforms the DNPC into
44 ** a paperweight (albeit not a very useful one, considering
45 ** it only weighs a few grams).
46 **
47 ** Therefore, the BIOS blocks must never be erased or written to
48 ** except by people who know exactly what they are doing (e.g.
49 ** to install a BIOS update). These partitions are marked read-only
50 ** by default, but can be made read/write by undefining
51 ** DNPC_BIOS_BLOCKS_WRITEPROTECTED:
52 */
53 #define DNPC_BIOS_BLOCKS_WRITEPROTECTED
55 /*
56 ** The ID string (in ROM) is checked to determine whether we
57 ** are running on a DNP/1486 or ADNP/1486
58 */
59 #define BIOSID_BASE 0x000fe100
61 #define ID_DNPC "DNP1486"
62 #define ID_ADNP "ADNP1486"
64 /*
65 ** Address where the flash should appear in CPU space
66 */
67 #define FLASH_BASE 0x2000000
69 /*
70 ** Chip Setup and Control (CSC) indexed register space
71 */
72 #define CSC_INDEX 0x22
73 #define CSC_DATA 0x23
75 #define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */
76 #define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */
78 #define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */
80 #define CSC_CR 0xd0 /* internal I/O device disable/Echo */
81 /* Z-bus/configuration register */
83 #define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */
86 /*
87 ** PC Card indexed register space:
88 */
90 #define PCC_INDEX 0x3e0
91 #define PCC_DATA 0x3e1
93 #define PCC_AWER_B 0x46 /* Socket B Address Window enable register */
94 #define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */
95 #define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */
96 #define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */
97 #define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */
98 #define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */
99 #define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */
102 /*
103 ** Access to SC4x0's Chip Setup and Control (CSC)
104 ** and PC Card (PCC) indexed registers:
105 */
106 static inline void setcsc(int reg, unsigned char data)
107 {
108 outb(reg, CSC_INDEX);
109 outb(data, CSC_DATA);
110 }
112 static inline unsigned char getcsc(int reg)
113 {
114 outb(reg, CSC_INDEX);
115 return(inb(CSC_DATA));
116 }
118 static inline void setpcc(int reg, unsigned char data)
119 {
120 outb(reg, PCC_INDEX);
121 outb(data, PCC_DATA);
122 }
124 static inline unsigned char getpcc(int reg)
125 {
126 outb(reg, PCC_INDEX);
127 return(inb(PCC_DATA));
128 }
131 /*
132 ************************************************************
133 ** Enable access to DIL/NetPC's flash by mapping it into
134 ** the SC4x0's MMS Window C.
135 ************************************************************
136 */
137 static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size)
138 {
139 unsigned long flash_end = flash_base + flash_size - 1;
141 /*
142 ** enable setup of MMS windows C-F:
143 */
144 /* - enable PC Card indexed register space */
145 setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
146 /* - set PC Card controller to operate in standard mode */
147 setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1);
149 /*
150 ** Program base address and end address of window
151 ** where the flash ROM should appear in CPU address space
152 */
153 setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff);
154 setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f);
155 setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff);
156 setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f);
158 /* program offset of first flash location to appear in this window (0) */
159 setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff);
160 setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f);
162 /* set attributes for MMS window C: non-cacheable, write-enabled */
163 setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11);
165 /* select physical device ROMCS0 (i.e. flash) for MMS Window C */
166 setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03);
168 /* enable memory window 1 */
169 setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02);
171 /* now disable PC Card indexed register space again */
172 setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
173 }
176 /*
177 ************************************************************
178 ** Disable access to DIL/NetPC's flash by mapping it into
179 ** the SC4x0's MMS Window C.
180 ************************************************************
181 */
182 static void dnpc_unmap_flash(void)
183 {
184 /* - enable PC Card indexed register space */
185 setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
187 /* disable memory window 1 */
188 setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02);
190 /* now disable PC Card indexed register space again */
191 setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
192 }
196 /*
197 ************************************************************
198 ** Enable/Disable VPP to write to flash
199 ************************************************************
200 */
202 static DEFINE_SPINLOCK(dnpc_spin);
203 static int vpp_counter = 0;
204 /*
205 ** This is what has to be done for the DNP board ..
206 */
207 static void dnp_set_vpp(struct map_info *not_used, int on)
208 {
209 spin_lock_irq(&dnpc_spin);
211 if (on)
212 {
213 if(++vpp_counter == 1)
214 setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4);
215 }
216 else
217 {
218 if(--vpp_counter == 0)
219 setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4);
220 else
221 BUG_ON(vpp_counter < 0);
222 }
223 spin_unlock_irq(&dnpc_spin);
224 }
226 /*
227 ** .. and this the ADNP version:
228 */
229 static void adnp_set_vpp(struct map_info *not_used, int on)
230 {
231 spin_lock_irq(&dnpc_spin);
233 if (on)
234 {
235 if(++vpp_counter == 1)
236 setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8);
237 }
238 else
239 {
240 if(--vpp_counter == 0)
241 setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8);
242 else
243 BUG_ON(vpp_counter < 0);
244 }
245 spin_unlock_irq(&dnpc_spin);
246 }
250 #define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */
251 #define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */
252 #define WINDOW_ADDR FLASH_BASE
254 static struct map_info dnpc_map = {
255 .name = "ADNP Flash Bank",
256 .size = ADNP_WINDOW_SIZE,
257 .bankwidth = 1,
258 .set_vpp = adnp_set_vpp,
259 .phys = WINDOW_ADDR
260 };
262 /*
263 ** The layout of the flash is somewhat "strange":
264 **
265 ** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data
266 ** 2. 64 KiB (1 block) : System BIOS
267 ** 3. 960 KiB (15 blocks) : User Data (DNP model) or
268 ** 3. 3008 KiB (47 blocks) : User Data (ADNP model)
269 ** 4. 64 KiB (1 block) : System BIOS Entry
270 */
272 static struct mtd_partition partition_info[]=
273 {
274 {
275 .name = "ADNP boot",
276 .offset = 0,
277 .size = 0xf0000,
278 },
279 {
280 .name = "ADNP system BIOS",
281 .offset = MTDPART_OFS_NXTBLK,
282 .size = 0x10000,
283 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
284 .mask_flags = MTD_WRITEABLE,
285 #endif
286 },
287 {
288 .name = "ADNP file system",
289 .offset = MTDPART_OFS_NXTBLK,
290 .size = 0x2f0000,
291 },
292 {
293 .name = "ADNP system BIOS entry",
294 .offset = MTDPART_OFS_NXTBLK,
295 .size = MTDPART_SIZ_FULL,
296 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
297 .mask_flags = MTD_WRITEABLE,
298 #endif
299 },
300 };
302 #define NUM_PARTITIONS ARRAY_SIZE(partition_info)
304 static struct mtd_info *mymtd;
305 static struct mtd_info *lowlvl_parts[NUM_PARTITIONS];
306 static struct mtd_info *merged_mtd;
308 /*
309 ** "Highlevel" partition info:
310 **
311 ** Using the MTD concat layer, we can re-arrange partitions to our
312 ** liking: we construct a virtual MTD device by concatenating the
313 ** partitions, specifying the sequence such that the boot block
314 ** is immediately followed by the filesystem block (i.e. the stupid
315 ** system BIOS block is mapped to a different place). When re-partitioning
316 ** this concatenated MTD device, we can set the boot block size to
317 ** an arbitrary (though erase block aligned) value i.e. not one that
318 ** is dictated by the flash's physical layout. We can thus set the
319 ** boot block to be e.g. 64 KB (which is fully sufficient if we want
320 ** to boot an etherboot image) or to -say- 1.5 MB if we want to boot
321 ** a large kernel image. In all cases, the remainder of the flash
322 ** is available as file system space.
323 */
325 static struct mtd_partition higlvl_partition_info[]=
326 {
327 {
328 .name = "ADNP boot block",
329 .offset = 0,
330 .size = CONFIG_MTD_DILNETPC_BOOTSIZE,
331 },
332 {
333 .name = "ADNP file system space",
334 .offset = MTDPART_OFS_NXTBLK,
335 .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
336 },
337 {
338 .name = "ADNP system BIOS + BIOS Entry",
339 .offset = MTDPART_OFS_NXTBLK,
340 .size = MTDPART_SIZ_FULL,
341 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
342 .mask_flags = MTD_WRITEABLE,
343 #endif
344 },
345 };
347 #define NUM_HIGHLVL_PARTITIONS ARRAY_SIZE(higlvl_partition_info)
350 static int dnp_adnp_probe(void)
351 {
352 char *biosid, rc = -1;
354 biosid = (char*)ioremap(BIOSID_BASE, 16);
355 if(biosid)
356 {
357 if(!strcmp(biosid, ID_DNPC))
358 rc = 1; /* this is a DNPC */
359 else if(!strcmp(biosid, ID_ADNP))
360 rc = 0; /* this is a ADNPC */
361 }
362 iounmap((void *)biosid);
363 return(rc);
364 }
367 static int __init init_dnpc(void)
368 {
369 int is_dnp;
371 /*
372 ** determine hardware (DNP/ADNP/invalid)
373 */
374 if((is_dnp = dnp_adnp_probe()) < 0)
375 return -ENXIO;
377 /*
378 ** Things are set up for ADNP by default
379 ** -> modify all that needs to be different for DNP
380 */
381 if(is_dnp)
382 { /*
383 ** Adjust window size, select correct set_vpp function.
384 ** The partitioning scheme is identical on both DNP
385 ** and ADNP except for the size of the third partition.
386 */
387 int i;
388 dnpc_map.size = DNP_WINDOW_SIZE;
389 dnpc_map.set_vpp = dnp_set_vpp;
390 partition_info[2].size = 0xf0000;
392 /*
393 ** increment all string pointers so the leading 'A' gets skipped,
394 ** thus turning all occurrences of "ADNP ..." into "DNP ..."
395 */
396 ++dnpc_map.name;
397 for(i = 0; i < NUM_PARTITIONS; i++)
398 ++partition_info[i].name;
399 higlvl_partition_info[1].size = DNP_WINDOW_SIZE -
400 CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000;
401 for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++)
402 ++higlvl_partition_info[i].name;
403 }
405 printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n",
406 is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
408 dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size);
410 dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
412 if (!dnpc_map.virt) {
413 printk("Failed to ioremap_nocache\n");
414 return -EIO;
415 }
416 simple_map_init(&dnpc_map);
418 printk("FLASH virtual address: 0x%p\n", dnpc_map.virt);
420 mymtd = do_map_probe("jedec_probe", &dnpc_map);
422 if (!mymtd)
423 mymtd = do_map_probe("cfi_probe", &dnpc_map);
425 /*
426 ** If flash probes fail, try to make flashes accessible
427 ** at least as ROM. Ajust erasesize in this case since
428 ** the default one (128M) will break our partitioning
429 */
430 if (!mymtd)
431 if((mymtd = do_map_probe("map_rom", &dnpc_map)))
432 mymtd->erasesize = 0x10000;
434 if (!mymtd) {
435 iounmap(dnpc_map.virt);
436 return -ENXIO;
437 }
439 mymtd->owner = THIS_MODULE;
441 /*
442 ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
443 ** -> add_mtd_partitions() will _not_ register MTD devices for
444 ** the partitions, but will instead store pointers to the MTD
445 ** objects it creates into our lowlvl_parts[] array.
446 ** NOTE: we arrange the pointers such that the sequence of the
447 ** partitions gets re-arranged: partition #2 follows
448 ** partition #0.
449 */
450 partition_info[0].mtdp = &lowlvl_parts[0];
451 partition_info[1].mtdp = &lowlvl_parts[2];
452 partition_info[2].mtdp = &lowlvl_parts[1];
453 partition_info[3].mtdp = &lowlvl_parts[3];
455 add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
457 /*
458 ** now create a virtual MTD device by concatenating the for partitions
459 ** (in the sequence given by the lowlvl_parts[] array.
460 */
461 merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated");
462 if(merged_mtd)
463 { /*
464 ** now partition the new device the way we want it. This time,
465 ** we do not supply mtd pointers in higlvl_partition_info, so
466 ** add_mtd_partitions() will register the devices.
467 */
468 add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS);
469 }
471 return 0;
472 }
474 static void __exit cleanup_dnpc(void)
475 {
476 if(merged_mtd) {
477 del_mtd_partitions(merged_mtd);
478 mtd_concat_destroy(merged_mtd);
479 }
481 if (mymtd) {
482 del_mtd_partitions(mymtd);
483 map_destroy(mymtd);
484 }
485 if (dnpc_map.virt) {
486 iounmap(dnpc_map.virt);
487 dnpc_unmap_flash();
488 dnpc_map.virt = NULL;
489 }
490 }
492 module_init(init_dnpc);
493 module_exit(cleanup_dnpc);
495 MODULE_LICENSE("GPL");
496 MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
497 MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP");