ia64/linux-2.6.18-xen.hg

view drivers/net/chelsio/espi.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 * *
3 * File: espi.c *
4 * $Revision: 1.14 $ *
5 * $Date: 2005/05/14 00:59:32 $ *
6 * Description: *
7 * Ethernet SPI functionality. *
8 * part of the Chelsio 10Gb Ethernet Driver. *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License, version 2, as *
12 * published by the Free Software Foundation. *
13 * *
14 * You should have received a copy of the GNU General Public License along *
15 * with this program; if not, write to the Free Software Foundation, Inc., *
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17 * *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED *
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
21 * *
22 * http://www.chelsio.com *
23 * *
24 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
25 * All rights reserved. *
26 * *
27 * Maintainers: maintainers@chelsio.com *
28 * *
29 * Authors: Dimitrios Michailidis <dm@chelsio.com> *
30 * Tina Yang <tainay@chelsio.com> *
31 * Felix Marti <felix@chelsio.com> *
32 * Scott Bardone <sbardone@chelsio.com> *
33 * Kurt Ottaway <kottaway@chelsio.com> *
34 * Frank DiMambro <frank@chelsio.com> *
35 * *
36 * History: *
37 * *
38 ****************************************************************************/
40 #include "common.h"
41 #include "regs.h"
42 #include "espi.h"
44 struct peespi {
45 adapter_t *adapter;
46 struct espi_intr_counts intr_cnt;
47 u32 misc_ctrl;
48 spinlock_t lock;
49 };
51 #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
52 F_RAMPARITYERR | F_DIP2PARITYERR)
53 #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
54 | F_MONITORED_INTERFACE)
56 #define TRICN_CNFG 14
57 #define TRICN_CMD_READ 0x11
58 #define TRICN_CMD_WRITE 0x21
59 #define TRICN_CMD_ATTEMPTS 10
61 static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
62 int ch_addr, int reg_offset, u32 wr_data)
63 {
64 int busy, attempts = TRICN_CMD_ATTEMPTS;
66 writel(V_WRITE_DATA(wr_data) |
67 V_REGISTER_OFFSET(reg_offset) |
68 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) |
69 V_BUNDLE_ADDR(bundle_addr) |
70 V_SPI4_COMMAND(TRICN_CMD_WRITE),
71 adapter->regs + A_ESPI_CMD_ADDR);
72 writel(0, adapter->regs + A_ESPI_GOSTAT);
74 do {
75 busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY;
76 } while (busy && --attempts);
78 if (busy)
79 CH_ERR("%s: TRICN write timed out\n", adapter->name);
81 return busy;
82 }
84 /* 1. Deassert rx_reset_core. */
85 /* 2. Program TRICN_CNFG registers. */
86 /* 3. Deassert rx_reset_link */
87 static int tricn_init(adapter_t *adapter)
88 {
89 int i = 0;
90 int stat = 0;
91 int timeout = 0;
92 int is_ready = 0;
94 /* 1 */
95 timeout=1000;
96 do {
97 stat = readl(adapter->regs + A_ESPI_RX_RESET);
98 is_ready = (stat & 0x4);
99 timeout--;
100 udelay(5);
101 } while (!is_ready || (timeout==0));
102 writel(0x2, adapter->regs + A_ESPI_RX_RESET);
103 if (timeout==0)
104 {
105 CH_ERR("ESPI : ERROR : Timeout tricn_init() \n");
106 t1_fatal_err(adapter);
107 }
109 /* 2 */
110 tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
111 tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
112 tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
113 for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
114 for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
115 for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
116 for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
117 for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
118 for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
119 for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80);
120 for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
122 /* 3 */
123 writel(0x3, adapter->regs + A_ESPI_RX_RESET);
125 return 0;
126 }
128 void t1_espi_intr_enable(struct peespi *espi)
129 {
130 u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
132 /*
133 * Cannot enable ESPI interrupts on T1B because HW asserts the
134 * interrupt incorrectly, namely the driver gets ESPI interrupts
135 * but no data is actually dropped (can verify this reading the ESPI
136 * drop registers). Also, once the ESPI interrupt is asserted it
137 * cannot be cleared (HW bug).
138 */
139 enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK;
140 writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE);
141 writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
142 }
144 void t1_espi_intr_clear(struct peespi *espi)
145 {
146 writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS);
147 writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE);
148 }
150 void t1_espi_intr_disable(struct peespi *espi)
151 {
152 u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
154 writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE);
155 writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
156 }
158 int t1_espi_intr_handler(struct peespi *espi)
159 {
160 u32 cnt;
161 u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
163 if (status & F_DIP4ERR)
164 espi->intr_cnt.DIP4_err++;
165 if (status & F_RXDROP)
166 espi->intr_cnt.rx_drops++;
167 if (status & F_TXDROP)
168 espi->intr_cnt.tx_drops++;
169 if (status & F_RXOVERFLOW)
170 espi->intr_cnt.rx_ovflw++;
171 if (status & F_RAMPARITYERR)
172 espi->intr_cnt.parity_err++;
173 if (status & F_DIP2PARITYERR) {
174 espi->intr_cnt.DIP2_parity_err++;
176 /*
177 * Must read the error count to clear the interrupt
178 * that it causes.
179 */
180 cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
181 }
183 /*
184 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
185 * write the status as is.
186 */
187 if (status && t1_is_T1B(espi->adapter))
188 status = 1;
189 writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
190 return 0;
191 }
193 const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi)
194 {
195 return &espi->intr_cnt;
196 }
198 static void espi_setup_for_pm3393(adapter_t *adapter)
199 {
200 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
202 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
203 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1);
204 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
205 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3);
206 writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
207 writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
208 writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH);
209 writel(0x08000008, adapter->regs + A_ESPI_TRAIN);
210 writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG);
211 }
213 /* T2 Init part -- */
214 /* 1. Set T_ESPI_MISCCTRL_ADDR */
215 /* 2. Init ESPI registers. */
216 /* 3. Init TriCN Hard Macro */
217 int t1_espi_init(struct peespi *espi, int mac_type, int nports)
218 {
219 u32 cnt;
221 u32 status_enable_extra = 0;
222 adapter_t *adapter = espi->adapter;
223 u32 status, burstval = 0x800100;
225 /* Disable ESPI training. MACs that can handle it enable it below. */
226 writel(0, adapter->regs + A_ESPI_TRAIN);
228 if (is_T2(adapter)) {
229 writel(V_OUT_OF_SYNC_COUNT(4) |
230 V_DIP2_PARITY_ERR_THRES(3) |
231 V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
232 if (nports == 4) {
233 /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */
234 burstval = 0x200040;
235 }
236 }
237 writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
239 switch (mac_type) {
240 case CHBT_MAC_PM3393:
241 espi_setup_for_pm3393(adapter);
242 break;
243 default:
244 return -1;
245 }
247 /*
248 * Make sure any pending interrupts from the SPI are
249 * Cleared before enabling the interrupt.
250 */
251 writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE);
252 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
253 if (status & F_DIP2PARITYERR) {
254 cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
255 }
257 /*
258 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
259 * write the status as is.
260 */
261 if (status && t1_is_T1B(espi->adapter))
262 status = 1;
263 writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
265 writel(status_enable_extra | F_RXSTATUSENABLE,
266 adapter->regs + A_ESPI_FIFO_STATUS_ENABLE);
268 if (is_T2(adapter)) {
269 tricn_init(adapter);
270 /*
271 * Always position the control at the 1st port egress IN
272 * (sop,eop) counter to reduce PIOs for T/N210 workaround.
273 */
274 espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL)
275 & ~MON_MASK) | (F_MONITORED_DIRECTION
276 | F_MONITORED_INTERFACE);
277 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
278 spin_lock_init(&espi->lock);
279 }
281 return 0;
282 }
284 void t1_espi_destroy(struct peespi *espi)
285 {
286 kfree(espi);
287 }
289 struct peespi *t1_espi_create(adapter_t *adapter)
290 {
291 struct peespi *espi = kzalloc(sizeof(*espi), GFP_KERNEL);
293 if (espi)
294 espi->adapter = adapter;
295 return espi;
296 }
298 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
299 {
300 struct peespi *espi = adapter->espi;
302 if (!is_T2(adapter))
303 return;
304 spin_lock(&espi->lock);
305 espi->misc_ctrl = (val & ~MON_MASK) |
306 (espi->misc_ctrl & MON_MASK);
307 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
308 spin_unlock(&espi->lock);
309 }
311 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
312 {
313 u32 sel;
315 struct peespi *espi = adapter->espi;
317 if (!is_T2(adapter))
318 return 0;
319 sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
320 if (!wait) {
321 if (!spin_trylock(&espi->lock))
322 return 0;
323 }
324 else
325 spin_lock(&espi->lock);
326 if ((sel != (espi->misc_ctrl & MON_MASK))) {
327 writel(((espi->misc_ctrl & ~MON_MASK) | sel),
328 adapter->regs + A_ESPI_MISC_CONTROL);
329 sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
330 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
331 }
332 else
333 sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
334 spin_unlock(&espi->lock);
335 return sel;
336 }