ia64/linux-2.6.18-xen.hg

view drivers/atm/uPD98402.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/uPD98402.c - NEC uPD98402 (PHY) declarations */
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/module.h>
7 #include <linux/sched.h> /* for jiffies */
8 #include <linux/mm.h>
9 #include <linux/errno.h>
10 #include <linux/atmdev.h>
11 #include <linux/sonet.h>
12 #include <linux/init.h>
13 #include <asm/uaccess.h>
14 #include <asm/atomic.h>
16 #include "uPD98402.h"
19 #if 0
20 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
21 #else
22 #define DPRINTK(format,args...)
23 #endif
26 struct uPD98402_priv {
27 struct k_sonet_stats sonet_stats;/* link diagnostics */
28 unsigned char framing; /* SONET/SDH framing */
29 int loop_mode; /* loopback mode */
30 spinlock_t lock;
31 };
34 #define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data)
36 #define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg)
37 #define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg)
40 static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero)
41 {
42 struct sonet_stats tmp;
43 int error = 0;
45 atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
46 sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
47 if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
48 if (zero && !error) {
49 /* unused fields are reported as -1, but we must not "adjust"
50 them */
51 tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
52 sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
53 }
54 return error ? -EFAULT : 0;
55 }
58 static int set_framing(struct atm_dev *dev,unsigned char framing)
59 {
60 static const unsigned char sonet[] = { 1,2,3,0 };
61 static const unsigned char sdh[] = { 1,0,0,2 };
62 const char *set;
63 unsigned long flags;
65 switch (framing) {
66 case SONET_FRAME_SONET:
67 set = sonet;
68 break;
69 case SONET_FRAME_SDH:
70 set = sdh;
71 break;
72 default:
73 return -EINVAL;
74 }
75 spin_lock_irqsave(&PRIV(dev)->lock, flags);
76 PUT(set[0],C11T);
77 PUT(set[1],C12T);
78 PUT(set[2],C13T);
79 PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] <<
80 uPD98402_MDR_SS_SHIFT),MDR);
81 spin_unlock_irqrestore(&PRIV(dev)->lock, flags);
82 return 0;
83 }
86 static int get_sense(struct atm_dev *dev,u8 __user *arg)
87 {
88 unsigned long flags;
89 unsigned char s[3];
91 spin_lock_irqsave(&PRIV(dev)->lock, flags);
92 s[0] = GET(C11R);
93 s[1] = GET(C12R);
94 s[2] = GET(C13R);
95 spin_unlock_irqrestore(&PRIV(dev)->lock, flags);
96 return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
97 put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
98 put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
99 }
102 static int set_loopback(struct atm_dev *dev,int mode)
103 {
104 unsigned char mode_reg;
106 mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
107 uPD98402_MDR_RPLP);
108 switch (__ATM_LM_XTLOC(mode)) {
109 case __ATM_LM_NONE:
110 break;
111 case __ATM_LM_PHY:
112 mode_reg |= uPD98402_MDR_TPLP;
113 break;
114 case __ATM_LM_ATM:
115 mode_reg |= uPD98402_MDR_ALP;
116 break;
117 default:
118 return -EINVAL;
119 }
120 switch (__ATM_LM_XTRMT(mode)) {
121 case __ATM_LM_NONE:
122 break;
123 case __ATM_LM_PHY:
124 mode_reg |= uPD98402_MDR_RPLP;
125 break;
126 default:
127 return -EINVAL;
128 }
129 PUT(mode_reg,MDR);
130 PRIV(dev)->loop_mode = mode;
131 return 0;
132 }
135 static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
136 {
137 switch (cmd) {
139 case SONET_GETSTATZ:
140 case SONET_GETSTAT:
141 return fetch_stats(dev,arg, cmd == SONET_GETSTATZ);
142 case SONET_SETFRAMING:
143 return set_framing(dev, (int)(unsigned long)arg);
144 case SONET_GETFRAMING:
145 return put_user(PRIV(dev)->framing,(int __user *)arg) ?
146 -EFAULT : 0;
147 case SONET_GETFRSENSE:
148 return get_sense(dev,arg);
149 case ATM_SETLOOP:
150 return set_loopback(dev, (int)(unsigned long)arg);
151 case ATM_GETLOOP:
152 return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ?
153 -EFAULT : 0;
154 case ATM_QUERYLOOP:
155 return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
156 ATM_LM_RMT_PHY,(int __user *)arg) ? -EFAULT : 0;
157 default:
158 return -ENOIOCTLCMD;
159 }
160 }
163 #define ADD_LIMITED(s,v) \
164 { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \
165 if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \
166 atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
169 static void stat_event(struct atm_dev *dev)
170 {
171 unsigned char events;
173 events = GET(PCR);
174 if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
175 if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
176 if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
177 if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
178 if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
179 }
182 #undef ADD_LIMITED
185 static void uPD98402_int(struct atm_dev *dev)
186 {
187 static unsigned long silence = 0;
188 unsigned char reason;
190 while ((reason = GET(PICR))) {
191 if (reason & uPD98402_INT_LOS)
192 printk(KERN_NOTICE "%s(itf %d): signal lost\n",
193 dev->type,dev->number);
194 if (reason & uPD98402_INT_PFM) stat_event(dev);
195 if (reason & uPD98402_INT_PCO) {
196 (void) GET(PCOCR); /* clear interrupt cause */
197 atomic_add(GET(HECCT),
198 &PRIV(dev)->sonet_stats.uncorr_hcs);
199 }
200 if ((reason & uPD98402_INT_RFO) &&
201 (time_after(jiffies, silence) || silence == 0)) {
202 printk(KERN_WARNING "%s(itf %d): uPD98402 receive "
203 "FIFO overflow\n",dev->type,dev->number);
204 silence = (jiffies+HZ/2)|1;
205 }
206 }
207 }
210 static int uPD98402_start(struct atm_dev *dev)
211 {
212 DPRINTK("phy_start\n");
213 if (!(dev->dev_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
214 return -ENOMEM;
215 spin_lock_init(&PRIV(dev)->lock);
216 memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
217 (void) GET(PCR); /* clear performance events */
218 PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
219 (void) GET(PCOCR); /* clear overflows */
220 PUT(~uPD98402_PCO_HECC,PCOMR);
221 (void) GET(PICR); /* clear interrupts */
222 PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
223 uPD98402_INT_LOS),PIMR); /* enable them */
224 (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
225 atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
226 atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
227 atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
228 return 0;
229 }
232 static int uPD98402_stop(struct atm_dev *dev)
233 {
234 /* let SAR driver worry about stopping interrupts */
235 kfree(PRIV(dev));
236 return 0;
237 }
240 static const struct atmphy_ops uPD98402_ops = {
241 .start = uPD98402_start,
242 .ioctl = uPD98402_ioctl,
243 .interrupt = uPD98402_int,
244 .stop = uPD98402_stop,
245 };
248 int uPD98402_init(struct atm_dev *dev)
249 {
250 DPRINTK("phy_init\n");
251 dev->phy = &uPD98402_ops;
252 return 0;
253 }
256 MODULE_LICENSE("GPL");
258 EXPORT_SYMBOL(uPD98402_init);
260 static __init int uPD98402_module_init(void)
261 {
262 return 0;
263 }
264 module_init(uPD98402_module_init);
265 /* module_exit not defined so not unloadable */