ia64/linux-2.6.18-xen.hg

view arch/sparc64/kernel/us3_cpufreq.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 /* us3_cpufreq.c: UltraSPARC-III cpu frequency support
2 *
3 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
4 *
5 * Many thanks to Dominik Brodowski for fixing up the cpufreq
6 * infrastructure in order to make this driver easier to implement.
7 */
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/sched.h>
12 #include <linux/smp.h>
13 #include <linux/cpufreq.h>
14 #include <linux/threads.h>
15 #include <linux/slab.h>
16 #include <linux/init.h>
18 #include <asm/head.h>
19 #include <asm/timer.h>
21 static struct cpufreq_driver *cpufreq_us3_driver;
23 struct us3_freq_percpu_info {
24 struct cpufreq_frequency_table table[4];
25 };
27 /* Indexed by cpu number. */
28 static struct us3_freq_percpu_info *us3_freq_table;
30 /* UltraSPARC-III has three dividers: 1, 2, and 32. These are controlled
31 * in the Safari config register.
32 */
33 #define SAFARI_CFG_DIV_1 0x0000000000000000UL
34 #define SAFARI_CFG_DIV_2 0x0000000040000000UL
35 #define SAFARI_CFG_DIV_32 0x0000000080000000UL
36 #define SAFARI_CFG_DIV_MASK 0x00000000C0000000UL
38 static unsigned long read_safari_cfg(void)
39 {
40 unsigned long ret;
42 __asm__ __volatile__("ldxa [%%g0] %1, %0"
43 : "=&r" (ret)
44 : "i" (ASI_SAFARI_CONFIG));
45 return ret;
46 }
48 static void write_safari_cfg(unsigned long val)
49 {
50 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
51 "membar #Sync"
52 : /* no outputs */
53 : "r" (val), "i" (ASI_SAFARI_CONFIG)
54 : "memory");
55 }
57 static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
58 {
59 unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
60 unsigned long ret;
62 switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
63 case SAFARI_CFG_DIV_1:
64 ret = clock_tick / 1;
65 break;
66 case SAFARI_CFG_DIV_2:
67 ret = clock_tick / 2;
68 break;
69 case SAFARI_CFG_DIV_32:
70 ret = clock_tick / 32;
71 break;
72 default:
73 BUG();
74 };
76 return ret;
77 }
79 static unsigned int us3_freq_get(unsigned int cpu)
80 {
81 cpumask_t cpus_allowed;
82 unsigned long reg;
83 unsigned int ret;
85 if (!cpu_online(cpu))
86 return 0;
88 cpus_allowed = current->cpus_allowed;
89 set_cpus_allowed(current, cpumask_of_cpu(cpu));
91 reg = read_safari_cfg();
92 ret = get_current_freq(cpu, reg);
94 set_cpus_allowed(current, cpus_allowed);
96 return ret;
97 }
99 static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
100 {
101 unsigned long new_bits, new_freq, reg;
102 cpumask_t cpus_allowed;
103 struct cpufreq_freqs freqs;
105 if (!cpu_online(cpu))
106 return;
108 cpus_allowed = current->cpus_allowed;
109 set_cpus_allowed(current, cpumask_of_cpu(cpu));
111 new_freq = sparc64_get_clock_tick(cpu) / 1000;
112 switch (index) {
113 case 0:
114 new_bits = SAFARI_CFG_DIV_1;
115 new_freq /= 1;
116 break;
117 case 1:
118 new_bits = SAFARI_CFG_DIV_2;
119 new_freq /= 2;
120 break;
121 case 2:
122 new_bits = SAFARI_CFG_DIV_32;
123 new_freq /= 32;
124 break;
126 default:
127 BUG();
128 };
130 reg = read_safari_cfg();
132 freqs.old = get_current_freq(cpu, reg);
133 freqs.new = new_freq;
134 freqs.cpu = cpu;
135 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
137 reg &= ~SAFARI_CFG_DIV_MASK;
138 reg |= new_bits;
139 write_safari_cfg(reg);
141 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
143 set_cpus_allowed(current, cpus_allowed);
144 }
146 static int us3_freq_target(struct cpufreq_policy *policy,
147 unsigned int target_freq,
148 unsigned int relation)
149 {
150 unsigned int new_index = 0;
152 if (cpufreq_frequency_table_target(policy,
153 &us3_freq_table[policy->cpu].table[0],
154 target_freq,
155 relation,
156 &new_index))
157 return -EINVAL;
159 us3_set_cpu_divider_index(policy->cpu, new_index);
161 return 0;
162 }
164 static int us3_freq_verify(struct cpufreq_policy *policy)
165 {
166 return cpufreq_frequency_table_verify(policy,
167 &us3_freq_table[policy->cpu].table[0]);
168 }
170 static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
171 {
172 unsigned int cpu = policy->cpu;
173 unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
174 struct cpufreq_frequency_table *table =
175 &us3_freq_table[cpu].table[0];
177 table[0].index = 0;
178 table[0].frequency = clock_tick / 1;
179 table[1].index = 1;
180 table[1].frequency = clock_tick / 2;
181 table[2].index = 2;
182 table[2].frequency = clock_tick / 32;
183 table[3].index = 0;
184 table[3].frequency = CPUFREQ_TABLE_END;
186 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
187 policy->cpuinfo.transition_latency = 0;
188 policy->cur = clock_tick;
190 return cpufreq_frequency_table_cpuinfo(policy, table);
191 }
193 static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
194 {
195 if (cpufreq_us3_driver)
196 us3_set_cpu_divider_index(policy->cpu, 0);
198 return 0;
199 }
201 static int __init us3_freq_init(void)
202 {
203 unsigned long manuf, impl, ver;
204 int ret;
206 if (tlb_type != cheetah && tlb_type != cheetah_plus)
207 return -ENODEV;
209 __asm__("rdpr %%ver, %0" : "=r" (ver));
210 manuf = ((ver >> 48) & 0xffff);
211 impl = ((ver >> 32) & 0xffff);
213 if (manuf == CHEETAH_MANUF &&
214 (impl == CHEETAH_IMPL ||
215 impl == CHEETAH_PLUS_IMPL ||
216 impl == JAGUAR_IMPL ||
217 impl == PANTHER_IMPL)) {
218 struct cpufreq_driver *driver;
220 ret = -ENOMEM;
221 driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
222 if (!driver)
223 goto err_out;
225 us3_freq_table = kzalloc(
226 (NR_CPUS * sizeof(struct us3_freq_percpu_info)),
227 GFP_KERNEL);
228 if (!us3_freq_table)
229 goto err_out;
231 driver->init = us3_freq_cpu_init;
232 driver->verify = us3_freq_verify;
233 driver->target = us3_freq_target;
234 driver->get = us3_freq_get;
235 driver->exit = us3_freq_cpu_exit;
236 driver->owner = THIS_MODULE,
237 strcpy(driver->name, "UltraSPARC-III");
239 cpufreq_us3_driver = driver;
240 ret = cpufreq_register_driver(driver);
241 if (ret)
242 goto err_out;
244 return 0;
246 err_out:
247 if (driver) {
248 kfree(driver);
249 cpufreq_us3_driver = NULL;
250 }
251 kfree(us3_freq_table);
252 us3_freq_table = NULL;
253 return ret;
254 }
256 return -ENODEV;
257 }
259 static void __exit us3_freq_exit(void)
260 {
261 if (cpufreq_us3_driver) {
262 cpufreq_unregister_driver(cpufreq_us3_driver);
263 kfree(cpufreq_us3_driver);
264 cpufreq_us3_driver = NULL;
265 kfree(us3_freq_table);
266 us3_freq_table = NULL;
267 }
268 }
270 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
271 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
272 MODULE_LICENSE("GPL");
274 module_init(us3_freq_init);
275 module_exit(us3_freq_exit);