ia64/linux-2.6.18-xen.hg

view drivers/net/ixp2000/pm3386.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 /*
2 * Helper functions for the PM3386s on the Radisys ENP2611
3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
4 * Dedicated to Marija Kulikova.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/netdevice.h>
15 #include <asm/io.h>
16 #include "pm3386.h"
18 /*
19 * Read from register 'reg' of PM3386 device 'pm'.
20 */
21 static u16 pm3386_reg_read(int pm, int reg)
22 {
23 void *_reg;
24 u16 value;
26 _reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
27 if (pm == 1)
28 _reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
30 value = *((volatile u16 *)(_reg + (reg << 1)));
32 // printk(KERN_INFO "pm3386_reg_read(%d, %.3x) = %.8x\n", pm, reg, value);
34 return value;
35 }
37 /*
38 * Write to register 'reg' of PM3386 device 'pm', and perform
39 * a readback from the identification register.
40 */
41 static void pm3386_reg_write(int pm, int reg, u16 value)
42 {
43 void *_reg;
44 u16 dummy;
46 // printk(KERN_INFO "pm3386_reg_write(%d, %.3x, %.8x)\n", pm, reg, value);
48 _reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
49 if (pm == 1)
50 _reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
52 *((volatile u16 *)(_reg + (reg << 1))) = value;
54 dummy = *((volatile u16 *)_reg);
55 __asm__ __volatile__("mov %0, %0" : "+r" (dummy));
56 }
58 /*
59 * Read from port 'port' register 'reg', where the registers
60 * for the different ports are 'spacing' registers apart.
61 */
62 static u16 pm3386_port_reg_read(int port, int _reg, int spacing)
63 {
64 int reg;
66 reg = _reg;
67 if (port & 1)
68 reg += spacing;
70 return pm3386_reg_read(port >> 1, reg);
71 }
73 /*
74 * Write to port 'port' register 'reg', where the registers
75 * for the different ports are 'spacing' registers apart.
76 */
77 static void pm3386_port_reg_write(int port, int _reg, int spacing, u16 value)
78 {
79 int reg;
81 reg = _reg;
82 if (port & 1)
83 reg += spacing;
85 pm3386_reg_write(port >> 1, reg, value);
86 }
88 int pm3386_secondary_present(void)
89 {
90 return pm3386_reg_read(1, 0) == 0x3386;
91 }
93 void pm3386_reset(void)
94 {
95 u8 mac[3][6];
96 int secondary;
98 secondary = pm3386_secondary_present();
100 /* Save programmed MAC addresses. */
101 pm3386_get_mac(0, mac[0]);
102 pm3386_get_mac(1, mac[1]);
103 if (secondary)
104 pm3386_get_mac(2, mac[2]);
106 /* Assert analog and digital reset. */
107 pm3386_reg_write(0, 0x002, 0x0060);
108 if (secondary)
109 pm3386_reg_write(1, 0x002, 0x0060);
110 mdelay(1);
112 /* Deassert analog reset. */
113 pm3386_reg_write(0, 0x002, 0x0062);
114 if (secondary)
115 pm3386_reg_write(1, 0x002, 0x0062);
116 mdelay(10);
118 /* Deassert digital reset. */
119 pm3386_reg_write(0, 0x002, 0x0063);
120 if (secondary)
121 pm3386_reg_write(1, 0x002, 0x0063);
122 mdelay(10);
124 /* Restore programmed MAC addresses. */
125 pm3386_set_mac(0, mac[0]);
126 pm3386_set_mac(1, mac[1]);
127 if (secondary)
128 pm3386_set_mac(2, mac[2]);
130 /* Disable carrier on all ports. */
131 pm3386_set_carrier(0, 0);
132 pm3386_set_carrier(1, 0);
133 if (secondary)
134 pm3386_set_carrier(2, 0);
135 }
137 static u16 swaph(u16 x)
138 {
139 return ((x << 8) | (x >> 8)) & 0xffff;
140 }
142 int pm3386_port_count(void)
143 {
144 return 2 + pm3386_secondary_present();
145 }
147 void pm3386_init_port(int port)
148 {
149 int pm = port >> 1;
151 /*
152 * Work around ENP2611 bootloader programming MAC address
153 * in reverse.
154 */
155 if (pm3386_port_reg_read(port, 0x30a, 0x100) == 0x0000 &&
156 (pm3386_port_reg_read(port, 0x309, 0x100) & 0xff00) == 0x5000) {
157 u16 temp[3];
159 temp[0] = pm3386_port_reg_read(port, 0x308, 0x100);
160 temp[1] = pm3386_port_reg_read(port, 0x309, 0x100);
161 temp[2] = pm3386_port_reg_read(port, 0x30a, 0x100);
162 pm3386_port_reg_write(port, 0x308, 0x100, swaph(temp[2]));
163 pm3386_port_reg_write(port, 0x309, 0x100, swaph(temp[1]));
164 pm3386_port_reg_write(port, 0x30a, 0x100, swaph(temp[0]));
165 }
167 /*
168 * Initialise narrowbanding mode. See application note 2010486
169 * for more information. (@@@ We also need to issue a reset
170 * when ROOL or DOOL are detected.)
171 */
172 pm3386_port_reg_write(port, 0x708, 0x10, 0xd055);
173 udelay(500);
174 pm3386_port_reg_write(port, 0x708, 0x10, 0x5055);
176 /*
177 * SPI-3 ingress block. Set 64 bytes SPI-3 burst size
178 * towards SPI-3 bridge.
179 */
180 pm3386_port_reg_write(port, 0x122, 0x20, 0x0002);
182 /*
183 * Enable ingress protocol checking, and soft reset the
184 * SPI-3 ingress block.
185 */
186 pm3386_reg_write(pm, 0x103, 0x0003);
187 while (!(pm3386_reg_read(pm, 0x103) & 0x80))
188 ;
190 /*
191 * SPI-3 egress block. Gather 12288 bytes of the current
192 * packet in the TX fifo before initiating transmit on the
193 * SERDES interface. (Prevents TX underflows.)
194 */
195 pm3386_port_reg_write(port, 0x221, 0x20, 0x0007);
197 /*
198 * Enforce odd parity from the SPI-3 bridge, and soft reset
199 * the SPI-3 egress block.
200 */
201 pm3386_reg_write(pm, 0x203, 0x000d & ~(4 << (port & 1)));
202 while ((pm3386_reg_read(pm, 0x203) & 0x000c) != 0x000c)
203 ;
205 /*
206 * EGMAC block. Set this channels to reject long preambles,
207 * not send or transmit PAUSE frames, enable preamble checking,
208 * disable frame length checking, enable FCS appending, enable
209 * TX frame padding.
210 */
211 pm3386_port_reg_write(port, 0x302, 0x100, 0x0113);
213 /*
214 * Soft reset the EGMAC block.
215 */
216 pm3386_port_reg_write(port, 0x301, 0x100, 0x8000);
217 pm3386_port_reg_write(port, 0x301, 0x100, 0x0000);
219 /*
220 * Auto-sense autonegotiation status.
221 */
222 pm3386_port_reg_write(port, 0x306, 0x100, 0x0100);
224 /*
225 * Allow reception of jumbo frames.
226 */
227 pm3386_port_reg_write(port, 0x310, 0x100, 9018);
229 /*
230 * Allow transmission of jumbo frames.
231 */
232 pm3386_port_reg_write(port, 0x336, 0x100, 9018);
234 /* @@@ Should set 0x337/0x437 (RX forwarding threshold.) */
236 /*
237 * Set autonegotiation parameters to 'no PAUSE, full duplex.'
238 */
239 pm3386_port_reg_write(port, 0x31c, 0x100, 0x0020);
241 /*
242 * Enable and restart autonegotiation.
243 */
244 pm3386_port_reg_write(port, 0x318, 0x100, 0x0003);
245 pm3386_port_reg_write(port, 0x318, 0x100, 0x0002);
246 }
248 void pm3386_get_mac(int port, u8 *mac)
249 {
250 u16 temp;
252 temp = pm3386_port_reg_read(port, 0x308, 0x100);
253 mac[0] = temp & 0xff;
254 mac[1] = (temp >> 8) & 0xff;
256 temp = pm3386_port_reg_read(port, 0x309, 0x100);
257 mac[2] = temp & 0xff;
258 mac[3] = (temp >> 8) & 0xff;
260 temp = pm3386_port_reg_read(port, 0x30a, 0x100);
261 mac[4] = temp & 0xff;
262 mac[5] = (temp >> 8) & 0xff;
263 }
265 void pm3386_set_mac(int port, u8 *mac)
266 {
267 pm3386_port_reg_write(port, 0x308, 0x100, (mac[1] << 8) | mac[0]);
268 pm3386_port_reg_write(port, 0x309, 0x100, (mac[3] << 8) | mac[2]);
269 pm3386_port_reg_write(port, 0x30a, 0x100, (mac[5] << 8) | mac[4]);
270 }
272 static u32 pm3386_get_stat(int port, u16 base)
273 {
274 u32 value;
276 value = pm3386_port_reg_read(port, base, 0x100);
277 value |= pm3386_port_reg_read(port, base + 1, 0x100) << 16;
279 return value;
280 }
282 void pm3386_get_stats(int port, struct net_device_stats *stats)
283 {
284 /*
285 * Snapshot statistics counters.
286 */
287 pm3386_port_reg_write(port, 0x500, 0x100, 0x0001);
288 while (pm3386_port_reg_read(port, 0x500, 0x100) & 0x0001)
289 ;
291 memset(stats, 0, sizeof(*stats));
293 stats->rx_packets = pm3386_get_stat(port, 0x510);
294 stats->tx_packets = pm3386_get_stat(port, 0x590);
295 stats->rx_bytes = pm3386_get_stat(port, 0x514);
296 stats->tx_bytes = pm3386_get_stat(port, 0x594);
297 /* @@@ Add other stats. */
298 }
300 void pm3386_set_carrier(int port, int state)
301 {
302 pm3386_port_reg_write(port, 0x703, 0x10, state ? 0x1001 : 0x0000);
303 }
305 int pm3386_is_link_up(int port)
306 {
307 u16 temp;
309 temp = pm3386_port_reg_read(port, 0x31a, 0x100);
310 temp = pm3386_port_reg_read(port, 0x31a, 0x100);
312 return !!(temp & 0x0002);
313 }
315 void pm3386_enable_rx(int port)
316 {
317 u16 temp;
319 temp = pm3386_port_reg_read(port, 0x303, 0x100);
320 temp |= 0x1000;
321 pm3386_port_reg_write(port, 0x303, 0x100, temp);
322 }
324 void pm3386_disable_rx(int port)
325 {
326 u16 temp;
328 temp = pm3386_port_reg_read(port, 0x303, 0x100);
329 temp &= 0xefff;
330 pm3386_port_reg_write(port, 0x303, 0x100, temp);
331 }
333 void pm3386_enable_tx(int port)
334 {
335 u16 temp;
337 temp = pm3386_port_reg_read(port, 0x303, 0x100);
338 temp |= 0x4000;
339 pm3386_port_reg_write(port, 0x303, 0x100, temp);
340 }
342 void pm3386_disable_tx(int port)
343 {
344 u16 temp;
346 temp = pm3386_port_reg_read(port, 0x303, 0x100);
347 temp &= 0xbfff;
348 pm3386_port_reg_write(port, 0x303, 0x100, temp);
349 }
351 MODULE_LICENSE("GPL");