ia64/linux-2.6.18-xen.hg

view drivers/atm/suni.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/suni.c - PMC PM5346 SUNI (PHY) driver */
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/module.h>
7 #include <linux/jiffies.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_suni.h>
18 #include <asm/system.h>
19 #include <asm/param.h>
20 #include <asm/uaccess.h>
21 #include <asm/atomic.h>
23 #include "suni.h"
26 #if 0
27 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
28 #else
29 #define DPRINTK(format,args...)
30 #endif
33 struct suni_priv {
34 struct k_sonet_stats sonet_stats; /* link diagnostics */
35 int loop_mode; /* loopback mode */
36 struct atm_dev *dev; /* device back-pointer */
37 struct suni_priv *next; /* next SUNI */
38 };
41 #define PRIV(dev) ((struct suni_priv *) dev->phy_data)
43 #define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg)
44 #define GET(reg) dev->ops->phy_get(dev,SUNI_##reg)
45 #define REG_CHANGE(mask,shift,value,reg) \
46 PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg)
49 static struct timer_list poll_timer;
50 static struct suni_priv *sunis = NULL;
51 static DEFINE_SPINLOCK(sunis_lock);
54 #define ADD_LIMITED(s,v) \
55 atomic_add((v),&stats->s); \
56 if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);
59 static void suni_hz(unsigned long from_timer)
60 {
61 struct suni_priv *walk;
62 struct atm_dev *dev;
63 struct k_sonet_stats *stats;
65 for (walk = sunis; walk; walk = walk->next) {
66 dev = walk->dev;
67 stats = &walk->sonet_stats;
68 PUT(0,MRI); /* latch counters */
69 udelay(1);
70 ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
71 ((GET(RSOP_SBM) & 0xff) << 8));
72 ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
73 ((GET(RLOP_LB) & 0xff) << 8) |
74 ((GET(RLOP_LBM) & 0xf) << 16));
75 ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
76 ((GET(RPOP_PBM) & 0xff) << 8));
77 ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
78 ((GET(RLOP_LF) & 0xff) << 8) |
79 ((GET(RLOP_LFM) & 0xf) << 16));
80 ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
81 ((GET(RPOP_PFM) & 0xff) << 8));
82 ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
83 ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
84 ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
85 ((GET(RACP_RCC) & 0xff) << 8) |
86 ((GET(RACP_RCCM) & 7) << 16));
87 ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
88 ((GET(TACP_TCC) & 0xff) << 8) |
89 ((GET(TACP_TCCM) & 7) << 16));
90 }
91 if (from_timer) mod_timer(&poll_timer,jiffies+HZ);
92 }
95 #undef ADD_LIMITED
98 static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero)
99 {
100 struct sonet_stats tmp;
101 int error = 0;
103 sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
104 if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
105 if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
106 return error ? -EFAULT : 0;
107 }
110 #define HANDLE_FLAG(flag,reg,bit) \
111 if (todo & flag) { \
112 if (set) PUT(GET(reg) | bit,reg); \
113 else PUT(GET(reg) & ~bit,reg); \
114 todo &= ~flag; \
115 }
118 static int change_diag(struct atm_dev *dev,void __user *arg,int set)
119 {
120 int todo;
122 if (get_user(todo,(int __user *)arg)) return -EFAULT;
123 HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8);
124 HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP);
125 HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3);
126 HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF);
127 HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS);
128 HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS);
129 HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS);
130 HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS);
131 return put_user(todo,(int __user *)arg) ? -EFAULT : 0;
132 }
135 #undef HANDLE_FLAG
138 static int get_diag(struct atm_dev *dev,void __user *arg)
139 {
140 int set;
142 set = 0;
143 if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP;
144 if (GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP;
145 if (GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP;
146 /* SONET_INS_FRAME is one-shot only */
147 if (GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS;
148 if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS;
149 if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS;
150 if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS;
151 return put_user(set,(int __user *)arg) ? -EFAULT : 0;
152 }
155 static int set_loopback(struct atm_dev *dev,int mode)
156 {
157 unsigned char control;
159 control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE);
160 switch (mode) {
161 case ATM_LM_NONE:
162 break;
163 case ATM_LM_LOC_PHY:
164 control |= SUNI_MCT_DLE;
165 break;
166 case ATM_LM_RMT_PHY:
167 control |= SUNI_MCT_LLE;
168 break;
169 default:
170 return -EINVAL;
171 }
172 PUT(control,MCT);
173 PRIV(dev)->loop_mode = mode;
174 return 0;
175 }
178 static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
179 {
180 switch (cmd) {
181 case SONET_GETSTATZ:
182 case SONET_GETSTAT:
183 return fetch_stats(dev, arg, cmd == SONET_GETSTATZ);
184 case SONET_SETDIAG:
185 return change_diag(dev,arg,1);
186 case SONET_CLRDIAG:
187 return change_diag(dev,arg,0);
188 case SONET_GETDIAG:
189 return get_diag(dev,arg);
190 case SONET_SETFRAMING:
191 if ((int)(unsigned long)arg != SONET_FRAME_SONET) return -EINVAL;
192 return 0;
193 case SONET_GETFRAMING:
194 return put_user(SONET_FRAME_SONET,(int __user *)arg) ?
195 -EFAULT : 0;
196 case SONET_GETFRSENSE:
197 return -EINVAL;
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_PHY | ATM_LM_RMT_PHY,
205 (int __user *) arg) ? -EFAULT : 0;
206 default:
207 return -ENOIOCTLCMD;
208 }
209 }
212 static void poll_los(struct atm_dev *dev)
213 {
214 dev->signal = GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? ATM_PHY_SIG_LOST :
215 ATM_PHY_SIG_FOUND;
216 }
219 static void suni_int(struct atm_dev *dev)
220 {
221 poll_los(dev);
222 printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number,
223 dev->signal == ATM_PHY_SIG_LOST ? "lost" : "detected again");
224 }
227 static int suni_start(struct atm_dev *dev)
228 {
229 unsigned long flags;
230 int first;
232 if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
233 return -ENOMEM;
235 PRIV(dev)->dev = dev;
236 spin_lock_irqsave(&sunis_lock,flags);
237 first = !sunis;
238 PRIV(dev)->next = sunis;
239 sunis = PRIV(dev);
240 spin_unlock_irqrestore(&sunis_lock,flags);
241 memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
242 PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
243 /* interrupt on loss of signal */
244 poll_los(dev); /* ... and clear SUNI interrupts */
245 if (dev->signal == ATM_PHY_SIG_LOST)
246 printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
247 dev->number);
248 PRIV(dev)->loop_mode = ATM_LM_NONE;
249 suni_hz(0); /* clear SUNI counters */
250 (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
251 if (first) {
252 init_timer(&poll_timer);
253 poll_timer.expires = jiffies+HZ;
254 poll_timer.function = suni_hz;
255 poll_timer.data = 1;
256 #if 0
257 printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.list.prev,
258 (unsigned long) poll_timer.list.next);
259 #endif
260 add_timer(&poll_timer);
261 }
262 return 0;
263 }
266 static int suni_stop(struct atm_dev *dev)
267 {
268 struct suni_priv **walk;
269 unsigned long flags;
271 /* let SAR driver worry about stopping interrupts */
272 spin_lock_irqsave(&sunis_lock,flags);
273 for (walk = &sunis; *walk != PRIV(dev);
274 walk = &PRIV((*walk)->dev)->next);
275 *walk = PRIV((*walk)->dev)->next;
276 if (!sunis) del_timer_sync(&poll_timer);
277 spin_unlock_irqrestore(&sunis_lock,flags);
278 kfree(PRIV(dev));
280 return 0;
281 }
284 static const struct atmphy_ops suni_ops = {
285 .start = suni_start,
286 .ioctl = suni_ioctl,
287 .interrupt = suni_int,
288 .stop = suni_stop,
289 };
292 int __devinit suni_init(struct atm_dev *dev)
293 {
294 unsigned char mri;
296 mri = GET(MRI); /* reset SUNI */
297 PUT(mri | SUNI_MRI_RESET,MRI);
298 PUT(mri,MRI);
299 PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */
300 REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET,
301 TPOP_APM); /* use SONET */
302 REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP,
303 TACP_IUCHP); /* idle cells */
304 PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP);
305 dev->phy = &suni_ops;
306 return 0;
307 }
309 EXPORT_SYMBOL(suni_init);
311 MODULE_LICENSE("GPL");