ia64/linux-2.6.18-xen.hg

view drivers/atm/idt77105.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 /* drivers/atm/idt77105.c - IDT77105 (PHY) driver */
3 /* Written 1999 by Greg Banks, NEC Australia <gnb@linuxfan.com>. Based on suni.c */
6 #include <linux/module.h>
7 #include <linux/sched.h>
8 #include <linux/kernel.h>
9 #include <linux/mm.h>
10 #include <linux/errno.h>
11 #include <linux/atmdev.h>
12 #include <linux/sonet.h>
13 #include <linux/delay.h>
14 #include <linux/timer.h>
15 #include <linux/init.h>
16 #include <linux/capability.h>
17 #include <linux/atm_idt77105.h>
18 #include <linux/spinlock.h>
19 #include <asm/system.h>
20 #include <asm/param.h>
21 #include <asm/uaccess.h>
23 #include "idt77105.h"
25 #undef GENERAL_DEBUG
27 #ifdef GENERAL_DEBUG
28 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
29 #else
30 #define DPRINTK(format,args...)
31 #endif
34 struct idt77105_priv {
35 struct idt77105_stats stats; /* link diagnostics */
36 struct atm_dev *dev; /* device back-pointer */
37 struct idt77105_priv *next;
38 int loop_mode;
39 unsigned char old_mcr; /* storage of MCR reg while signal lost */
40 };
42 static DEFINE_SPINLOCK(idt77105_priv_lock);
44 #define PRIV(dev) ((struct idt77105_priv *) dev->phy_data)
46 #define PUT(val,reg) dev->ops->phy_put(dev,val,IDT77105_##reg)
47 #define GET(reg) dev->ops->phy_get(dev,IDT77105_##reg)
49 static void idt77105_stats_timer_func(unsigned long);
50 static void idt77105_restart_timer_func(unsigned long);
53 static DEFINE_TIMER(stats_timer, idt77105_stats_timer_func, 0, 0);
54 static DEFINE_TIMER(restart_timer, idt77105_restart_timer_func, 0, 0);
55 static int start_timer = 1;
56 static struct idt77105_priv *idt77105_all = NULL;
58 /*
59 * Retrieve the value of one of the IDT77105's counters.
60 * `counter' is one of the IDT77105_CTRSEL_* constants.
61 */
62 static u16 get_counter(struct atm_dev *dev, int counter)
63 {
64 u16 val;
66 /* write the counter bit into PHY register 6 */
67 PUT(counter, CTRSEL);
68 /* read the low 8 bits from register 4 */
69 val = GET(CTRLO);
70 /* read the high 8 bits from register 5 */
71 val |= GET(CTRHI)<<8;
73 return val;
74 }
76 /*
77 * Timer function called every second to gather statistics
78 * from the 77105. This is done because the h/w registers
79 * will overflow if not read at least once per second. The
80 * kernel's stats are much higher precision. Also, having
81 * a separate copy of the stats allows implementation of
82 * an ioctl which gathers the stats *without* zero'ing them.
83 */
84 static void idt77105_stats_timer_func(unsigned long dummy)
85 {
86 struct idt77105_priv *walk;
87 struct atm_dev *dev;
88 struct idt77105_stats *stats;
90 DPRINTK("IDT77105 gathering statistics\n");
91 for (walk = idt77105_all; walk; walk = walk->next) {
92 dev = walk->dev;
94 stats = &walk->stats;
95 stats->symbol_errors += get_counter(dev, IDT77105_CTRSEL_SEC);
96 stats->tx_cells += get_counter(dev, IDT77105_CTRSEL_TCC);
97 stats->rx_cells += get_counter(dev, IDT77105_CTRSEL_RCC);
98 stats->rx_hec_errors += get_counter(dev, IDT77105_CTRSEL_RHEC);
99 }
100 if (!start_timer) mod_timer(&stats_timer,jiffies+IDT77105_STATS_TIMER_PERIOD);
101 }
104 /*
105 * A separate timer func which handles restarting PHY chips which
106 * have had the cable re-inserted after being pulled out. This is
107 * done by polling the Good Signal Bit in the Interrupt Status
108 * register every 5 seconds. The other technique (checking Good
109 * Signal Bit in the interrupt handler) cannot be used because PHY
110 * interrupts need to be disabled when the cable is pulled out
111 * to avoid lots of spurious cell error interrupts.
112 */
113 static void idt77105_restart_timer_func(unsigned long dummy)
114 {
115 struct idt77105_priv *walk;
116 struct atm_dev *dev;
117 unsigned char istat;
119 DPRINTK("IDT77105 checking for cable re-insertion\n");
120 for (walk = idt77105_all; walk; walk = walk->next) {
121 dev = walk->dev;
123 if (dev->signal != ATM_PHY_SIG_LOST)
124 continue;
126 istat = GET(ISTAT); /* side effect: clears all interrupt status bits */
127 if (istat & IDT77105_ISTAT_GOODSIG) {
128 /* Found signal again */
129 dev->signal = ATM_PHY_SIG_FOUND;
130 printk(KERN_NOTICE "%s(itf %d): signal detected again\n",
131 dev->type,dev->number);
132 /* flush the receive FIFO */
133 PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG);
134 /* re-enable interrupts */
135 PUT( walk->old_mcr ,MCR);
136 }
137 }
138 if (!start_timer) mod_timer(&restart_timer,jiffies+IDT77105_RESTART_TIMER_PERIOD);
139 }
142 static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int zero)
143 {
144 unsigned long flags;
145 struct idt77105_stats stats;
147 spin_lock_irqsave(&idt77105_priv_lock, flags);
148 memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
149 if (zero)
150 memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
151 spin_unlock_irqrestore(&idt77105_priv_lock, flags);
152 if (arg == NULL)
153 return 0;
154 return copy_to_user(arg, &PRIV(dev)->stats,
155 sizeof(struct idt77105_stats)) ? -EFAULT : 0;
156 }
159 static int set_loopback(struct atm_dev *dev,int mode)
160 {
161 int diag;
163 diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK;
164 switch (mode) {
165 case ATM_LM_NONE:
166 break;
167 case ATM_LM_LOC_ATM:
168 diag |= IDT77105_DIAG_LC_PHY_LOOPBACK;
169 break;
170 case ATM_LM_RMT_ATM:
171 diag |= IDT77105_DIAG_LC_LINE_LOOPBACK;
172 break;
173 default:
174 return -EINVAL;
175 }
176 PUT(diag,DIAG);
177 printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type,
178 dev->number,
179 (mode == ATM_LM_NONE ? "NONE" :
180 (mode == ATM_LM_LOC_ATM ? "DIAG (local)" :
181 (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" :
182 "unknown")))
183 );
184 PRIV(dev)->loop_mode = mode;
185 return 0;
186 }
189 static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
190 {
191 printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number);
192 switch (cmd) {
193 case IDT77105_GETSTATZ:
194 if (!capable(CAP_NET_ADMIN)) return -EPERM;
195 /* fall through */
196 case IDT77105_GETSTAT:
197 return fetch_stats(dev, arg, cmd == IDT77105_GETSTATZ);
198 case ATM_SETLOOP:
199 return set_loopback(dev,(int)(unsigned long) arg);
200 case ATM_GETLOOP:
201 return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ?
202 -EFAULT : 0;
203 case ATM_QUERYLOOP:
204 return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM,
205 (int __user *) arg) ? -EFAULT : 0;
206 default:
207 return -ENOIOCTLCMD;
208 }
209 }
213 static void idt77105_int(struct atm_dev *dev)
214 {
215 unsigned char istat;
217 istat = GET(ISTAT); /* side effect: clears all interrupt status bits */
219 DPRINTK("IDT77105 generated an interrupt, istat=%02x\n", (unsigned)istat);
221 if (istat & IDT77105_ISTAT_RSCC) {
222 /* Rx Signal Condition Change - line went up or down */
223 if (istat & IDT77105_ISTAT_GOODSIG) { /* signal detected again */
224 /* This should not happen (restart timer does it) but JIC */
225 dev->signal = ATM_PHY_SIG_FOUND;
226 } else { /* signal lost */
227 /*
228 * Disable interrupts and stop all transmission and
229 * reception - the restart timer will restore these.
230 */
231 PRIV(dev)->old_mcr = GET(MCR);
232 PUT(
233 (PRIV(dev)->old_mcr|
234 IDT77105_MCR_DREC|
235 IDT77105_MCR_DRIC|
236 IDT77105_MCR_HALTTX
237 ) & ~IDT77105_MCR_EIP, MCR);
238 dev->signal = ATM_PHY_SIG_LOST;
239 printk(KERN_NOTICE "%s(itf %d): signal lost\n",
240 dev->type,dev->number);
241 }
242 }
244 if (istat & IDT77105_ISTAT_RFO) {
245 /* Rx FIFO Overrun -- perform a FIFO flush */
246 PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG);
247 printk(KERN_NOTICE "%s(itf %d): receive FIFO overrun\n",
248 dev->type,dev->number);
249 }
250 #ifdef GENERAL_DEBUG
251 if (istat & (IDT77105_ISTAT_HECERR | IDT77105_ISTAT_SCR |
252 IDT77105_ISTAT_RSE)) {
253 /* normally don't care - just report in stats */
254 printk(KERN_NOTICE "%s(itf %d): received cell with error\n",
255 dev->type,dev->number);
256 }
257 #endif
258 }
261 static int idt77105_start(struct atm_dev *dev)
262 {
263 unsigned long flags;
265 if (!(dev->dev_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
266 return -ENOMEM;
267 PRIV(dev)->dev = dev;
268 spin_lock_irqsave(&idt77105_priv_lock, flags);
269 PRIV(dev)->next = idt77105_all;
270 idt77105_all = PRIV(dev);
271 spin_unlock_irqrestore(&idt77105_priv_lock, flags);
272 memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
274 /* initialise dev->signal from Good Signal Bit */
275 dev->signal = GET(ISTAT) & IDT77105_ISTAT_GOODSIG ? ATM_PHY_SIG_FOUND :
276 ATM_PHY_SIG_LOST;
277 if (dev->signal == ATM_PHY_SIG_LOST)
278 printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
279 dev->number);
281 /* initialise loop mode from hardware */
282 switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) {
283 case IDT77105_DIAG_LC_NORMAL:
284 PRIV(dev)->loop_mode = ATM_LM_NONE;
285 break;
286 case IDT77105_DIAG_LC_PHY_LOOPBACK:
287 PRIV(dev)->loop_mode = ATM_LM_LOC_ATM;
288 break;
289 case IDT77105_DIAG_LC_LINE_LOOPBACK:
290 PRIV(dev)->loop_mode = ATM_LM_RMT_ATM;
291 break;
292 }
294 /* enable interrupts, e.g. on loss of signal */
295 PRIV(dev)->old_mcr = GET(MCR);
296 if (dev->signal == ATM_PHY_SIG_FOUND) {
297 PRIV(dev)->old_mcr |= IDT77105_MCR_EIP;
298 PUT(PRIV(dev)->old_mcr, MCR);
299 }
302 idt77105_stats_timer_func(0); /* clear 77105 counters */
303 (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
305 spin_lock_irqsave(&idt77105_priv_lock, flags);
306 if (start_timer) {
307 start_timer = 0;
309 init_timer(&stats_timer);
310 stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
311 stats_timer.function = idt77105_stats_timer_func;
312 add_timer(&stats_timer);
314 init_timer(&restart_timer);
315 restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD;
316 restart_timer.function = idt77105_restart_timer_func;
317 add_timer(&restart_timer);
318 }
319 spin_unlock_irqrestore(&idt77105_priv_lock, flags);
320 return 0;
321 }
324 static int idt77105_stop(struct atm_dev *dev)
325 {
326 struct idt77105_priv *walk, *prev;
328 DPRINTK("%s(itf %d): stopping IDT77105\n",dev->type,dev->number);
330 /* disable interrupts */
331 PUT( GET(MCR) & ~IDT77105_MCR_EIP, MCR );
333 /* detach private struct from atm_dev & free */
334 for (prev = NULL, walk = idt77105_all ;
335 walk != NULL;
336 prev = walk, walk = walk->next) {
337 if (walk->dev == dev) {
338 if (prev != NULL)
339 prev->next = walk->next;
340 else
341 idt77105_all = walk->next;
342 dev->phy = NULL;
343 dev->dev_data = NULL;
344 kfree(walk);
345 break;
346 }
347 }
349 return 0;
350 }
353 static const struct atmphy_ops idt77105_ops = {
354 .start = idt77105_start,
355 .ioctl = idt77105_ioctl,
356 .interrupt = idt77105_int,
357 .stop = idt77105_stop,
358 };
361 int __devinit idt77105_init(struct atm_dev *dev)
362 {
363 dev->phy = &idt77105_ops;
364 return 0;
365 }
367 EXPORT_SYMBOL(idt77105_init);
369 static void __exit idt77105_exit(void)
370 {
371 /* turn off timers */
372 del_timer(&stats_timer);
373 del_timer(&restart_timer);
374 }
376 module_exit(idt77105_exit);
378 MODULE_LICENSE("GPL");