ia64/linux-2.6.18-xen.hg

view arch/alpha/kernel/sys_marvel.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 * linux/arch/alpha/kernel/sys_marvel.c
3 *
4 * Marvel / IO7 support
5 */
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/mm.h>
10 #include <linux/sched.h>
11 #include <linux/pci.h>
12 #include <linux/init.h>
13 #include <linux/bitops.h>
15 #include <asm/ptrace.h>
16 #include <asm/system.h>
17 #include <asm/dma.h>
18 #include <asm/irq.h>
19 #include <asm/mmu_context.h>
20 #include <asm/io.h>
21 #include <asm/pgtable.h>
22 #include <asm/core_marvel.h>
23 #include <asm/hwrpb.h>
24 #include <asm/tlbflush.h>
26 #include "proto.h"
27 #include "err_impl.h"
28 #include "irq_impl.h"
29 #include "pci_impl.h"
30 #include "machvec_impl.h"
32 #if NR_IRQS < MARVEL_NR_IRQS
33 # error NR_IRQS < MARVEL_NR_IRQS !!!
34 #endif
37 /*
38 * Interrupt handling.
39 */
40 static void
41 io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
42 {
43 unsigned int pid;
44 unsigned int irq;
46 /*
47 * Vector is 0x800 + (interrupt)
48 *
49 * where (interrupt) is:
50 *
51 * ...16|15 14|13 4|3 0
52 * -----+-----+--------+---
53 * PE | 0 | irq | 0
54 *
55 * where (irq) is
56 *
57 * 0x0800 - 0x0ff0 - 0x0800 + (LSI id << 4)
58 * 0x1000 - 0x2ff0 - 0x1000 + (MSI_DAT<8:0> << 4)
59 */
60 pid = vector >> 16;
61 irq = ((vector & 0xffff) - 0x800) >> 4;
63 irq += 16; /* offset for legacy */
64 irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */
65 irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
67 handle_irq(irq, regs);
68 }
70 static volatile unsigned long *
71 io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
72 {
73 volatile unsigned long *ctl;
74 unsigned int pid;
75 struct io7 *io7;
77 pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
79 if (!(io7 = marvel_find_io7(pid))) {
80 printk(KERN_ERR
81 "%s for nonexistent io7 -- vec %x, pid %d\n",
82 __FUNCTION__, irq, pid);
83 return NULL;
84 }
86 irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* isolate the vector */
87 irq -= 16; /* subtract legacy bias */
89 if (irq >= 0x180) {
90 printk(KERN_ERR
91 "%s for invalid irq -- pid %d adjusted irq %x\n",
92 __FUNCTION__, pid, irq);
93 return NULL;
94 }
96 ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
97 if (irq >= 0x80) /* MSI */
98 ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
100 if (pio7) *pio7 = io7;
101 return ctl;
102 }
104 static void
105 io7_enable_irq(unsigned int irq)
106 {
107 volatile unsigned long *ctl;
108 struct io7 *io7;
110 ctl = io7_get_irq_ctl(irq, &io7);
111 if (!ctl || !io7) {
112 printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
113 __FUNCTION__, irq);
114 return;
115 }
117 spin_lock(&io7->irq_lock);
118 *ctl |= 1UL << 24;
119 mb();
120 *ctl;
121 spin_unlock(&io7->irq_lock);
122 }
124 static void
125 io7_disable_irq(unsigned int irq)
126 {
127 volatile unsigned long *ctl;
128 struct io7 *io7;
130 ctl = io7_get_irq_ctl(irq, &io7);
131 if (!ctl || !io7) {
132 printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
133 __FUNCTION__, irq);
134 return;
135 }
137 spin_lock(&io7->irq_lock);
138 *ctl &= ~(1UL << 24);
139 mb();
140 *ctl;
141 spin_unlock(&io7->irq_lock);
142 }
144 static unsigned int
145 io7_startup_irq(unsigned int irq)
146 {
147 io7_enable_irq(irq);
148 return 0; /* never anything pending */
149 }
151 static void
152 io7_end_irq(unsigned int irq)
153 {
154 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
155 io7_enable_irq(irq);
156 }
158 static void
159 marvel_irq_noop(unsigned int irq)
160 {
161 return;
162 }
164 static unsigned int
165 marvel_irq_noop_return(unsigned int irq)
166 {
167 return 0;
168 }
170 static struct hw_interrupt_type marvel_legacy_irq_type = {
171 .typename = "LEGACY",
172 .startup = marvel_irq_noop_return,
173 .shutdown = marvel_irq_noop,
174 .enable = marvel_irq_noop,
175 .disable = marvel_irq_noop,
176 .ack = marvel_irq_noop,
177 .end = marvel_irq_noop,
178 };
180 static struct hw_interrupt_type io7_lsi_irq_type = {
181 .typename = "LSI",
182 .startup = io7_startup_irq,
183 .shutdown = io7_disable_irq,
184 .enable = io7_enable_irq,
185 .disable = io7_disable_irq,
186 .ack = io7_disable_irq,
187 .end = io7_end_irq,
188 };
190 static struct hw_interrupt_type io7_msi_irq_type = {
191 .typename = "MSI",
192 .startup = io7_startup_irq,
193 .shutdown = io7_disable_irq,
194 .enable = io7_enable_irq,
195 .disable = io7_disable_irq,
196 .ack = marvel_irq_noop,
197 .end = io7_end_irq,
198 };
200 static void
201 io7_redirect_irq(struct io7 *io7,
202 volatile unsigned long *csr,
203 unsigned int where)
204 {
205 unsigned long val;
207 val = *csr;
208 val &= ~(0x1ffUL << 24); /* clear the target pid */
209 val |= ((unsigned long)where << 24); /* set the new target pid */
211 *csr = val;
212 mb();
213 *csr;
214 }
216 static void
217 io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
218 {
219 unsigned long val;
221 /*
222 * LSI_CTL has target PID @ 14
223 */
224 val = io7->csrs->PO7_LSI_CTL[which].csr;
225 val &= ~(0x1ffUL << 14); /* clear the target pid */
226 val |= ((unsigned long)where << 14); /* set the new target pid */
228 io7->csrs->PO7_LSI_CTL[which].csr = val;
229 mb();
230 io7->csrs->PO7_LSI_CTL[which].csr;
231 }
233 static void
234 io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
235 {
236 unsigned long val;
238 /*
239 * MSI_CTL has target PID @ 14
240 */
241 val = io7->csrs->PO7_MSI_CTL[which].csr;
242 val &= ~(0x1ffUL << 14); /* clear the target pid */
243 val |= ((unsigned long)where << 14); /* set the new target pid */
245 io7->csrs->PO7_MSI_CTL[which].csr = val;
246 mb();
247 io7->csrs->PO7_MSI_CTL[which].csr;
248 }
250 static void __init
251 init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
252 {
253 /*
254 * LSI_CTL has target PID @ 14
255 */
256 io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
257 mb();
258 io7->csrs->PO7_LSI_CTL[which].csr;
259 }
261 static void __init
262 init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
263 {
264 /*
265 * MSI_CTL has target PID @ 14
266 */
267 io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
268 mb();
269 io7->csrs->PO7_MSI_CTL[which].csr;
270 }
272 static void __init
273 init_io7_irqs(struct io7 *io7,
274 struct hw_interrupt_type *lsi_ops,
275 struct hw_interrupt_type *msi_ops)
276 {
277 long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
278 long i;
280 printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
281 io7->pe, base);
283 /*
284 * Where should interrupts from this IO7 go?
285 *
286 * They really should be sent to the local CPU to avoid having to
287 * traverse the mesh, but if it's not an SMP kernel, they have to
288 * go to the boot CPU. Send them all to the boot CPU for now,
289 * as each secondary starts, it can redirect it's local device
290 * interrupts.
291 */
292 printk(" Interrupts reported to CPU at PE %u\n", boot_cpuid);
294 spin_lock(&io7->irq_lock);
296 /* set up the error irqs */
297 io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
298 io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
299 io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
300 io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
301 io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
303 /* Set up the lsi irqs. */
304 for (i = 0; i < 128; ++i) {
305 irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
306 irq_desc[base + i].chip = lsi_ops;
307 }
309 /* Disable the implemented irqs in hardware. */
310 for (i = 0; i < 0x60; ++i)
311 init_one_io7_lsi(io7, i, boot_cpuid);
313 init_one_io7_lsi(io7, 0x74, boot_cpuid);
314 init_one_io7_lsi(io7, 0x75, boot_cpuid);
317 /* Set up the msi irqs. */
318 for (i = 128; i < (128 + 512); ++i) {
319 irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
320 irq_desc[base + i].chip = msi_ops;
321 }
323 for (i = 0; i < 16; ++i)
324 init_one_io7_msi(io7, i, boot_cpuid);
326 spin_unlock(&io7->irq_lock);
327 }
329 static void __init
330 marvel_init_irq(void)
331 {
332 int i;
333 struct io7 *io7 = NULL;
335 /* Reserve the legacy irqs. */
336 for (i = 0; i < 16; ++i) {
337 irq_desc[i].status = IRQ_DISABLED;
338 irq_desc[i].chip = &marvel_legacy_irq_type;
339 }
341 /* Init the io7 irqs. */
342 for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
343 init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
344 }
346 static int
347 marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
348 {
349 struct pci_controller *hose = dev->sysdata;
350 struct io7_port *io7_port = hose->sysdata;
351 struct io7 *io7 = io7_port->io7;
352 int msi_loc, msi_data_off;
353 u16 msg_ctl;
354 u16 msg_dat;
355 u8 intline;
356 int irq;
358 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
359 irq = intline;
361 msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
362 msg_ctl = 0;
363 if (msi_loc)
364 pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
366 if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
367 msi_data_off = PCI_MSI_DATA_32;
368 if (msg_ctl & PCI_MSI_FLAGS_64BIT)
369 msi_data_off = PCI_MSI_DATA_64;
370 pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
372 irq = msg_dat & 0x1ff; /* we use msg_data<8:0> */
373 irq += 0x80; /* offset for lsi */
375 #if 1
376 printk("PCI:%d:%d:%d (hose %d) is using MSI\n",
377 dev->bus->number,
378 PCI_SLOT(dev->devfn),
379 PCI_FUNC(dev->devfn),
380 hose->index);
381 printk(" %d message(s) from 0x%04x\n",
382 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
383 msg_dat);
384 printk(" reporting on %d IRQ(s) from %d (0x%x)\n",
385 1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
386 (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
387 (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
388 #endif
390 #if 0
391 pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
392 msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
393 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
394 irq = intline;
396 printk(" forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
397 #endif
398 }
400 irq += 16; /* offset for legacy */
401 irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
403 return irq;
404 }
406 static void __init
407 marvel_init_pci(void)
408 {
409 struct io7 *io7;
411 marvel_register_error_handlers();
413 pci_probe_only = 1;
414 common_init_pci();
416 #ifdef CONFIG_VGA_HOSE
417 locate_and_init_vga(NULL);
418 #endif
420 /* Clear any io7 errors. */
421 for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
422 io7_clear_errors(io7);
423 }
425 static void
426 marvel_init_rtc(void)
427 {
428 init_rtc_irq();
429 }
431 static void
432 marvel_smp_callin(void)
433 {
434 int cpuid = hard_smp_processor_id();
435 struct io7 *io7 = marvel_find_io7(cpuid);
436 unsigned int i;
438 if (!io7)
439 return;
441 /*
442 * There is a local IO7 - redirect all of its interrupts here.
443 */
444 printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
446 /* Redirect the error IRQS here. */
447 io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
448 io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
449 io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
450 io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
451 io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
453 /* Redirect the implemented LSIs here. */
454 for (i = 0; i < 0x60; ++i)
455 io7_redirect_one_lsi(io7, i, cpuid);
457 io7_redirect_one_lsi(io7, 0x74, cpuid);
458 io7_redirect_one_lsi(io7, 0x75, cpuid);
460 /* Redirect the MSIs here. */
461 for (i = 0; i < 16; ++i)
462 io7_redirect_one_msi(io7, i, cpuid);
463 }
465 /*
466 * System Vectors
467 */
468 struct alpha_machine_vector marvel_ev7_mv __initmv = {
469 .vector_name = "MARVEL/EV7",
470 DO_EV7_MMU,
471 DO_DEFAULT_RTC,
472 DO_MARVEL_IO,
473 .machine_check = marvel_machine_check,
474 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
475 .min_io_address = DEFAULT_IO_BASE,
476 .min_mem_address = DEFAULT_MEM_BASE,
477 .pci_dac_offset = IO7_DAC_OFFSET,
479 .nr_irqs = MARVEL_NR_IRQS,
480 .device_interrupt = io7_device_interrupt,
482 .agp_info = marvel_agp_info,
484 .smp_callin = marvel_smp_callin,
485 .init_arch = marvel_init_arch,
486 .init_irq = marvel_init_irq,
487 .init_rtc = marvel_init_rtc,
488 .init_pci = marvel_init_pci,
489 .kill_arch = marvel_kill_arch,
490 .pci_map_irq = marvel_map_irq,
491 .pci_swizzle = common_swizzle,
493 .pa_to_nid = marvel_pa_to_nid,
494 .cpuid_to_nid = marvel_cpuid_to_nid,
495 .node_mem_start = marvel_node_mem_start,
496 .node_mem_size = marvel_node_mem_size,
497 };
498 ALIAS_MV(marvel_ev7)