ia64/linux-2.6.18-xen.hg

view drivers/net/ixp2000/ixp2400-msf.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 * Generic library functions for the MSF (Media and Switch Fabric) unit
3 * found on the Intel IXP2400 network processor.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <asm/hardware.h>
17 #include <asm/arch/ixp2000-regs.h>
18 #include <asm/delay.h>
19 #include <asm/io.h>
20 #include "ixp2400-msf.h"
22 /*
23 * This is the Intel recommended PLL init procedure as described on
24 * page 340 of the IXP2400/IXP2800 Programmer's Reference Manual.
25 */
26 static void ixp2400_pll_init(struct ixp2400_msf_parameters *mp)
27 {
28 int rx_dual_clock;
29 int tx_dual_clock;
30 u32 value;
32 /*
33 * If the RX mode is not 1x32, we have to enable both RX PLLs
34 * (#0 and #1.) The same thing for the TX direction.
35 */
36 rx_dual_clock = !!(mp->rx_mode & IXP2400_RX_MODE_WIDTH_MASK);
37 tx_dual_clock = !!(mp->tx_mode & IXP2400_TX_MODE_WIDTH_MASK);
39 /*
40 * Read initial value.
41 */
42 value = ixp2000_reg_read(IXP2000_MSF_CLK_CNTRL);
44 /*
45 * Put PLLs in powerdown and bypass mode.
46 */
47 value |= 0x0000f0f0;
48 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
50 /*
51 * Set single or dual clock mode bits.
52 */
53 value &= ~0x03000000;
54 value |= (rx_dual_clock << 24) | (tx_dual_clock << 25);
56 /*
57 * Set multipliers.
58 */
59 value &= ~0x00ff0000;
60 value |= mp->rxclk01_multiplier << 16;
61 value |= mp->rxclk23_multiplier << 18;
62 value |= mp->txclk01_multiplier << 20;
63 value |= mp->txclk23_multiplier << 22;
65 /*
66 * And write value.
67 */
68 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
70 /*
71 * Disable PLL bypass mode.
72 */
73 value &= ~(0x00005000 | rx_dual_clock << 13 | tx_dual_clock << 15);
74 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
76 /*
77 * Turn on PLLs.
78 */
79 value &= ~(0x00000050 | rx_dual_clock << 5 | tx_dual_clock << 7);
80 ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
82 /*
83 * Wait for PLLs to lock. There are lock status bits, but IXP2400
84 * erratum #65 says that these lock bits should not be relied upon
85 * as they might not accurately reflect the true state of the PLLs.
86 */
87 udelay(100);
88 }
90 /*
91 * Needed according to p480 of Programmer's Reference Manual.
92 */
93 static void ixp2400_msf_free_rbuf_entries(struct ixp2400_msf_parameters *mp)
94 {
95 int size_bits;
96 int i;
98 /*
99 * Work around IXP2400 erratum #69 (silent RBUF-to-DRAM transfer
100 * corruption) in the Intel-recommended way: do not add the RBUF
101 * elements susceptible to corruption to the freelist.
102 */
103 size_bits = mp->rx_mode & IXP2400_RX_MODE_RBUF_SIZE_MASK;
104 if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_64) {
105 for (i = 1; i < 128; i++) {
106 if (i == 9 || i == 18 || i == 27)
107 continue;
108 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
109 }
110 } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_128) {
111 for (i = 1; i < 64; i++) {
112 if (i == 4 || i == 9 || i == 13)
113 continue;
114 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
115 }
116 } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_256) {
117 for (i = 1; i < 32; i++) {
118 if (i == 2 || i == 4 || i == 6)
119 continue;
120 ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
121 }
122 }
123 }
125 static u32 ixp2400_msf_valid_channels(u32 reg)
126 {
127 u32 channels;
129 channels = 0;
130 switch (reg & IXP2400_RX_MODE_WIDTH_MASK) {
131 case IXP2400_RX_MODE_1x32:
132 channels = 0x1;
133 if (reg & IXP2400_RX_MODE_MPHY &&
134 !(reg & IXP2400_RX_MODE_MPHY_32))
135 channels = 0xf;
136 break;
138 case IXP2400_RX_MODE_2x16:
139 channels = 0x5;
140 break;
142 case IXP2400_RX_MODE_4x8:
143 channels = 0xf;
144 break;
146 case IXP2400_RX_MODE_1x16_2x8:
147 channels = 0xd;
148 break;
149 }
151 return channels;
152 }
154 static void ixp2400_msf_enable_rx(struct ixp2400_msf_parameters *mp)
155 {
156 u32 value;
158 value = ixp2000_reg_read(IXP2000_MSF_RX_CONTROL) & 0x0fffffff;
159 value |= ixp2400_msf_valid_channels(mp->rx_mode) << 28;
160 ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, value);
161 }
163 static void ixp2400_msf_enable_tx(struct ixp2400_msf_parameters *mp)
164 {
165 u32 value;
167 value = ixp2000_reg_read(IXP2000_MSF_TX_CONTROL) & 0x0fffffff;
168 value |= ixp2400_msf_valid_channels(mp->tx_mode) << 28;
169 ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, value);
170 }
173 void ixp2400_msf_init(struct ixp2400_msf_parameters *mp)
174 {
175 u32 value;
176 int i;
178 /*
179 * Init the RX/TX PLLs based on the passed parameter block.
180 */
181 ixp2400_pll_init(mp);
183 /*
184 * Reset MSF. Bit 7 in IXP_RESET_0 resets the MSF.
185 */
186 value = ixp2000_reg_read(IXP2000_RESET0);
187 ixp2000_reg_write(IXP2000_RESET0, value | 0x80);
188 ixp2000_reg_write(IXP2000_RESET0, value & ~0x80);
190 /*
191 * Initialise the RX section.
192 */
193 ixp2000_reg_write(IXP2000_MSF_RX_MPHY_POLL_LIMIT, mp->rx_poll_ports - 1);
194 ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, mp->rx_mode);
195 for (i = 0; i < 4; i++) {
196 ixp2000_reg_write(IXP2000_MSF_RX_UP_CONTROL_0 + i,
197 mp->rx_channel_mode[i]);
198 }
199 ixp2400_msf_free_rbuf_entries(mp);
200 ixp2400_msf_enable_rx(mp);
202 /*
203 * Initialise the TX section.
204 */
205 ixp2000_reg_write(IXP2000_MSF_TX_MPHY_POLL_LIMIT, mp->tx_poll_ports - 1);
206 ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, mp->tx_mode);
207 for (i = 0; i < 4; i++) {
208 ixp2000_reg_write(IXP2000_MSF_TX_UP_CONTROL_0 + i,
209 mp->tx_channel_mode[i]);
210 }
211 ixp2400_msf_enable_tx(mp);
212 }