diff options
Diffstat (limited to 'arch')
372 files changed, 26423 insertions, 5251 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 694c9af520bb..3ea332b009e5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -36,3 +36,6 @@ config HAVE_KPROBES | |||
36 | 36 | ||
37 | config HAVE_KRETPROBES | 37 | config HAVE_KRETPROBES |
38 | def_bool n | 38 | def_bool n |
39 | |||
40 | config HAVE_DMA_ATTRS | ||
41 | def_bool n | ||
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index 6c56c754a0b5..4b18cd94d59d 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c | |||
@@ -8,13 +8,9 @@ | |||
8 | #include <linux/stddef.h> | 8 | #include <linux/stddef.h> |
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/ptrace.h> | 10 | #include <linux/ptrace.h> |
11 | #include <linux/kbuild.h> | ||
11 | #include <asm/io.h> | 12 | #include <asm/io.h> |
12 | 13 | ||
13 | #define DEFINE(sym, val) \ | ||
14 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
15 | |||
16 | #define BLANK() asm volatile("\n->" : : ) | ||
17 | |||
18 | void foo(void) | 14 | void foo(void) |
19 | { | 15 | { |
20 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 16 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c index f10d2eddd2c3..b04f1feb1dda 100644 --- a/arch/alpha/kernel/core_marvel.c +++ b/arch/alpha/kernel/core_marvel.c | |||
@@ -994,7 +994,7 @@ marvel_agp_configure(alpha_agp_info *agp) | |||
994 | * rate, but warn the user. | 994 | * rate, but warn the user. |
995 | */ | 995 | */ |
996 | printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n", | 996 | printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n", |
997 | __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll); | 997 | __func__, IO7_PLL_RNGB(agp_pll), agp_pll); |
998 | break; | 998 | break; |
999 | } | 999 | } |
1000 | 1000 | ||
@@ -1044,13 +1044,13 @@ marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr) | |||
1044 | 1044 | ||
1045 | if (addr < agp->aperture.bus_base || | 1045 | if (addr < agp->aperture.bus_base || |
1046 | addr >= agp->aperture.bus_base + agp->aperture.size) { | 1046 | addr >= agp->aperture.bus_base + agp->aperture.size) { |
1047 | printk("%s: addr out of range\n", __FUNCTION__); | 1047 | printk("%s: addr out of range\n", __func__); |
1048 | return -EINVAL; | 1048 | return -EINVAL; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | pte = aper->arena->ptes[baddr >> PAGE_SHIFT]; | 1051 | pte = aper->arena->ptes[baddr >> PAGE_SHIFT]; |
1052 | if (!(pte & 1)) { | 1052 | if (!(pte & 1)) { |
1053 | printk("%s: pte not valid\n", __FUNCTION__); | 1053 | printk("%s: pte not valid\n", __func__); |
1054 | return -EINVAL; | 1054 | return -EINVAL; |
1055 | } | 1055 | } |
1056 | return (pte >> 1) << PAGE_SHIFT; | 1056 | return (pte >> 1) << PAGE_SHIFT; |
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c index f5ca5255eb06..c0750291b44a 100644 --- a/arch/alpha/kernel/core_t2.c +++ b/arch/alpha/kernel/core_t2.c | |||
@@ -336,10 +336,7 @@ t2_direct_map_window1(unsigned long base, unsigned long length) | |||
336 | 336 | ||
337 | #if DEBUG_PRINT_FINAL_SETTINGS | 337 | #if DEBUG_PRINT_FINAL_SETTINGS |
338 | printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", | 338 | printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", |
339 | __FUNCTION__, | 339 | __func__, *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1); |
340 | *(vulp)T2_WBASE1, | ||
341 | *(vulp)T2_WMASK1, | ||
342 | *(vulp)T2_TBASE1); | ||
343 | #endif | 340 | #endif |
344 | } | 341 | } |
345 | 342 | ||
@@ -366,10 +363,7 @@ t2_sg_map_window2(struct pci_controller *hose, | |||
366 | 363 | ||
367 | #if DEBUG_PRINT_FINAL_SETTINGS | 364 | #if DEBUG_PRINT_FINAL_SETTINGS |
368 | printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", | 365 | printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", |
369 | __FUNCTION__, | 366 | __func__, *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2); |
370 | *(vulp)T2_WBASE2, | ||
371 | *(vulp)T2_WMASK2, | ||
372 | *(vulp)T2_TBASE2); | ||
373 | #endif | 367 | #endif |
374 | } | 368 | } |
375 | 369 | ||
@@ -377,15 +371,15 @@ static void __init | |||
377 | t2_save_configuration(void) | 371 | t2_save_configuration(void) |
378 | { | 372 | { |
379 | #if DEBUG_PRINT_INITIAL_SETTINGS | 373 | #if DEBUG_PRINT_INITIAL_SETTINGS |
380 | printk("%s: HAE_1 was 0x%lx\n", __FUNCTION__, srm_hae); /* HW is 0 */ | 374 | printk("%s: HAE_1 was 0x%lx\n", __func__, srm_hae); /* HW is 0 */ |
381 | printk("%s: HAE_2 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_2); | 375 | printk("%s: HAE_2 was 0x%lx\n", __func__, *(vulp)T2_HAE_2); |
382 | printk("%s: HAE_3 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_3); | 376 | printk("%s: HAE_3 was 0x%lx\n", __func__, *(vulp)T2_HAE_3); |
383 | printk("%s: HAE_4 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_4); | 377 | printk("%s: HAE_4 was 0x%lx\n", __func__, *(vulp)T2_HAE_4); |
384 | printk("%s: HBASE was 0x%lx\n", __FUNCTION__, *(vulp)T2_HBASE); | 378 | printk("%s: HBASE was 0x%lx\n", __func__, *(vulp)T2_HBASE); |
385 | 379 | ||
386 | printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __FUNCTION__, | 380 | printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __func__, |
387 | *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1); | 381 | *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1); |
388 | printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __FUNCTION__, | 382 | printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __func__, |
389 | *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2); | 383 | *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2); |
390 | #endif | 384 | #endif |
391 | 385 | ||
diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c index 819326627b96..319fcb74611e 100644 --- a/arch/alpha/kernel/core_titan.c +++ b/arch/alpha/kernel/core_titan.c | |||
@@ -365,21 +365,21 @@ void __init | |||
365 | titan_init_arch(void) | 365 | titan_init_arch(void) |
366 | { | 366 | { |
367 | #if 0 | 367 | #if 0 |
368 | printk("%s: titan_init_arch()\n", __FUNCTION__); | 368 | printk("%s: titan_init_arch()\n", __func__); |
369 | printk("%s: CChip registers:\n", __FUNCTION__); | 369 | printk("%s: CChip registers:\n", __func__); |
370 | printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr); | 370 | printk("%s: CSR_CSC 0x%lx\n", __func__, TITAN_cchip->csc.csr); |
371 | printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr); | 371 | printk("%s: CSR_MTR 0x%lx\n", __func__, TITAN_cchip->mtr.csr); |
372 | printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr); | 372 | printk("%s: CSR_MISC 0x%lx\n", __func__, TITAN_cchip->misc.csr); |
373 | printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr); | 373 | printk("%s: CSR_DIM0 0x%lx\n", __func__, TITAN_cchip->dim0.csr); |
374 | printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr); | 374 | printk("%s: CSR_DIM1 0x%lx\n", __func__, TITAN_cchip->dim1.csr); |
375 | printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr); | 375 | printk("%s: CSR_DIR0 0x%lx\n", __func__, TITAN_cchip->dir0.csr); |
376 | printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr); | 376 | printk("%s: CSR_DIR1 0x%lx\n", __func__, TITAN_cchip->dir1.csr); |
377 | printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr); | 377 | printk("%s: CSR_DRIR 0x%lx\n", __func__, TITAN_cchip->drir.csr); |
378 | 378 | ||
379 | printk("%s: DChip registers:\n", __FUNCTION__); | 379 | printk("%s: DChip registers:\n", __func__); |
380 | printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr); | 380 | printk("%s: CSR_DSC 0x%lx\n", __func__, TITAN_dchip->dsc.csr); |
381 | printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr); | 381 | printk("%s: CSR_STR 0x%lx\n", __func__, TITAN_dchip->str.csr); |
382 | printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr); | 382 | printk("%s: CSR_DREV 0x%lx\n", __func__, TITAN_dchip->drev.csr); |
383 | #endif | 383 | #endif |
384 | 384 | ||
385 | boot_cpuid = __hard_smp_processor_id(); | 385 | boot_cpuid = __hard_smp_processor_id(); |
@@ -700,13 +700,13 @@ titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr) | |||
700 | 700 | ||
701 | if (addr < agp->aperture.bus_base || | 701 | if (addr < agp->aperture.bus_base || |
702 | addr >= agp->aperture.bus_base + agp->aperture.size) { | 702 | addr >= agp->aperture.bus_base + agp->aperture.size) { |
703 | printk("%s: addr out of range\n", __FUNCTION__); | 703 | printk("%s: addr out of range\n", __func__); |
704 | return -EINVAL; | 704 | return -EINVAL; |
705 | } | 705 | } |
706 | 706 | ||
707 | pte = aper->arena->ptes[baddr >> PAGE_SHIFT]; | 707 | pte = aper->arena->ptes[baddr >> PAGE_SHIFT]; |
708 | if (!(pte & 1)) { | 708 | if (!(pte & 1)) { |
709 | printk("%s: pte not valid\n", __FUNCTION__); | 709 | printk("%s: pte not valid\n", __func__); |
710 | return -EINVAL; | 710 | return -EINVAL; |
711 | } | 711 | } |
712 | 712 | ||
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index ef91e09590d4..5e7c28f92f19 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c | |||
@@ -241,8 +241,6 @@ tsunami_probe_write(volatile unsigned long *vaddr) | |||
241 | #define tsunami_probe_read(ADDR) 1 | 241 | #define tsunami_probe_read(ADDR) 1 |
242 | #endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */ | 242 | #endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */ |
243 | 243 | ||
244 | #define FN __FUNCTION__ | ||
245 | |||
246 | static void __init | 244 | static void __init |
247 | tsunami_init_one_pchip(tsunami_pchip *pchip, int index) | 245 | tsunami_init_one_pchip(tsunami_pchip *pchip, int index) |
248 | { | 246 | { |
@@ -383,27 +381,27 @@ tsunami_init_arch(void) | |||
383 | /* NXMs just don't matter to Tsunami--unless they make it | 381 | /* NXMs just don't matter to Tsunami--unless they make it |
384 | choke completely. */ | 382 | choke completely. */ |
385 | tmp = (unsigned long)(TSUNAMI_cchip - 1); | 383 | tmp = (unsigned long)(TSUNAMI_cchip - 1); |
386 | printk("%s: probing bogus address: 0x%016lx\n", FN, bogus_addr); | 384 | printk("%s: probing bogus address: 0x%016lx\n", __func__, bogus_addr); |
387 | printk("\tprobe %s\n", | 385 | printk("\tprobe %s\n", |
388 | tsunami_probe_write((unsigned long *)bogus_addr) | 386 | tsunami_probe_write((unsigned long *)bogus_addr) |
389 | ? "succeeded" : "failed"); | 387 | ? "succeeded" : "failed"); |
390 | #endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */ | 388 | #endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */ |
391 | 389 | ||
392 | #if 0 | 390 | #if 0 |
393 | printk("%s: CChip registers:\n", FN); | 391 | printk("%s: CChip registers:\n", __func__); |
394 | printk("%s: CSR_CSC 0x%lx\n", FN, TSUNAMI_cchip->csc.csr); | 392 | printk("%s: CSR_CSC 0x%lx\n", __func__, TSUNAMI_cchip->csc.csr); |
395 | printk("%s: CSR_MTR 0x%lx\n", FN, TSUNAMI_cchip.mtr.csr); | 393 | printk("%s: CSR_MTR 0x%lx\n", __func__, TSUNAMI_cchip.mtr.csr); |
396 | printk("%s: CSR_MISC 0x%lx\n", FN, TSUNAMI_cchip->misc.csr); | 394 | printk("%s: CSR_MISC 0x%lx\n", __func__, TSUNAMI_cchip->misc.csr); |
397 | printk("%s: CSR_DIM0 0x%lx\n", FN, TSUNAMI_cchip->dim0.csr); | 395 | printk("%s: CSR_DIM0 0x%lx\n", __func__, TSUNAMI_cchip->dim0.csr); |
398 | printk("%s: CSR_DIM1 0x%lx\n", FN, TSUNAMI_cchip->dim1.csr); | 396 | printk("%s: CSR_DIM1 0x%lx\n", __func__, TSUNAMI_cchip->dim1.csr); |
399 | printk("%s: CSR_DIR0 0x%lx\n", FN, TSUNAMI_cchip->dir0.csr); | 397 | printk("%s: CSR_DIR0 0x%lx\n", __func__, TSUNAMI_cchip->dir0.csr); |
400 | printk("%s: CSR_DIR1 0x%lx\n", FN, TSUNAMI_cchip->dir1.csr); | 398 | printk("%s: CSR_DIR1 0x%lx\n", __func__, TSUNAMI_cchip->dir1.csr); |
401 | printk("%s: CSR_DRIR 0x%lx\n", FN, TSUNAMI_cchip->drir.csr); | 399 | printk("%s: CSR_DRIR 0x%lx\n", __func__, TSUNAMI_cchip->drir.csr); |
402 | 400 | ||
403 | printk("%s: DChip registers:\n"); | 401 | printk("%s: DChip registers:\n"); |
404 | printk("%s: CSR_DSC 0x%lx\n", FN, TSUNAMI_dchip->dsc.csr); | 402 | printk("%s: CSR_DSC 0x%lx\n", __func__, TSUNAMI_dchip->dsc.csr); |
405 | printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr); | 403 | printk("%s: CSR_STR 0x%lx\n", __func__, TSUNAMI_dchip->str.csr); |
406 | printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr); | 404 | printk("%s: CSR_DREV 0x%lx\n", __func__, TSUNAMI_dchip->drev.csr); |
407 | #endif | 405 | #endif |
408 | /* With multiple PCI busses, we play with I/O as physical addrs. */ | 406 | /* With multiple PCI busses, we play with I/O as physical addrs. */ |
409 | ioport_resource.end = ~0UL; | 407 | ioport_resource.end = ~0UL; |
diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c index 026ba9af6d6a..ebc3c894b5a2 100644 --- a/arch/alpha/kernel/module.c +++ b/arch/alpha/kernel/module.c | |||
@@ -120,6 +120,12 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs, | |||
120 | 120 | ||
121 | nsyms = symtab->sh_size / sizeof(Elf64_Sym); | 121 | nsyms = symtab->sh_size / sizeof(Elf64_Sym); |
122 | chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL); | 122 | chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL); |
123 | if (!chains) { | ||
124 | printk(KERN_ERR | ||
125 | "module %s: no memory for symbol chain buffer\n", | ||
126 | me->name); | ||
127 | return -ENOMEM; | ||
128 | } | ||
123 | 129 | ||
124 | got->sh_size = 0; | 130 | got->sh_size = 0; |
125 | got->sh_addralign = 8; | 131 | got->sh_addralign = 8; |
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 78357798b6fd..36ab22a7ea12 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c | |||
@@ -208,7 +208,7 @@ pdev_save_srm_config(struct pci_dev *dev) | |||
208 | 208 | ||
209 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 209 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
210 | if (!tmp) { | 210 | if (!tmp) { |
211 | printk(KERN_ERR "%s: kmalloc() failed!\n", __FUNCTION__); | 211 | printk(KERN_ERR "%s: kmalloc() failed!\n", __func__); |
212 | return; | 212 | return; |
213 | } | 213 | } |
214 | tmp->next = srm_saved_configs; | 214 | tmp->next = srm_saved_configs; |
@@ -514,8 +514,8 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) | |||
514 | 514 | ||
515 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 515 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
516 | { | 516 | { |
517 | unsigned long start = pci_resource_start(dev, bar); | 517 | resource_size_t start = pci_resource_start(dev, bar); |
518 | unsigned long len = pci_resource_len(dev, bar); | 518 | resource_size_t len = pci_resource_len(dev, bar); |
519 | unsigned long flags = pci_resource_flags(dev, bar); | 519 | unsigned long flags = pci_resource_flags(dev, bar); |
520 | 520 | ||
521 | if (!len || !start) | 521 | if (!len || !start) |
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index dd6e334ab9e1..2179c602032a 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c | |||
@@ -79,25 +79,21 @@ iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base, | |||
79 | 79 | ||
80 | #ifdef CONFIG_DISCONTIGMEM | 80 | #ifdef CONFIG_DISCONTIGMEM |
81 | 81 | ||
82 | if (!NODE_DATA(nid) || | 82 | arena = alloc_bootmem_node(NODE_DATA(nid), sizeof(*arena)); |
83 | (NULL == (arena = alloc_bootmem_node(NODE_DATA(nid), | 83 | if (!NODE_DATA(nid) || !arena) { |
84 | sizeof(*arena))))) { | 84 | printk("%s: couldn't allocate arena from node %d\n" |
85 | printk("%s: couldn't allocate arena from node %d\n" | 85 | " falling back to system-wide allocation\n", |
86 | " falling back to system-wide allocation\n", | 86 | __func__, nid); |
87 | __FUNCTION__, nid); | 87 | arena = alloc_bootmem(sizeof(*arena)); |
88 | arena = alloc_bootmem(sizeof(*arena)); | 88 | } |
89 | } | 89 | |
90 | 90 | arena->ptes = __alloc_bootmem_node(NODE_DATA(nid), mem_size, align, 0); | |
91 | if (!NODE_DATA(nid) || | 91 | if (!NODE_DATA(nid) || !arena->ptes) { |
92 | (NULL == (arena->ptes = __alloc_bootmem_node(NODE_DATA(nid), | 92 | printk("%s: couldn't allocate arena ptes from node %d\n" |
93 | mem_size, | 93 | " falling back to system-wide allocation\n", |
94 | align, | 94 | __func__, nid); |
95 | 0)))) { | 95 | arena->ptes = __alloc_bootmem(mem_size, align, 0); |
96 | printk("%s: couldn't allocate arena ptes from node %d\n" | 96 | } |
97 | " falling back to system-wide allocation\n", | ||
98 | __FUNCTION__, nid); | ||
99 | arena->ptes = __alloc_bootmem(mem_size, align, 0); | ||
100 | } | ||
101 | 97 | ||
102 | #else /* CONFIG_DISCONTIGMEM */ | 98 | #else /* CONFIG_DISCONTIGMEM */ |
103 | 99 | ||
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 63c2073401ee..2525692db0ab 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c | |||
@@ -755,7 +755,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry, | |||
755 | if (atomic_read(&data.unstarted_count) > 0) { | 755 | if (atomic_read(&data.unstarted_count) > 0) { |
756 | long start_time = jiffies; | 756 | long start_time = jiffies; |
757 | printk(KERN_ERR "%s: initial timeout -- trying long wait\n", | 757 | printk(KERN_ERR "%s: initial timeout -- trying long wait\n", |
758 | __FUNCTION__); | 758 | __func__); |
759 | timeout = jiffies + 30 * HZ; | 759 | timeout = jiffies + 30 * HZ; |
760 | while (atomic_read(&data.unstarted_count) > 0 | 760 | while (atomic_read(&data.unstarted_count) > 0 |
761 | && time_before(jiffies, timeout)) | 761 | && time_before(jiffies, timeout)) |
@@ -764,7 +764,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry, | |||
764 | long delta = jiffies - start_time; | 764 | long delta = jiffies - start_time; |
765 | printk(KERN_ERR | 765 | printk(KERN_ERR |
766 | "%s: response %ld.%ld seconds into long wait\n", | 766 | "%s: response %ld.%ld seconds into long wait\n", |
767 | __FUNCTION__, delta / HZ, | 767 | __func__, delta / HZ, |
768 | (100 * (delta - ((delta / HZ) * HZ))) / HZ); | 768 | (100 * (delta - ((delta / HZ) * HZ))) / HZ); |
769 | } | 769 | } |
770 | } | 770 | } |
diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c index f7dd081d57ff..78ad7cd1bbd6 100644 --- a/arch/alpha/kernel/srm_env.c +++ b/arch/alpha/kernel/srm_env.c | |||
@@ -199,7 +199,7 @@ srm_env_init(void) | |||
199 | printk(KERN_INFO "%s: This Alpha system doesn't " | 199 | printk(KERN_INFO "%s: This Alpha system doesn't " |
200 | "know about SRM (or you've booted " | 200 | "know about SRM (or you've booted " |
201 | "SRM->MILO->Linux, which gets " | 201 | "SRM->MILO->Linux, which gets " |
202 | "misdetected)...\n", __FUNCTION__); | 202 | "misdetected)...\n", __func__); |
203 | return -ENODEV; | 203 | return -ENODEV; |
204 | } | 204 | } |
205 | 205 | ||
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index d187d01d2a17..e53a1e1c2f21 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c | |||
@@ -259,7 +259,7 @@ alcor_init_pci(void) | |||
259 | if (dev && dev->devfn == PCI_DEVFN(6,0)) { | 259 | if (dev && dev->devfn == PCI_DEVFN(6,0)) { |
260 | alpha_mv.sys.cia.gru_int_req_bits = XLT_GRU_INT_REQ_BITS; | 260 | alpha_mv.sys.cia.gru_int_req_bits = XLT_GRU_INT_REQ_BITS; |
261 | printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n", | 261 | printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n", |
262 | __FUNCTION__); | 262 | __func__); |
263 | } | 263 | } |
264 | pci_dev_put(dev); | 264 | pci_dev_put(dev); |
265 | } | 265 | } |
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index 922143ea1cdb..828449cd2636 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c | |||
@@ -80,7 +80,7 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7) | |||
80 | if (!(io7 = marvel_find_io7(pid))) { | 80 | if (!(io7 = marvel_find_io7(pid))) { |
81 | printk(KERN_ERR | 81 | printk(KERN_ERR |
82 | "%s for nonexistent io7 -- vec %x, pid %d\n", | 82 | "%s for nonexistent io7 -- vec %x, pid %d\n", |
83 | __FUNCTION__, irq, pid); | 83 | __func__, irq, pid); |
84 | return NULL; | 84 | return NULL; |
85 | } | 85 | } |
86 | 86 | ||
@@ -90,7 +90,7 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7) | |||
90 | if (irq >= 0x180) { | 90 | if (irq >= 0x180) { |
91 | printk(KERN_ERR | 91 | printk(KERN_ERR |
92 | "%s for invalid irq -- pid %d adjusted irq %x\n", | 92 | "%s for invalid irq -- pid %d adjusted irq %x\n", |
93 | __FUNCTION__, pid, irq); | 93 | __func__, pid, irq); |
94 | return NULL; | 94 | return NULL; |
95 | } | 95 | } |
96 | 96 | ||
@@ -110,8 +110,8 @@ io7_enable_irq(unsigned int irq) | |||
110 | 110 | ||
111 | ctl = io7_get_irq_ctl(irq, &io7); | 111 | ctl = io7_get_irq_ctl(irq, &io7); |
112 | if (!ctl || !io7) { | 112 | if (!ctl || !io7) { |
113 | printk(KERN_ERR "%s: get_ctl failed for irq %x\n", | 113 | printk(KERN_ERR "%s: get_ctl failed for irq %x\n", |
114 | __FUNCTION__, irq); | 114 | __func__, irq); |
115 | return; | 115 | return; |
116 | } | 116 | } |
117 | 117 | ||
@@ -130,8 +130,8 @@ io7_disable_irq(unsigned int irq) | |||
130 | 130 | ||
131 | ctl = io7_get_irq_ctl(irq, &io7); | 131 | ctl = io7_get_irq_ctl(irq, &io7); |
132 | if (!ctl || !io7) { | 132 | if (!ctl || !io7) { |
133 | printk(KERN_ERR "%s: get_ctl failed for irq %x\n", | 133 | printk(KERN_ERR "%s: get_ctl failed for irq %x\n", |
134 | __FUNCTION__, irq); | 134 | __func__, irq); |
135 | return; | 135 | return; |
136 | } | 136 | } |
137 | 137 | ||
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c index 906019cfa681..99a7f19da13a 100644 --- a/arch/alpha/kernel/sys_sable.c +++ b/arch/alpha/kernel/sys_sable.c | |||
@@ -454,7 +454,7 @@ sable_lynx_enable_irq(unsigned int irq) | |||
454 | spin_unlock(&sable_lynx_irq_lock); | 454 | spin_unlock(&sable_lynx_irq_lock); |
455 | #if 0 | 455 | #if 0 |
456 | printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n", | 456 | printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n", |
457 | __FUNCTION__, mask, bit, irq); | 457 | __func__, mask, bit, irq); |
458 | #endif | 458 | #endif |
459 | } | 459 | } |
460 | 460 | ||
@@ -470,7 +470,7 @@ sable_lynx_disable_irq(unsigned int irq) | |||
470 | spin_unlock(&sable_lynx_irq_lock); | 470 | spin_unlock(&sable_lynx_irq_lock); |
471 | #if 0 | 471 | #if 0 |
472 | printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n", | 472 | printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n", |
473 | __FUNCTION__, mask, bit, irq); | 473 | __func__, mask, bit, irq); |
474 | #endif | 474 | #endif |
475 | } | 475 | } |
476 | 476 | ||
@@ -524,7 +524,7 @@ sable_lynx_srm_device_interrupt(unsigned long vector) | |||
524 | irq = sable_lynx_irq_swizzle->mask_to_irq[bit]; | 524 | irq = sable_lynx_irq_swizzle->mask_to_irq[bit]; |
525 | #if 0 | 525 | #if 0 |
526 | printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n", | 526 | printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n", |
527 | __FUNCTION__, vector, bit, irq); | 527 | __func__, vector, bit, irq); |
528 | #endif | 528 | #endif |
529 | handle_irq(irq); | 529 | handle_irq(irq); |
530 | } | 530 | } |
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index ee7b9009ebb4..d4327e461c22 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c | |||
@@ -89,7 +89,7 @@ sio_pci_route(void) | |||
89 | /* First, ALWAYS read and print the original setting. */ | 89 | /* First, ALWAYS read and print the original setting. */ |
90 | pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, | 90 | pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, |
91 | &orig_route_tab); | 91 | &orig_route_tab); |
92 | printk("%s: PIRQ original 0x%x new 0x%x\n", __FUNCTION__, | 92 | printk("%s: PIRQ original 0x%x new 0x%x\n", __func__, |
93 | orig_route_tab, alpha_mv.sys.sio.route_tab); | 93 | orig_route_tab, alpha_mv.sys.sio.route_tab); |
94 | 94 | ||
95 | #if defined(ALPHA_RESTORE_SRM_SETUP) | 95 | #if defined(ALPHA_RESTORE_SRM_SETUP) |
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 2dc7f9fed213..dc57790250d2 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * This file initializes the trap entry points | 8 | * This file initializes the trap entry points |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/jiffies.h> | ||
11 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/tty.h> | 14 | #include <linux/tty.h> |
@@ -770,7 +771,7 @@ do_entUnaUser(void __user * va, unsigned long opcode, | |||
770 | unsigned long reg, struct pt_regs *regs) | 771 | unsigned long reg, struct pt_regs *regs) |
771 | { | 772 | { |
772 | static int cnt = 0; | 773 | static int cnt = 0; |
773 | static long last_time = 0; | 774 | static unsigned long last_time; |
774 | 775 | ||
775 | unsigned long tmp1, tmp2, tmp3, tmp4; | 776 | unsigned long tmp1, tmp2, tmp3, tmp4; |
776 | unsigned long fake_reg, *reg_addr = &fake_reg; | 777 | unsigned long fake_reg, *reg_addr = &fake_reg; |
@@ -781,7 +782,7 @@ do_entUnaUser(void __user * va, unsigned long opcode, | |||
781 | with the unaliged access. */ | 782 | with the unaliged access. */ |
782 | 783 | ||
783 | if (!test_thread_flag (TIF_UAC_NOPRINT)) { | 784 | if (!test_thread_flag (TIF_UAC_NOPRINT)) { |
784 | if (cnt >= 5 && jiffies - last_time > 5*HZ) { | 785 | if (cnt >= 5 && time_after(jiffies, last_time + 5 * HZ)) { |
785 | cnt = 0; | 786 | cnt = 0; |
786 | } | 787 | } |
787 | if (++cnt < 5) { | 788 | if (++cnt < 5) { |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d8d253285a94..b786e68914d4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" | |||
8 | config ARM | 8 | config ARM |
9 | bool | 9 | bool |
10 | default y | 10 | default y |
11 | select HAVE_IDE | ||
11 | select RTC_LIB | 12 | select RTC_LIB |
12 | select SYS_SUPPORTS_APM_EMULATION | 13 | select SYS_SUPPORTS_APM_EMULATION |
13 | select HAVE_OPROFILE | 14 | select HAVE_OPROFILE |
@@ -223,7 +224,6 @@ config ARCH_CLPS7500 | |||
223 | select TIMER_ACORN | 224 | select TIMER_ACORN |
224 | select ISA | 225 | select ISA |
225 | select NO_IOPORT | 226 | select NO_IOPORT |
226 | select HAVE_IDE | ||
227 | help | 227 | help |
228 | Support for the Cirrus Logic PS7500FE system-on-a-chip. | 228 | Support for the Cirrus Logic PS7500FE system-on-a-chip. |
229 | 229 | ||
@@ -236,7 +236,6 @@ config ARCH_CO285 | |||
236 | bool "Co-EBSA285" | 236 | bool "Co-EBSA285" |
237 | select FOOTBRIDGE | 237 | select FOOTBRIDGE |
238 | select FOOTBRIDGE_ADDIN | 238 | select FOOTBRIDGE_ADDIN |
239 | select HAVE_IDE | ||
240 | help | 239 | help |
241 | Support for Intel's EBSA285 companion chip. | 240 | Support for Intel's EBSA285 companion chip. |
242 | 241 | ||
@@ -262,7 +261,6 @@ config ARCH_EP93XX | |||
262 | config ARCH_FOOTBRIDGE | 261 | config ARCH_FOOTBRIDGE |
263 | bool "FootBridge" | 262 | bool "FootBridge" |
264 | select FOOTBRIDGE | 263 | select FOOTBRIDGE |
265 | select HAVE_IDE | ||
266 | help | 264 | help |
267 | Support for systems based on the DC21285 companion chip | 265 | Support for systems based on the DC21285 companion chip |
268 | ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. | 266 | ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. |
@@ -301,7 +299,6 @@ config ARCH_IOP32X | |||
301 | depends on MMU | 299 | depends on MMU |
302 | select PLAT_IOP | 300 | select PLAT_IOP |
303 | select PCI | 301 | select PCI |
304 | select HAVE_IDE | ||
305 | help | 302 | help |
306 | Support for Intel's 80219 and IOP32X (XScale) family of | 303 | Support for Intel's 80219 and IOP32X (XScale) family of |
307 | processors. | 304 | processors. |
@@ -311,14 +308,12 @@ config ARCH_IOP33X | |||
311 | depends on MMU | 308 | depends on MMU |
312 | select PLAT_IOP | 309 | select PLAT_IOP |
313 | select PCI | 310 | select PCI |
314 | select HAVE_IDE | ||
315 | help | 311 | help |
316 | Support for Intel's IOP33X (XScale) family of processors. | 312 | Support for Intel's IOP33X (XScale) family of processors. |
317 | 313 | ||
318 | config ARCH_IXP23XX | 314 | config ARCH_IXP23XX |
319 | bool "IXP23XX-based" | 315 | bool "IXP23XX-based" |
320 | depends on MMU | 316 | depends on MMU |
321 | select HAVE_IDE | ||
322 | select PCI | 317 | select PCI |
323 | help | 318 | help |
324 | Support for Intel's IXP23xx (XScale) family of processors. | 319 | Support for Intel's IXP23xx (XScale) family of processors. |
@@ -336,14 +331,12 @@ config ARCH_IXP4XX | |||
336 | select GENERIC_GPIO | 331 | select GENERIC_GPIO |
337 | select GENERIC_TIME | 332 | select GENERIC_TIME |
338 | select GENERIC_CLOCKEVENTS | 333 | select GENERIC_CLOCKEVENTS |
339 | select HAVE_IDE | ||
340 | help | 334 | help |
341 | Support for Intel's IXP4XX (XScale) family of processors. | 335 | Support for Intel's IXP4XX (XScale) family of processors. |
342 | 336 | ||
343 | config ARCH_L7200 | 337 | config ARCH_L7200 |
344 | bool "LinkUp-L7200" | 338 | bool "LinkUp-L7200" |
345 | select FIQ | 339 | select FIQ |
346 | select HAVE_IDE | ||
347 | help | 340 | help |
348 | Say Y here if you intend to run this kernel on a LinkUp Systems | 341 | Say Y here if you intend to run this kernel on a LinkUp Systems |
349 | L7200 Software Development Board which uses an ARM720T processor. | 342 | L7200 Software Development Board which uses an ARM720T processor. |
@@ -400,7 +393,6 @@ config ARCH_PXA | |||
400 | depends on MMU | 393 | depends on MMU |
401 | select ARCH_MTD_XIP | 394 | select ARCH_MTD_XIP |
402 | select GENERIC_GPIO | 395 | select GENERIC_GPIO |
403 | select HAVE_IDE | ||
404 | select HAVE_GPIO_LIB | 396 | select HAVE_GPIO_LIB |
405 | select GENERIC_TIME | 397 | select GENERIC_TIME |
406 | select GENERIC_CLOCKEVENTS | 398 | select GENERIC_CLOCKEVENTS |
@@ -416,7 +408,6 @@ config ARCH_RPC | |||
416 | select ARCH_MAY_HAVE_PC_FDC | 408 | select ARCH_MAY_HAVE_PC_FDC |
417 | select ISA_DMA_API | 409 | select ISA_DMA_API |
418 | select NO_IOPORT | 410 | select NO_IOPORT |
419 | select HAVE_IDE | ||
420 | help | 411 | help |
421 | On the Acorn Risc-PC, Linux can support the internal IDE disk and | 412 | On the Acorn Risc-PC, Linux can support the internal IDE disk and |
422 | CD-ROM interface, serial and parallel port, and the floppy drive. | 413 | CD-ROM interface, serial and parallel port, and the floppy drive. |
@@ -432,7 +423,6 @@ config ARCH_SA1100 | |||
432 | select GENERIC_TIME | 423 | select GENERIC_TIME |
433 | select GENERIC_CLOCKEVENTS | 424 | select GENERIC_CLOCKEVENTS |
434 | select TICK_ONESHOT | 425 | select TICK_ONESHOT |
435 | select HAVE_IDE | ||
436 | select HAVE_GPIO_LIB | 426 | select HAVE_GPIO_LIB |
437 | help | 427 | help |
438 | Support for StrongARM 11x0 based boards. | 428 | Support for StrongARM 11x0 based boards. |
@@ -440,7 +430,6 @@ config ARCH_SA1100 | |||
440 | config ARCH_S3C2410 | 430 | config ARCH_S3C2410 |
441 | bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443" | 431 | bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443" |
442 | select GENERIC_GPIO | 432 | select GENERIC_GPIO |
443 | select HAVE_IDE | ||
444 | help | 433 | help |
445 | Samsung S3C2410X CPU based systems, such as the Simtec Electronics | 434 | Samsung S3C2410X CPU based systems, such as the Simtec Electronics |
446 | BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or | 435 | BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or |
@@ -448,7 +437,6 @@ config ARCH_S3C2410 | |||
448 | 437 | ||
449 | config ARCH_SHARK | 438 | config ARCH_SHARK |
450 | bool "Shark" | 439 | bool "Shark" |
451 | select HAVE_IDE | ||
452 | select ISA | 440 | select ISA |
453 | select ISA_DMA | 441 | select ISA_DMA |
454 | select PCI | 442 | select PCI |
@@ -458,7 +446,6 @@ config ARCH_SHARK | |||
458 | 446 | ||
459 | config ARCH_LH7A40X | 447 | config ARCH_LH7A40X |
460 | bool "Sharp LH7A40X" | 448 | bool "Sharp LH7A40X" |
461 | select HAVE_IDE | ||
462 | help | 449 | help |
463 | Say Y here for systems based on one of the Sharp LH7A40X | 450 | Say Y here for systems based on one of the Sharp LH7A40X |
464 | System on a Chip processors. These CPUs include an ARM922T | 451 | System on a Chip processors. These CPUs include an ARM922T |
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 0a0d2479274b..4a881258bb17 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/thread_info.h> | 16 | #include <asm/thread_info.h> |
17 | #include <asm/memory.h> | 17 | #include <asm/memory.h> |
18 | #include <asm/procinfo.h> | 18 | #include <asm/procinfo.h> |
19 | #include <linux/kbuild.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * Make sure that the compiler and target are compatible. | 22 | * Make sure that the compiler and target are compatible. |
@@ -35,13 +36,6 @@ | |||
35 | #error Known good compilers: 3.3 | 36 | #error Known good compilers: 3.3 |
36 | #endif | 37 | #endif |
37 | 38 | ||
38 | /* Use marker if you need to separate the values later */ | ||
39 | |||
40 | #define DEFINE(sym, val) \ | ||
41 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
42 | |||
43 | #define BLANK() asm volatile("\n->" : : ) | ||
44 | |||
45 | int main(void) | 39 | int main(void) |
46 | { | 40 | { |
47 | DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); | 41 | DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); |
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c index e2e934c38080..64c420805e6f 100644 --- a/arch/arm/kernel/atags.c +++ b/arch/arm/kernel/atags.c | |||
@@ -35,7 +35,7 @@ create_proc_entries(void) | |||
35 | { | 35 | { |
36 | struct proc_dir_entry* tags_entry; | 36 | struct proc_dir_entry* tags_entry; |
37 | 37 | ||
38 | tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer); | 38 | tags_entry = create_proc_read_entry("atags", 0400, NULL, read_buffer, &tags_buffer); |
39 | if (!tags_entry) | 39 | if (!tags_entry) |
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | 41 | ||
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index f56d48c451ea..a53c0aba5c14 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/mm.h> | 37 | #include <linux/mm.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/proc_fs.h> | 39 | #include <linux/proc_fs.h> |
40 | #include <linux/seq_file.h> | ||
40 | #include <linux/device.h> | 41 | #include <linux/device.h> |
41 | #include <linux/init.h> | 42 | #include <linux/init.h> |
42 | #include <linux/mutex.h> | 43 | #include <linux/mutex.h> |
@@ -723,17 +724,14 @@ unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) | |||
723 | return address; | 724 | return address; |
724 | } | 725 | } |
725 | 726 | ||
726 | static int ecard_prints(char *buffer, ecard_t *ec) | 727 | static int ecard_prints(struct seq_file *m, ecard_t *ec) |
727 | { | 728 | { |
728 | char *start = buffer; | 729 | seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " "); |
729 | |||
730 | buffer += sprintf(buffer, " %d: %s ", ec->slot_no, | ||
731 | ec->easi ? "EASI" : " "); | ||
732 | 730 | ||
733 | if (ec->cid.id == 0) { | 731 | if (ec->cid.id == 0) { |
734 | struct in_chunk_dir incd; | 732 | struct in_chunk_dir incd; |
735 | 733 | ||
736 | buffer += sprintf(buffer, "[%04X:%04X] ", | 734 | seq_printf(m, "[%04X:%04X] ", |
737 | ec->cid.manufacturer, ec->cid.product); | 735 | ec->cid.manufacturer, ec->cid.product); |
738 | 736 | ||
739 | if (!ec->card_desc && ec->cid.cd && | 737 | if (!ec->card_desc && ec->cid.cd && |
@@ -744,43 +742,43 @@ static int ecard_prints(char *buffer, ecard_t *ec) | |||
744 | strcpy((char *)ec->card_desc, incd.d.string); | 742 | strcpy((char *)ec->card_desc, incd.d.string); |
745 | } | 743 | } |
746 | 744 | ||
747 | buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); | 745 | seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); |
748 | } else | 746 | } else |
749 | buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); | 747 | seq_printf(m, "Simple card %d\n", ec->cid.id); |
750 | 748 | ||
751 | return buffer - start; | 749 | return 0; |
752 | } | 750 | } |
753 | 751 | ||
754 | static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count) | 752 | static int ecard_devices_proc_show(struct seq_file *m, void *v) |
755 | { | 753 | { |
756 | ecard_t *ec = cards; | 754 | ecard_t *ec = cards; |
757 | off_t at = 0; | 755 | |
758 | int len, cnt; | 756 | while (ec) { |
759 | 757 | ecard_prints(m, ec); | |
760 | cnt = 0; | ||
761 | while (ec && count > cnt) { | ||
762 | len = ecard_prints(buf, ec); | ||
763 | at += len; | ||
764 | if (at >= pos) { | ||
765 | if (!*start) { | ||
766 | *start = buf + (pos - (at - len)); | ||
767 | cnt = at - pos; | ||
768 | } else | ||
769 | cnt += len; | ||
770 | buf += len; | ||
771 | } | ||
772 | ec = ec->next; | 758 | ec = ec->next; |
773 | } | 759 | } |
774 | return (count > cnt) ? cnt : count; | 760 | return 0; |
775 | } | 761 | } |
776 | 762 | ||
763 | static int ecard_devices_proc_open(struct inode *inode, struct file *file) | ||
764 | { | ||
765 | return single_open(file, ecard_devices_proc_show, NULL); | ||
766 | } | ||
767 | |||
768 | static const struct file_operations bus_ecard_proc_fops = { | ||
769 | .owner = THIS_MODULE, | ||
770 | .open = ecard_devices_proc_open, | ||
771 | .read = seq_read, | ||
772 | .llseek = seq_lseek, | ||
773 | .release = single_release, | ||
774 | }; | ||
775 | |||
777 | static struct proc_dir_entry *proc_bus_ecard_dir = NULL; | 776 | static struct proc_dir_entry *proc_bus_ecard_dir = NULL; |
778 | 777 | ||
779 | static void ecard_proc_init(void) | 778 | static void ecard_proc_init(void) |
780 | { | 779 | { |
781 | proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus); | 780 | proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL); |
782 | create_proc_info_entry("devices", 0, proc_bus_ecard_dir, | 781 | proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops); |
783 | get_ecard_dev_info); | ||
784 | } | 782 | } |
785 | 783 | ||
786 | #define ec_set_resource(ec,nr,st,sz) \ | 784 | #define ec_set_resource(ec,nr,st,sz) \ |
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 37cd547855b1..728bb8f39441 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c | |||
@@ -539,6 +539,17 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) | |||
539 | at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */ | 539 | at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */ |
540 | #endif | 540 | #endif |
541 | 541 | ||
542 | if (ARRAY_SIZE(lcdc_resources) > 2) { | ||
543 | void __iomem *fb; | ||
544 | struct resource *fb_res = &lcdc_resources[2]; | ||
545 | size_t fb_len = fb_res->end - fb_res->start + 1; | ||
546 | |||
547 | fb = ioremap_writecombine(fb_res->start, fb_len); | ||
548 | if (fb) { | ||
549 | memset(fb, 0, fb_len); | ||
550 | iounmap(fb, fb_len); | ||
551 | } | ||
552 | } | ||
542 | lcdc_data = *data; | 553 | lcdc_data = *data; |
543 | platform_device_register(&at91_lcdc_device); | 554 | platform_device_register(&at91_lcdc_device); |
544 | } | 555 | } |
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index dbb9a5fc2090..054689804e77 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c | |||
@@ -381,6 +381,20 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) | |||
381 | at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */ | 381 | at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */ |
382 | at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */ | 382 | at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */ |
383 | 383 | ||
384 | #ifdef CONFIG_FB_INTSRAM | ||
385 | { | ||
386 | void __iomem *fb; | ||
387 | struct resource *fb_res = &lcdc_resources[2]; | ||
388 | size_t fb_len = fb_res->end - fb_res->start + 1; | ||
389 | |||
390 | fb = ioremap_writecombine(fb_res->start, fb_len); | ||
391 | if (fb) { | ||
392 | memset(fb, 0, fb_len); | ||
393 | iounmap(fb, fb_len); | ||
394 | } | ||
395 | } | ||
396 | #endif | ||
397 | |||
384 | lcdc_data = *data; | 398 | lcdc_data = *data; |
385 | platform_device_register(&at91_lcdc_device); | 399 | platform_device_register(&at91_lcdc_device); |
386 | } | 400 | } |
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 4143828a9684..c6b94f60e0b2 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c | |||
@@ -311,11 +311,7 @@ static const struct file_operations proc_davinci_ck_operations = { | |||
311 | 311 | ||
312 | static int __init davinci_ck_proc_init(void) | 312 | static int __init davinci_ck_proc_init(void) |
313 | { | 313 | { |
314 | struct proc_dir_entry *entry; | 314 | proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations); |
315 | |||
316 | entry = create_proc_entry("davinci_clocks", 0, NULL); | ||
317 | if (entry) | ||
318 | entry->proc_fops = &proc_davinci_ck_operations; | ||
319 | return 0; | 315 | return 0; |
320 | 316 | ||
321 | } | 317 | } |
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c index 62066f3020c8..7429f8c01015 100644 --- a/arch/arm/mm/iomap.c +++ b/arch/arm/mm/iomap.c | |||
@@ -26,8 +26,8 @@ EXPORT_SYMBOL(ioport_unmap); | |||
26 | #ifdef CONFIG_PCI | 26 | #ifdef CONFIG_PCI |
27 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 27 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
28 | { | 28 | { |
29 | unsigned long start = pci_resource_start(dev, bar); | 29 | resource_size_t start = pci_resource_start(dev, bar); |
30 | unsigned long len = pci_resource_len(dev, bar); | 30 | resource_size_t len = pci_resource_len(dev, bar); |
31 | unsigned long flags = pci_resource_flags(dev, bar); | 31 | unsigned long flags = pci_resource_flags(dev, bar); |
32 | 32 | ||
33 | if (!len || !start) | 33 | if (!len || !start) |
diff --git a/arch/avr32/kernel/asm-offsets.c b/arch/avr32/kernel/asm-offsets.c index 078cd33f467b..e4796c67a831 100644 --- a/arch/avr32/kernel/asm-offsets.c +++ b/arch/avr32/kernel/asm-offsets.c | |||
@@ -5,14 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/thread_info.h> | 7 | #include <linux/thread_info.h> |
8 | 8 | #include <linux/kbuild.h> | |
9 | #define DEFINE(sym, val) \ | ||
10 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
11 | |||
12 | #define BLANK() asm volatile("\n->" : : ) | ||
13 | |||
14 | #define OFFSET(sym, str, mem) \ | ||
15 | DEFINE(sym, offsetof(struct str, mem)); | ||
16 | 9 | ||
17 | void foo(void) | 10 | void foo(void) |
18 | { | 11 | { |
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index 2687b730e2d0..ce48c14f4349 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c | |||
@@ -274,6 +274,8 @@ static int __init early_parse_fbmem(char *p) | |||
274 | printk(KERN_WARNING | 274 | printk(KERN_WARNING |
275 | "Failed to allocate framebuffer memory\n"); | 275 | "Failed to allocate framebuffer memory\n"); |
276 | fbmem_size = 0; | 276 | fbmem_size = 0; |
277 | } else { | ||
278 | memset(__va(fbmem_start), 0, fbmem_size); | ||
277 | } | 279 | } |
278 | } | 280 | } |
279 | 281 | ||
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c index b835257a8fa3..cd12edbea9f2 100644 --- a/arch/avr32/mm/tlb.c +++ b/arch/avr32/mm/tlb.c | |||
@@ -369,11 +369,7 @@ static const struct file_operations proc_tlb_operations = { | |||
369 | 369 | ||
370 | static int __init proctlb_init(void) | 370 | static int __init proctlb_init(void) |
371 | { | 371 | { |
372 | struct proc_dir_entry *entry; | 372 | proc_create("tlb", 0, NULL, &proc_tlb_operations); |
373 | |||
374 | entry = create_proc_entry("tlb", 0, NULL); | ||
375 | if (entry) | ||
376 | entry->proc_fops = &proc_tlb_operations; | ||
377 | return 0; | 373 | return 0; |
378 | } | 374 | } |
379 | late_initcall(proctlb_init); | 375 | late_initcall(proctlb_init); |
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c index b56b2741cdea..721f15f3cebf 100644 --- a/arch/blackfin/kernel/asm-offsets.c +++ b/arch/blackfin/kernel/asm-offsets.c | |||
@@ -34,8 +34,7 @@ | |||
34 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
35 | #include <linux/irq.h> | 35 | #include <linux/irq.h> |
36 | #include <linux/thread_info.h> | 36 | #include <linux/thread_info.h> |
37 | 37 | #include <linux/kbuild.h> | |
38 | #define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
39 | 38 | ||
40 | int main(void) | 39 | int main(void) |
41 | { | 40 | { |
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index d1fa24401dc6..cb9d883d493c 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c | |||
@@ -212,7 +212,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, | |||
212 | 212 | ||
213 | /* Set up registers for signal handler */ | 213 | /* Set up registers for signal handler */ |
214 | wrusp((unsigned long)frame); | 214 | wrusp((unsigned long)frame); |
215 | if (get_personality & FDPIC_FUNCPTRS) { | 215 | if (current->personality & FDPIC_FUNCPTRS) { |
216 | struct fdpic_func_descriptor __user *funcptr = | 216 | struct fdpic_func_descriptor __user *funcptr = |
217 | (struct fdpic_func_descriptor *) ka->sa.sa_handler; | 217 | (struct fdpic_func_descriptor *) ka->sa.sa_handler; |
218 | __get_user(regs->pc, &funcptr->text); | 218 | __get_user(regs->pc, &funcptr->text); |
diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c index aad0a9e5991a..44f7b4f79476 100644 --- a/arch/cris/kernel/profile.c +++ b/arch/cris/kernel/profile.c | |||
@@ -75,9 +75,9 @@ __init init_cris_profile(void) | |||
75 | 75 | ||
76 | sample_buffer_pos = sample_buffer; | 76 | sample_buffer_pos = sample_buffer; |
77 | 77 | ||
78 | entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL); | 78 | entry = proc_create("system_profile", S_IWUSR | S_IRUGO, NULL, |
79 | &cris_proc_profile_operations); | ||
79 | if (entry) { | 80 | if (entry) { |
80 | entry->proc_fops = &cris_proc_profile_operations; | ||
81 | entry->size = SAMPLE_BUFFER_SIZE; | 81 | entry->size = SAMPLE_BUFFER_SIZE; |
82 | } | 82 | } |
83 | prof_running = 1; | 83 | prof_running = 1; |
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c index 4207a2b52750..5b06ffa15e34 100644 --- a/arch/cris/mm/init.c +++ b/arch/cris/mm/init.c | |||
@@ -27,7 +27,6 @@ show_mem(void) | |||
27 | 27 | ||
28 | printk("\nMem-info:\n"); | 28 | printk("\nMem-info:\n"); |
29 | show_free_areas(); | 29 | show_free_areas(); |
30 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | ||
31 | i = max_mapnr; | 30 | i = max_mapnr; |
32 | while (i-- > 0) { | 31 | while (i-- > 0) { |
33 | total++; | 32 | total++; |
diff --git a/arch/frv/kernel/asm-offsets.c b/arch/frv/kernel/asm-offsets.c index fbb19fc1af40..9de96843a278 100644 --- a/arch/frv/kernel/asm-offsets.c +++ b/arch/frv/kernel/asm-offsets.c | |||
@@ -7,15 +7,13 @@ | |||
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/signal.h> | 8 | #include <linux/signal.h> |
9 | #include <linux/personality.h> | 9 | #include <linux/personality.h> |
10 | #include <linux/kbuild.h> | ||
10 | #include <asm/registers.h> | 11 | #include <asm/registers.h> |
11 | #include <asm/ucontext.h> | 12 | #include <asm/ucontext.h> |
12 | #include <asm/processor.h> | 13 | #include <asm/processor.h> |
13 | #include <asm/thread_info.h> | 14 | #include <asm/thread_info.h> |
14 | #include <asm/gdb-stub.h> | 15 | #include <asm/gdb-stub.h> |
15 | 16 | ||
16 | #define DEFINE(sym, val) \ | ||
17 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
18 | |||
19 | #define DEF_PTREG(sym, reg) \ | 17 | #define DEF_PTREG(sym, reg) \ |
20 | asm volatile("\n->" #sym " %0 offsetof(struct pt_regs, " #reg ")" \ | 18 | asm volatile("\n->" #sym " %0 offsetof(struct pt_regs, " #reg ")" \ |
21 | : : "i" (offsetof(struct pt_regs, reg))) | 19 | : : "i" (offsetof(struct pt_regs, reg))) |
@@ -32,11 +30,6 @@ | |||
32 | asm volatile("\n->" #sym " %0 offsetof(struct frv_frame0, " #reg ")" \ | 30 | asm volatile("\n->" #sym " %0 offsetof(struct frv_frame0, " #reg ")" \ |
33 | : : "i" (offsetof(struct frv_frame0, reg))) | 31 | : : "i" (offsetof(struct frv_frame0, reg))) |
34 | 32 | ||
35 | #define BLANK() asm volatile("\n->" : : ) | ||
36 | |||
37 | #define OFFSET(sym, str, mem) \ | ||
38 | DEFINE(sym, offsetof(struct str, mem)); | ||
39 | |||
40 | void foo(void) | 33 | void foo(void) |
41 | { | 34 | { |
42 | /* offsets into the thread_info structure */ | 35 | /* offsets into the thread_info structure */ |
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index d64bcaff54cd..3bdb368292a8 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
@@ -297,7 +297,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | |||
297 | __frame->lr = (unsigned long) &frame->retcode; | 297 | __frame->lr = (unsigned long) &frame->retcode; |
298 | __frame->gr8 = sig; | 298 | __frame->gr8 = sig; |
299 | 299 | ||
300 | if (get_personality & FDPIC_FUNCPTRS) { | 300 | if (current->personality & FDPIC_FUNCPTRS) { |
301 | struct fdpic_func_descriptor __user *funcptr = | 301 | struct fdpic_func_descriptor __user *funcptr = |
302 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 302 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
303 | __get_user(__frame->pc, &funcptr->text); | 303 | __get_user(__frame->pc, &funcptr->text); |
@@ -396,7 +396,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
396 | __frame->gr8 = sig; | 396 | __frame->gr8 = sig; |
397 | __frame->gr9 = (unsigned long) &frame->info; | 397 | __frame->gr9 = (unsigned long) &frame->info; |
398 | 398 | ||
399 | if (get_personality & FDPIC_FUNCPTRS) { | 399 | if (current->personality & FDPIC_FUNCPTRS) { |
400 | struct fdpic_func_descriptor __user *funcptr = | 400 | struct fdpic_func_descriptor __user *funcptr = |
401 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 401 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
402 | __get_user(__frame->pc, &funcptr->text); | 402 | __get_user(__frame->pc, &funcptr->text); |
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c index 7089c2428b3f..1d2dfe67d442 100644 --- a/arch/frv/kernel/traps.c +++ b/arch/frv/kernel/traps.c | |||
@@ -49,7 +49,7 @@ asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsi | |||
49 | info.si_signo = SIGSEGV; | 49 | info.si_signo = SIGSEGV; |
50 | info.si_code = SEGV_ACCERR; | 50 | info.si_code = SEGV_ACCERR; |
51 | info.si_errno = 0; | 51 | info.si_errno = 0; |
52 | info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); | 52 | info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); |
53 | 53 | ||
54 | force_sig_info(info.si_signo, &info, current); | 54 | force_sig_info(info.si_signo, &info, current); |
55 | } /* end insn_access_error() */ | 55 | } /* end insn_access_error() */ |
@@ -73,7 +73,7 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un | |||
73 | epcr0, esr0, esfr1); | 73 | epcr0, esr0, esfr1); |
74 | 74 | ||
75 | info.si_errno = 0; | 75 | info.si_errno = 0; |
76 | info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); | 76 | info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); |
77 | 77 | ||
78 | switch (__frame->tbr & TBR_TT) { | 78 | switch (__frame->tbr & TBR_TT) { |
79 | case TBR_TT_ILLEGAL_INSTR: | 79 | case TBR_TT_ILLEGAL_INSTR: |
@@ -111,7 +111,8 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
111 | unsigned long esr0) | 111 | unsigned long esr0) |
112 | { | 112 | { |
113 | static DEFINE_SPINLOCK(atomic_op_lock); | 113 | static DEFINE_SPINLOCK(atomic_op_lock); |
114 | unsigned long x, y, z, *p; | 114 | unsigned long x, y, z; |
115 | unsigned long __user *p; | ||
115 | mm_segment_t oldfs; | 116 | mm_segment_t oldfs; |
116 | siginfo_t info; | 117 | siginfo_t info; |
117 | int ret; | 118 | int ret; |
@@ -128,7 +129,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
128 | * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new) | 129 | * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new) |
129 | */ | 130 | */ |
130 | case TBR_TT_ATOMIC_CMPXCHG32: | 131 | case TBR_TT_ATOMIC_CMPXCHG32: |
131 | p = (unsigned long *) __frame->gr8; | 132 | p = (unsigned long __user *) __frame->gr8; |
132 | x = __frame->gr9; | 133 | x = __frame->gr9; |
133 | y = __frame->gr10; | 134 | y = __frame->gr10; |
134 | 135 | ||
@@ -158,7 +159,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
158 | * u32 __atomic_kernel_xchg32(void *v, u32 new) | 159 | * u32 __atomic_kernel_xchg32(void *v, u32 new) |
159 | */ | 160 | */ |
160 | case TBR_TT_ATOMIC_XCHG32: | 161 | case TBR_TT_ATOMIC_XCHG32: |
161 | p = (unsigned long *) __frame->gr8; | 162 | p = (unsigned long __user *) __frame->gr8; |
162 | y = __frame->gr9; | 163 | y = __frame->gr9; |
163 | 164 | ||
164 | for (;;) { | 165 | for (;;) { |
@@ -181,7 +182,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
181 | * ulong __atomic_kernel_XOR_return(ulong i, ulong *v) | 182 | * ulong __atomic_kernel_XOR_return(ulong i, ulong *v) |
182 | */ | 183 | */ |
183 | case TBR_TT_ATOMIC_XOR: | 184 | case TBR_TT_ATOMIC_XOR: |
184 | p = (unsigned long *) __frame->gr8; | 185 | p = (unsigned long __user *) __frame->gr8; |
185 | x = __frame->gr9; | 186 | x = __frame->gr9; |
186 | 187 | ||
187 | for (;;) { | 188 | for (;;) { |
@@ -205,7 +206,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
205 | * ulong __atomic_kernel_OR_return(ulong i, ulong *v) | 206 | * ulong __atomic_kernel_OR_return(ulong i, ulong *v) |
206 | */ | 207 | */ |
207 | case TBR_TT_ATOMIC_OR: | 208 | case TBR_TT_ATOMIC_OR: |
208 | p = (unsigned long *) __frame->gr8; | 209 | p = (unsigned long __user *) __frame->gr8; |
209 | x = __frame->gr9; | 210 | x = __frame->gr9; |
210 | 211 | ||
211 | for (;;) { | 212 | for (;;) { |
@@ -229,7 +230,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
229 | * ulong __atomic_kernel_AND_return(ulong i, ulong *v) | 230 | * ulong __atomic_kernel_AND_return(ulong i, ulong *v) |
230 | */ | 231 | */ |
231 | case TBR_TT_ATOMIC_AND: | 232 | case TBR_TT_ATOMIC_AND: |
232 | p = (unsigned long *) __frame->gr8; | 233 | p = (unsigned long __user *) __frame->gr8; |
233 | x = __frame->gr9; | 234 | x = __frame->gr9; |
234 | 235 | ||
235 | for (;;) { | 236 | for (;;) { |
@@ -253,7 +254,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
253 | * int __atomic_user_sub_return(atomic_t *v, int i) | 254 | * int __atomic_user_sub_return(atomic_t *v, int i) |
254 | */ | 255 | */ |
255 | case TBR_TT_ATOMIC_SUB: | 256 | case TBR_TT_ATOMIC_SUB: |
256 | p = (unsigned long *) __frame->gr8; | 257 | p = (unsigned long __user *) __frame->gr8; |
257 | x = __frame->gr9; | 258 | x = __frame->gr9; |
258 | 259 | ||
259 | for (;;) { | 260 | for (;;) { |
@@ -277,7 +278,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0, | |||
277 | * int __atomic_user_add_return(atomic_t *v, int i) | 278 | * int __atomic_user_add_return(atomic_t *v, int i) |
278 | */ | 279 | */ |
279 | case TBR_TT_ATOMIC_ADD: | 280 | case TBR_TT_ATOMIC_ADD: |
280 | p = (unsigned long *) __frame->gr8; | 281 | p = (unsigned long __user *) __frame->gr8; |
281 | x = __frame->gr9; | 282 | x = __frame->gr9; |
282 | 283 | ||
283 | for (;;) { | 284 | for (;;) { |
@@ -322,7 +323,7 @@ error: | |||
322 | info.si_signo = SIGSEGV; | 323 | info.si_signo = SIGSEGV; |
323 | info.si_code = SEGV_ACCERR; | 324 | info.si_code = SEGV_ACCERR; |
324 | info.si_errno = 0; | 325 | info.si_errno = 0; |
325 | info.si_addr = (void *) __frame->pc; | 326 | info.si_addr = (void __user *) __frame->pc; |
326 | 327 | ||
327 | force_sig_info(info.si_signo, &info, current); | 328 | force_sig_info(info.si_signo, &info, current); |
328 | } | 329 | } |
@@ -343,7 +344,7 @@ asmlinkage void media_exception(unsigned long msr0, unsigned long msr1) | |||
343 | info.si_signo = SIGFPE; | 344 | info.si_signo = SIGFPE; |
344 | info.si_code = FPE_MDAOVF; | 345 | info.si_code = FPE_MDAOVF; |
345 | info.si_errno = 0; | 346 | info.si_errno = 0; |
346 | info.si_addr = (void *) __frame->pc; | 347 | info.si_addr = (void __user *) __frame->pc; |
347 | 348 | ||
348 | force_sig_info(info.si_signo, &info, current); | 349 | force_sig_info(info.si_signo, &info, current); |
349 | } /* end media_exception() */ | 350 | } /* end media_exception() */ |
@@ -361,11 +362,8 @@ asmlinkage void memory_access_exception(unsigned long esr0, | |||
361 | #ifdef CONFIG_MMU | 362 | #ifdef CONFIG_MMU |
362 | unsigned long fixup; | 363 | unsigned long fixup; |
363 | 364 | ||
364 | if ((esr0 & ESRx_EC) == ESRx_EC_DATA_ACCESS) | 365 | fixup = search_exception_table(__frame->pc); |
365 | if (handle_misalignment(esr0, ear0, epcr0) == 0) | 366 | if (fixup) { |
366 | return; | ||
367 | |||
368 | if ((fixup = search_exception_table(__frame->pc)) != 0) { | ||
369 | __frame->pc = fixup; | 367 | __frame->pc = fixup; |
370 | return; | 368 | return; |
371 | } | 369 | } |
@@ -383,7 +381,7 @@ asmlinkage void memory_access_exception(unsigned long esr0, | |||
383 | info.si_addr = NULL; | 381 | info.si_addr = NULL; |
384 | 382 | ||
385 | if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV)) | 383 | if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV)) |
386 | info.si_addr = (void *) ear0; | 384 | info.si_addr = (void __user *) ear0; |
387 | 385 | ||
388 | force_sig_info(info.si_signo, &info, current); | 386 | force_sig_info(info.si_signo, &info, current); |
389 | 387 | ||
@@ -412,7 +410,7 @@ asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsi | |||
412 | info.si_signo = SIGSEGV; | 410 | info.si_signo = SIGSEGV; |
413 | info.si_code = SEGV_ACCERR; | 411 | info.si_code = SEGV_ACCERR; |
414 | info.si_errno = 0; | 412 | info.si_errno = 0; |
415 | info.si_addr = (void *) | 413 | info.si_addr = (void __user *) |
416 | (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); | 414 | (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); |
417 | 415 | ||
418 | force_sig_info(info.si_signo, &info, current); | 416 | force_sig_info(info.si_signo, &info, current); |
@@ -446,7 +444,7 @@ asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsi | |||
446 | info.si_signo = SIGFPE; | 444 | info.si_signo = SIGFPE; |
447 | info.si_code = FPE_INTDIV; | 445 | info.si_code = FPE_INTDIV; |
448 | info.si_errno = 0; | 446 | info.si_errno = 0; |
449 | info.si_addr = (void *) __frame->pc; | 447 | info.si_addr = (void __user *) __frame->pc; |
450 | 448 | ||
451 | force_sig_info(info.si_signo, &info, current); | 449 | force_sig_info(info.si_signo, &info, current); |
452 | } /* end division_exception() */ | 450 | } /* end division_exception() */ |
diff --git a/arch/frv/mb93090-mb00/pci-iomap.c b/arch/frv/mb93090-mb00/pci-iomap.c index 068fa04bd527..35f6df28351e 100644 --- a/arch/frv/mb93090-mb00/pci-iomap.c +++ b/arch/frv/mb93090-mb00/pci-iomap.c | |||
@@ -13,8 +13,8 @@ | |||
13 | 13 | ||
14 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 14 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
15 | { | 15 | { |
16 | unsigned long start = pci_resource_start(dev, bar); | 16 | resource_size_t start = pci_resource_start(dev, bar); |
17 | unsigned long len = pci_resource_len(dev, bar); | 17 | resource_size_t len = pci_resource_len(dev, bar); |
18 | unsigned long flags = pci_resource_flags(dev, bar); | 18 | unsigned long flags = pci_resource_flags(dev, bar); |
19 | 19 | ||
20 | if (!len || !start) | 20 | if (!len || !start) |
diff --git a/arch/frv/mm/unaligned.c b/arch/frv/mm/unaligned.c deleted file mode 100644 index 8f0375fc15a8..000000000000 --- a/arch/frv/mm/unaligned.c +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | /* unaligned.c: unalignment fixup handler for CPUs on which it is supported (FR451 only) | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | #include <linux/signal.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/user.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/linkage.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/system.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | |||
26 | #if 0 | ||
27 | #define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ ) | ||
28 | #else | ||
29 | #define kdebug(fmt, ...) do {} while(0) | ||
30 | #endif | ||
31 | |||
32 | #define _MA_SIGNED 0x01 | ||
33 | #define _MA_HALF 0x02 | ||
34 | #define _MA_WORD 0x04 | ||
35 | #define _MA_DWORD 0x08 | ||
36 | #define _MA_SZ_MASK 0x0e | ||
37 | #define _MA_LOAD 0x10 | ||
38 | #define _MA_STORE 0x20 | ||
39 | #define _MA_UPDATE 0x40 | ||
40 | #define _MA_IMM 0x80 | ||
41 | |||
42 | #define _MA_LDxU _MA_LOAD | _MA_UPDATE | ||
43 | #define _MA_LDxI _MA_LOAD | _MA_IMM | ||
44 | #define _MA_STxU _MA_STORE | _MA_UPDATE | ||
45 | #define _MA_STxI _MA_STORE | _MA_IMM | ||
46 | |||
47 | static const uint8_t tbl_LDGRk_reg[0x40] = { | ||
48 | [0x02] = _MA_LOAD | _MA_HALF | _MA_SIGNED, /* LDSH @(GRi,GRj),GRk */ | ||
49 | [0x03] = _MA_LOAD | _MA_HALF, /* LDUH @(GRi,GRj),GRk */ | ||
50 | [0x04] = _MA_LOAD | _MA_WORD, /* LD @(GRi,GRj),GRk */ | ||
51 | [0x05] = _MA_LOAD | _MA_DWORD, /* LDD @(GRi,GRj),GRk */ | ||
52 | [0x12] = _MA_LDxU | _MA_HALF | _MA_SIGNED, /* LDSHU @(GRi,GRj),GRk */ | ||
53 | [0x13] = _MA_LDxU | _MA_HALF, /* LDUHU @(GRi,GRj),GRk */ | ||
54 | [0x14] = _MA_LDxU | _MA_WORD, /* LDU @(GRi,GRj),GRk */ | ||
55 | [0x15] = _MA_LDxU | _MA_DWORD, /* LDDU @(GRi,GRj),GRk */ | ||
56 | }; | ||
57 | |||
58 | static const uint8_t tbl_STGRk_reg[0x40] = { | ||
59 | [0x01] = _MA_STORE | _MA_HALF, /* STH @(GRi,GRj),GRk */ | ||
60 | [0x02] = _MA_STORE | _MA_WORD, /* ST @(GRi,GRj),GRk */ | ||
61 | [0x03] = _MA_STORE | _MA_DWORD, /* STD @(GRi,GRj),GRk */ | ||
62 | [0x11] = _MA_STxU | _MA_HALF, /* STHU @(GRi,GRj),GRk */ | ||
63 | [0x12] = _MA_STxU | _MA_WORD, /* STU @(GRi,GRj),GRk */ | ||
64 | [0x13] = _MA_STxU | _MA_DWORD, /* STDU @(GRi,GRj),GRk */ | ||
65 | }; | ||
66 | |||
67 | static const uint8_t tbl_LDSTGRk_imm[0x80] = { | ||
68 | [0x31] = _MA_LDxI | _MA_HALF | _MA_SIGNED, /* LDSHI @(GRi,d12),GRk */ | ||
69 | [0x32] = _MA_LDxI | _MA_WORD, /* LDI @(GRi,d12),GRk */ | ||
70 | [0x33] = _MA_LDxI | _MA_DWORD, /* LDDI @(GRi,d12),GRk */ | ||
71 | [0x36] = _MA_LDxI | _MA_HALF, /* LDUHI @(GRi,d12),GRk */ | ||
72 | [0x51] = _MA_STxI | _MA_HALF, /* STHI @(GRi,d12),GRk */ | ||
73 | [0x52] = _MA_STxI | _MA_WORD, /* STI @(GRi,d12),GRk */ | ||
74 | [0x53] = _MA_STxI | _MA_DWORD, /* STDI @(GRi,d12),GRk */ | ||
75 | }; | ||
76 | |||
77 | |||
78 | /*****************************************************************************/ | ||
79 | /* | ||
80 | * see if we can handle the exception by fixing up a misaligned memory access | ||
81 | */ | ||
82 | int handle_misalignment(unsigned long esr0, unsigned long ear0, unsigned long epcr0) | ||
83 | { | ||
84 | unsigned long insn, addr, *greg; | ||
85 | int GRi, GRj, GRk, D12, op; | ||
86 | |||
87 | union { | ||
88 | uint64_t _64; | ||
89 | uint32_t _32[2]; | ||
90 | uint16_t _16; | ||
91 | uint8_t _8[8]; | ||
92 | } x; | ||
93 | |||
94 | if (!(esr0 & ESR0_EAV) || !(epcr0 & EPCR0_V) || !(ear0 & 7)) | ||
95 | return -EAGAIN; | ||
96 | |||
97 | epcr0 &= EPCR0_PC; | ||
98 | |||
99 | if (__frame->pc != epcr0) { | ||
100 | kdebug("MISALIGN: Execution not halted on excepting instruction\n"); | ||
101 | BUG(); | ||
102 | } | ||
103 | |||
104 | if (__get_user(insn, (unsigned long *) epcr0) < 0) | ||
105 | return -EFAULT; | ||
106 | |||
107 | /* determine the instruction type first */ | ||
108 | switch ((insn >> 18) & 0x7f) { | ||
109 | case 0x2: | ||
110 | /* LDx @(GRi,GRj),GRk */ | ||
111 | op = tbl_LDGRk_reg[(insn >> 6) & 0x3f]; | ||
112 | break; | ||
113 | |||
114 | case 0x3: | ||
115 | /* STx GRk,@(GRi,GRj) */ | ||
116 | op = tbl_STGRk_reg[(insn >> 6) & 0x3f]; | ||
117 | break; | ||
118 | |||
119 | default: | ||
120 | op = tbl_LDSTGRk_imm[(insn >> 18) & 0x7f]; | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | if (!op) | ||
125 | return -EAGAIN; | ||
126 | |||
127 | kdebug("MISALIGN: pc=%08lx insn=%08lx ad=%08lx op=%02x\n", epcr0, insn, ear0, op); | ||
128 | |||
129 | memset(&x, 0xba, 8); | ||
130 | |||
131 | /* validate the instruction parameters */ | ||
132 | greg = (unsigned long *) &__frame->tbr; | ||
133 | |||
134 | GRi = (insn >> 12) & 0x3f; | ||
135 | GRk = (insn >> 25) & 0x3f; | ||
136 | |||
137 | if (GRi > 31 || GRk > 31) | ||
138 | return -ENOENT; | ||
139 | |||
140 | if (op & _MA_DWORD && GRk & 1) | ||
141 | return -EINVAL; | ||
142 | |||
143 | if (op & _MA_IMM) { | ||
144 | D12 = insn & 0xfff; | ||
145 | asm ("slli %0,#20,%0 ! srai %0,#20,%0" : "=r"(D12) : "0"(D12)); /* sign extend */ | ||
146 | addr = (GRi ? greg[GRi] : 0) + D12; | ||
147 | } | ||
148 | else { | ||
149 | GRj = (insn >> 0) & 0x3f; | ||
150 | if (GRj > 31) | ||
151 | return -ENOENT; | ||
152 | addr = (GRi ? greg[GRi] : 0) + (GRj ? greg[GRj] : 0); | ||
153 | } | ||
154 | |||
155 | if (addr != ear0) { | ||
156 | kdebug("MISALIGN: Calculated addr (%08lx) does not match EAR0 (%08lx)\n", | ||
157 | addr, ear0); | ||
158 | return -EFAULT; | ||
159 | } | ||
160 | |||
161 | /* check the address is okay */ | ||
162 | if (user_mode(__frame) && ___range_ok(ear0, 8) < 0) | ||
163 | return -EFAULT; | ||
164 | |||
165 | /* perform the memory op */ | ||
166 | if (op & _MA_STORE) { | ||
167 | /* perform a store */ | ||
168 | x._32[0] = 0; | ||
169 | if (GRk != 0) { | ||
170 | if (op & _MA_HALF) { | ||
171 | x._16 = greg[GRk]; | ||
172 | } | ||
173 | else { | ||
174 | x._32[0] = greg[GRk]; | ||
175 | } | ||
176 | } | ||
177 | if (op & _MA_DWORD) | ||
178 | x._32[1] = greg[GRk + 1]; | ||
179 | |||
180 | kdebug("MISALIGN: Store GR%d { %08x:%08x } -> %08lx (%dB)\n", | ||
181 | GRk, x._32[1], x._32[0], addr, op & _MA_SZ_MASK); | ||
182 | |||
183 | if (__memcpy_user((void *) addr, &x, op & _MA_SZ_MASK) != 0) | ||
184 | return -EFAULT; | ||
185 | } | ||
186 | else { | ||
187 | /* perform a load */ | ||
188 | if (__memcpy_user(&x, (void *) addr, op & _MA_SZ_MASK) != 0) | ||
189 | return -EFAULT; | ||
190 | |||
191 | if (op & _MA_HALF) { | ||
192 | if (op & _MA_SIGNED) | ||
193 | asm ("slli %0,#16,%0 ! srai %0,#16,%0" | ||
194 | : "=r"(x._32[0]) : "0"(x._16)); | ||
195 | else | ||
196 | asm ("sethi #0,%0" | ||
197 | : "=r"(x._32[0]) : "0"(x._16)); | ||
198 | } | ||
199 | |||
200 | kdebug("MISALIGN: Load %08lx (%dB) -> GR%d, { %08x:%08x }\n", | ||
201 | addr, op & _MA_SZ_MASK, GRk, x._32[1], x._32[0]); | ||
202 | |||
203 | if (GRk != 0) | ||
204 | greg[GRk] = x._32[0]; | ||
205 | if (op & _MA_DWORD) | ||
206 | greg[GRk + 1] = x._32[1]; | ||
207 | } | ||
208 | |||
209 | /* update the base pointer if required */ | ||
210 | if (op & _MA_UPDATE) | ||
211 | greg[GRi] = addr; | ||
212 | |||
213 | /* well... we've done that insn */ | ||
214 | __frame->pc = __frame->pc + 4; | ||
215 | |||
216 | return 0; | ||
217 | } /* end handle_misalignment() */ | ||
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c index fc30b4fd0914..2042552e0871 100644 --- a/arch/h8300/kernel/asm-offsets.c +++ b/arch/h8300/kernel/asm-offsets.c | |||
@@ -13,15 +13,11 @@ | |||
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/ptrace.h> | 14 | #include <linux/ptrace.h> |
15 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
16 | #include <linux/kbuild.h> | ||
16 | #include <asm/bootinfo.h> | 17 | #include <asm/bootinfo.h> |
17 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
18 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
19 | 20 | ||
20 | #define DEFINE(sym, val) \ | ||
21 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
22 | |||
23 | #define BLANK() asm volatile("\n->" : : ) | ||
24 | |||
25 | int main(void) | 21 | int main(void) |
26 | { | 22 | { |
27 | /* offsets into the task struct */ | 23 | /* offsets into the task struct */ |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index cd13e138bd03..0df5f6f75edf 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -19,6 +19,8 @@ config IA64 | |||
19 | select HAVE_OPROFILE | 19 | select HAVE_OPROFILE |
20 | select HAVE_KPROBES | 20 | select HAVE_KPROBES |
21 | select HAVE_KRETPROBES | 21 | select HAVE_KRETPROBES |
22 | select HAVE_DMA_ATTRS | ||
23 | select HAVE_KVM | ||
22 | default y | 24 | default y |
23 | help | 25 | help |
24 | The Itanium Processor Family is Intel's 64-bit successor to | 26 | The Itanium Processor Family is Intel's 64-bit successor to |
@@ -46,6 +48,9 @@ config MMU | |||
46 | config SWIOTLB | 48 | config SWIOTLB |
47 | bool | 49 | bool |
48 | 50 | ||
51 | config IOMMU_HELPER | ||
52 | bool | ||
53 | |||
49 | config GENERIC_LOCKBREAK | 54 | config GENERIC_LOCKBREAK |
50 | bool | 55 | bool |
51 | default y | 56 | default y |
@@ -589,6 +594,8 @@ config MSPEC | |||
589 | 594 | ||
590 | source "fs/Kconfig" | 595 | source "fs/Kconfig" |
591 | 596 | ||
597 | source "arch/ia64/kvm/Kconfig" | ||
598 | |||
592 | source "lib/Kconfig" | 599 | source "lib/Kconfig" |
593 | 600 | ||
594 | # | 601 | # |
@@ -612,7 +619,7 @@ config IRQ_PER_CPU | |||
612 | default y | 619 | default y |
613 | 620 | ||
614 | config IOMMU_HELPER | 621 | config IOMMU_HELPER |
615 | def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC) | 622 | def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB) |
616 | 623 | ||
617 | source "arch/ia64/hp/sim/Kconfig" | 624 | source "arch/ia64/hp/sim/Kconfig" |
618 | 625 | ||
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index f1645c4f7039..ec4cca477f49 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile | |||
@@ -57,6 +57,7 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ | |||
57 | core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ | 57 | core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ |
58 | core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ | 58 | core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ |
59 | core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ | 59 | core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ |
60 | core-$(CONFIG_KVM) += arch/ia64/kvm/ | ||
60 | 61 | ||
61 | drivers-$(CONFIG_PCI) += arch/ia64/pci/ | 62 | drivers-$(CONFIG_PCI) += arch/ia64/pci/ |
62 | drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ | 63 | drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ |
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index 8f6bcfe1dada..1c44ec2a1d58 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ b/arch/ia64/hp/common/hwsw_iommu.c | |||
@@ -20,10 +20,10 @@ | |||
20 | extern int swiotlb_late_init_with_default_size (size_t size); | 20 | extern int swiotlb_late_init_with_default_size (size_t size); |
21 | extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; | 21 | extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; |
22 | extern ia64_mv_dma_free_coherent swiotlb_free_coherent; | 22 | extern ia64_mv_dma_free_coherent swiotlb_free_coherent; |
23 | extern ia64_mv_dma_map_single swiotlb_map_single; | 23 | extern ia64_mv_dma_map_single_attrs swiotlb_map_single_attrs; |
24 | extern ia64_mv_dma_unmap_single swiotlb_unmap_single; | 24 | extern ia64_mv_dma_unmap_single_attrs swiotlb_unmap_single_attrs; |
25 | extern ia64_mv_dma_map_sg swiotlb_map_sg; | 25 | extern ia64_mv_dma_map_sg_attrs swiotlb_map_sg_attrs; |
26 | extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg; | 26 | extern ia64_mv_dma_unmap_sg_attrs swiotlb_unmap_sg_attrs; |
27 | extern ia64_mv_dma_supported swiotlb_dma_supported; | 27 | extern ia64_mv_dma_supported swiotlb_dma_supported; |
28 | extern ia64_mv_dma_mapping_error swiotlb_dma_mapping_error; | 28 | extern ia64_mv_dma_mapping_error swiotlb_dma_mapping_error; |
29 | 29 | ||
@@ -31,19 +31,19 @@ extern ia64_mv_dma_mapping_error swiotlb_dma_mapping_error; | |||
31 | 31 | ||
32 | extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; | 32 | extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; |
33 | extern ia64_mv_dma_free_coherent sba_free_coherent; | 33 | extern ia64_mv_dma_free_coherent sba_free_coherent; |
34 | extern ia64_mv_dma_map_single sba_map_single; | 34 | extern ia64_mv_dma_map_single_attrs sba_map_single_attrs; |
35 | extern ia64_mv_dma_unmap_single sba_unmap_single; | 35 | extern ia64_mv_dma_unmap_single_attrs sba_unmap_single_attrs; |
36 | extern ia64_mv_dma_map_sg sba_map_sg; | 36 | extern ia64_mv_dma_map_sg_attrs sba_map_sg_attrs; |
37 | extern ia64_mv_dma_unmap_sg sba_unmap_sg; | 37 | extern ia64_mv_dma_unmap_sg_attrs sba_unmap_sg_attrs; |
38 | extern ia64_mv_dma_supported sba_dma_supported; | 38 | extern ia64_mv_dma_supported sba_dma_supported; |
39 | extern ia64_mv_dma_mapping_error sba_dma_mapping_error; | 39 | extern ia64_mv_dma_mapping_error sba_dma_mapping_error; |
40 | 40 | ||
41 | #define hwiommu_alloc_coherent sba_alloc_coherent | 41 | #define hwiommu_alloc_coherent sba_alloc_coherent |
42 | #define hwiommu_free_coherent sba_free_coherent | 42 | #define hwiommu_free_coherent sba_free_coherent |
43 | #define hwiommu_map_single sba_map_single | 43 | #define hwiommu_map_single_attrs sba_map_single_attrs |
44 | #define hwiommu_unmap_single sba_unmap_single | 44 | #define hwiommu_unmap_single_attrs sba_unmap_single_attrs |
45 | #define hwiommu_map_sg sba_map_sg | 45 | #define hwiommu_map_sg_attrs sba_map_sg_attrs |
46 | #define hwiommu_unmap_sg sba_unmap_sg | 46 | #define hwiommu_unmap_sg_attrs sba_unmap_sg_attrs |
47 | #define hwiommu_dma_supported sba_dma_supported | 47 | #define hwiommu_dma_supported sba_dma_supported |
48 | #define hwiommu_dma_mapping_error sba_dma_mapping_error | 48 | #define hwiommu_dma_mapping_error sba_dma_mapping_error |
49 | #define hwiommu_sync_single_for_cpu machvec_dma_sync_single | 49 | #define hwiommu_sync_single_for_cpu machvec_dma_sync_single |
@@ -98,41 +98,48 @@ hwsw_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma | |||
98 | } | 98 | } |
99 | 99 | ||
100 | dma_addr_t | 100 | dma_addr_t |
101 | hwsw_map_single (struct device *dev, void *addr, size_t size, int dir) | 101 | hwsw_map_single_attrs(struct device *dev, void *addr, size_t size, int dir, |
102 | struct dma_attrs *attrs) | ||
102 | { | 103 | { |
103 | if (use_swiotlb(dev)) | 104 | if (use_swiotlb(dev)) |
104 | return swiotlb_map_single(dev, addr, size, dir); | 105 | return swiotlb_map_single_attrs(dev, addr, size, dir, attrs); |
105 | else | 106 | else |
106 | return hwiommu_map_single(dev, addr, size, dir); | 107 | return hwiommu_map_single_attrs(dev, addr, size, dir, attrs); |
107 | } | 108 | } |
109 | EXPORT_SYMBOL(hwsw_map_single_attrs); | ||
108 | 110 | ||
109 | void | 111 | void |
110 | hwsw_unmap_single (struct device *dev, dma_addr_t iova, size_t size, int dir) | 112 | hwsw_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size, |
113 | int dir, struct dma_attrs *attrs) | ||
111 | { | 114 | { |
112 | if (use_swiotlb(dev)) | 115 | if (use_swiotlb(dev)) |
113 | return swiotlb_unmap_single(dev, iova, size, dir); | 116 | return swiotlb_unmap_single_attrs(dev, iova, size, dir, attrs); |
114 | else | 117 | else |
115 | return hwiommu_unmap_single(dev, iova, size, dir); | 118 | return hwiommu_unmap_single_attrs(dev, iova, size, dir, attrs); |
116 | } | 119 | } |
117 | 120 | EXPORT_SYMBOL(hwsw_unmap_single_attrs); | |
118 | 121 | ||
119 | int | 122 | int |
120 | hwsw_map_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) | 123 | hwsw_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents, |
124 | int dir, struct dma_attrs *attrs) | ||
121 | { | 125 | { |
122 | if (use_swiotlb(dev)) | 126 | if (use_swiotlb(dev)) |
123 | return swiotlb_map_sg(dev, sglist, nents, dir); | 127 | return swiotlb_map_sg_attrs(dev, sglist, nents, dir, attrs); |
124 | else | 128 | else |
125 | return hwiommu_map_sg(dev, sglist, nents, dir); | 129 | return hwiommu_map_sg_attrs(dev, sglist, nents, dir, attrs); |
126 | } | 130 | } |
131 | EXPORT_SYMBOL(hwsw_map_sg_attrs); | ||
127 | 132 | ||
128 | void | 133 | void |
129 | hwsw_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) | 134 | hwsw_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents, |
135 | int dir, struct dma_attrs *attrs) | ||
130 | { | 136 | { |
131 | if (use_swiotlb(dev)) | 137 | if (use_swiotlb(dev)) |
132 | return swiotlb_unmap_sg(dev, sglist, nents, dir); | 138 | return swiotlb_unmap_sg_attrs(dev, sglist, nents, dir, attrs); |
133 | else | 139 | else |
134 | return hwiommu_unmap_sg(dev, sglist, nents, dir); | 140 | return hwiommu_unmap_sg_attrs(dev, sglist, nents, dir, attrs); |
135 | } | 141 | } |
142 | EXPORT_SYMBOL(hwsw_unmap_sg_attrs); | ||
136 | 143 | ||
137 | void | 144 | void |
138 | hwsw_sync_single_for_cpu (struct device *dev, dma_addr_t addr, size_t size, int dir) | 145 | hwsw_sync_single_for_cpu (struct device *dev, dma_addr_t addr, size_t size, int dir) |
@@ -185,10 +192,6 @@ hwsw_dma_mapping_error (dma_addr_t dma_addr) | |||
185 | } | 192 | } |
186 | 193 | ||
187 | EXPORT_SYMBOL(hwsw_dma_mapping_error); | 194 | EXPORT_SYMBOL(hwsw_dma_mapping_error); |
188 | EXPORT_SYMBOL(hwsw_map_single); | ||
189 | EXPORT_SYMBOL(hwsw_unmap_single); | ||
190 | EXPORT_SYMBOL(hwsw_map_sg); | ||
191 | EXPORT_SYMBOL(hwsw_unmap_sg); | ||
192 | EXPORT_SYMBOL(hwsw_dma_supported); | 195 | EXPORT_SYMBOL(hwsw_dma_supported); |
193 | EXPORT_SYMBOL(hwsw_alloc_coherent); | 196 | EXPORT_SYMBOL(hwsw_alloc_coherent); |
194 | EXPORT_SYMBOL(hwsw_free_coherent); | 197 | EXPORT_SYMBOL(hwsw_free_coherent); |
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 9409de5c9441..34421aed1e2a 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c | |||
@@ -899,16 +899,18 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) | |||
899 | } | 899 | } |
900 | 900 | ||
901 | /** | 901 | /** |
902 | * sba_map_single - map one buffer and return IOVA for DMA | 902 | * sba_map_single_attrs - map one buffer and return IOVA for DMA |
903 | * @dev: instance of PCI owned by the driver that's asking. | 903 | * @dev: instance of PCI owned by the driver that's asking. |
904 | * @addr: driver buffer to map. | 904 | * @addr: driver buffer to map. |
905 | * @size: number of bytes to map in driver buffer. | 905 | * @size: number of bytes to map in driver buffer. |
906 | * @dir: R/W or both. | 906 | * @dir: R/W or both. |
907 | * @attrs: optional dma attributes | ||
907 | * | 908 | * |
908 | * See Documentation/DMA-mapping.txt | 909 | * See Documentation/DMA-mapping.txt |
909 | */ | 910 | */ |
910 | dma_addr_t | 911 | dma_addr_t |
911 | sba_map_single(struct device *dev, void *addr, size_t size, int dir) | 912 | sba_map_single_attrs(struct device *dev, void *addr, size_t size, int dir, |
913 | struct dma_attrs *attrs) | ||
912 | { | 914 | { |
913 | struct ioc *ioc; | 915 | struct ioc *ioc; |
914 | dma_addr_t iovp; | 916 | dma_addr_t iovp; |
@@ -932,7 +934,8 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir) | |||
932 | ** Device is bit capable of DMA'ing to the buffer... | 934 | ** Device is bit capable of DMA'ing to the buffer... |
933 | ** just return the PCI address of ptr | 935 | ** just return the PCI address of ptr |
934 | */ | 936 | */ |
935 | DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n", | 937 | DBG_BYPASS("sba_map_single_attrs() bypass mask/addr: " |
938 | "0x%lx/0x%lx\n", | ||
936 | to_pci_dev(dev)->dma_mask, pci_addr); | 939 | to_pci_dev(dev)->dma_mask, pci_addr); |
937 | return pci_addr; | 940 | return pci_addr; |
938 | } | 941 | } |
@@ -953,7 +956,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir) | |||
953 | 956 | ||
954 | #ifdef ASSERT_PDIR_SANITY | 957 | #ifdef ASSERT_PDIR_SANITY |
955 | spin_lock_irqsave(&ioc->res_lock, flags); | 958 | spin_lock_irqsave(&ioc->res_lock, flags); |
956 | if (sba_check_pdir(ioc,"Check before sba_map_single()")) | 959 | if (sba_check_pdir(ioc,"Check before sba_map_single_attrs()")) |
957 | panic("Sanity check failed"); | 960 | panic("Sanity check failed"); |
958 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 961 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
959 | #endif | 962 | #endif |
@@ -982,11 +985,12 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir) | |||
982 | /* form complete address */ | 985 | /* form complete address */ |
983 | #ifdef ASSERT_PDIR_SANITY | 986 | #ifdef ASSERT_PDIR_SANITY |
984 | spin_lock_irqsave(&ioc->res_lock, flags); | 987 | spin_lock_irqsave(&ioc->res_lock, flags); |
985 | sba_check_pdir(ioc,"Check after sba_map_single()"); | 988 | sba_check_pdir(ioc,"Check after sba_map_single_attrs()"); |
986 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 989 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
987 | #endif | 990 | #endif |
988 | return SBA_IOVA(ioc, iovp, offset); | 991 | return SBA_IOVA(ioc, iovp, offset); |
989 | } | 992 | } |
993 | EXPORT_SYMBOL(sba_map_single_attrs); | ||
990 | 994 | ||
991 | #ifdef ENABLE_MARK_CLEAN | 995 | #ifdef ENABLE_MARK_CLEAN |
992 | static SBA_INLINE void | 996 | static SBA_INLINE void |
@@ -1013,15 +1017,17 @@ sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size) | |||
1013 | #endif | 1017 | #endif |
1014 | 1018 | ||
1015 | /** | 1019 | /** |
1016 | * sba_unmap_single - unmap one IOVA and free resources | 1020 | * sba_unmap_single_attrs - unmap one IOVA and free resources |
1017 | * @dev: instance of PCI owned by the driver that's asking. | 1021 | * @dev: instance of PCI owned by the driver that's asking. |
1018 | * @iova: IOVA of driver buffer previously mapped. | 1022 | * @iova: IOVA of driver buffer previously mapped. |
1019 | * @size: number of bytes mapped in driver buffer. | 1023 | * @size: number of bytes mapped in driver buffer. |
1020 | * @dir: R/W or both. | 1024 | * @dir: R/W or both. |
1025 | * @attrs: optional dma attributes | ||
1021 | * | 1026 | * |
1022 | * See Documentation/DMA-mapping.txt | 1027 | * See Documentation/DMA-mapping.txt |
1023 | */ | 1028 | */ |
1024 | void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) | 1029 | void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size, |
1030 | int dir, struct dma_attrs *attrs) | ||
1025 | { | 1031 | { |
1026 | struct ioc *ioc; | 1032 | struct ioc *ioc; |
1027 | #if DELAYED_RESOURCE_CNT > 0 | 1033 | #if DELAYED_RESOURCE_CNT > 0 |
@@ -1038,7 +1044,8 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) | |||
1038 | /* | 1044 | /* |
1039 | ** Address does not fall w/in IOVA, must be bypassing | 1045 | ** Address does not fall w/in IOVA, must be bypassing |
1040 | */ | 1046 | */ |
1041 | DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova); | 1047 | DBG_BYPASS("sba_unmap_single_atttrs() bypass addr: 0x%lx\n", |
1048 | iova); | ||
1042 | 1049 | ||
1043 | #ifdef ENABLE_MARK_CLEAN | 1050 | #ifdef ENABLE_MARK_CLEAN |
1044 | if (dir == DMA_FROM_DEVICE) { | 1051 | if (dir == DMA_FROM_DEVICE) { |
@@ -1087,7 +1094,7 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) | |||
1087 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1094 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1088 | #endif /* DELAYED_RESOURCE_CNT == 0 */ | 1095 | #endif /* DELAYED_RESOURCE_CNT == 0 */ |
1089 | } | 1096 | } |
1090 | 1097 | EXPORT_SYMBOL(sba_unmap_single_attrs); | |
1091 | 1098 | ||
1092 | /** | 1099 | /** |
1093 | * sba_alloc_coherent - allocate/map shared mem for DMA | 1100 | * sba_alloc_coherent - allocate/map shared mem for DMA |
@@ -1144,7 +1151,8 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp | |||
1144 | * If device can't bypass or bypass is disabled, pass the 32bit fake | 1151 | * If device can't bypass or bypass is disabled, pass the 32bit fake |
1145 | * device to map single to get an iova mapping. | 1152 | * device to map single to get an iova mapping. |
1146 | */ | 1153 | */ |
1147 | *dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0); | 1154 | *dma_handle = sba_map_single_attrs(&ioc->sac_only_dev->dev, addr, |
1155 | size, 0, NULL); | ||
1148 | 1156 | ||
1149 | return addr; | 1157 | return addr; |
1150 | } | 1158 | } |
@@ -1161,7 +1169,7 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp | |||
1161 | */ | 1169 | */ |
1162 | void sba_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) | 1170 | void sba_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) |
1163 | { | 1171 | { |
1164 | sba_unmap_single(dev, dma_handle, size, 0); | 1172 | sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL); |
1165 | free_pages((unsigned long) vaddr, get_order(size)); | 1173 | free_pages((unsigned long) vaddr, get_order(size)); |
1166 | } | 1174 | } |
1167 | 1175 | ||
@@ -1410,10 +1418,12 @@ sba_coalesce_chunks(struct ioc *ioc, struct device *dev, | |||
1410 | * @sglist: array of buffer/length pairs | 1418 | * @sglist: array of buffer/length pairs |
1411 | * @nents: number of entries in list | 1419 | * @nents: number of entries in list |
1412 | * @dir: R/W or both. | 1420 | * @dir: R/W or both. |
1421 | * @attrs: optional dma attributes | ||
1413 | * | 1422 | * |
1414 | * See Documentation/DMA-mapping.txt | 1423 | * See Documentation/DMA-mapping.txt |
1415 | */ | 1424 | */ |
1416 | int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int dir) | 1425 | int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents, |
1426 | int dir, struct dma_attrs *attrs) | ||
1417 | { | 1427 | { |
1418 | struct ioc *ioc; | 1428 | struct ioc *ioc; |
1419 | int coalesced, filled = 0; | 1429 | int coalesced, filled = 0; |
@@ -1441,16 +1451,16 @@ int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int di | |||
1441 | /* Fast path single entry scatterlists. */ | 1451 | /* Fast path single entry scatterlists. */ |
1442 | if (nents == 1) { | 1452 | if (nents == 1) { |
1443 | sglist->dma_length = sglist->length; | 1453 | sglist->dma_length = sglist->length; |
1444 | sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length, dir); | 1454 | sglist->dma_address = sba_map_single_attrs(dev, sba_sg_address(sglist), sglist->length, dir, attrs); |
1445 | return 1; | 1455 | return 1; |
1446 | } | 1456 | } |
1447 | 1457 | ||
1448 | #ifdef ASSERT_PDIR_SANITY | 1458 | #ifdef ASSERT_PDIR_SANITY |
1449 | spin_lock_irqsave(&ioc->res_lock, flags); | 1459 | spin_lock_irqsave(&ioc->res_lock, flags); |
1450 | if (sba_check_pdir(ioc,"Check before sba_map_sg()")) | 1460 | if (sba_check_pdir(ioc,"Check before sba_map_sg_attrs()")) |
1451 | { | 1461 | { |
1452 | sba_dump_sg(ioc, sglist, nents); | 1462 | sba_dump_sg(ioc, sglist, nents); |
1453 | panic("Check before sba_map_sg()"); | 1463 | panic("Check before sba_map_sg_attrs()"); |
1454 | } | 1464 | } |
1455 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1465 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1456 | #endif | 1466 | #endif |
@@ -1479,10 +1489,10 @@ int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int di | |||
1479 | 1489 | ||
1480 | #ifdef ASSERT_PDIR_SANITY | 1490 | #ifdef ASSERT_PDIR_SANITY |
1481 | spin_lock_irqsave(&ioc->res_lock, flags); | 1491 | spin_lock_irqsave(&ioc->res_lock, flags); |
1482 | if (sba_check_pdir(ioc,"Check after sba_map_sg()")) | 1492 | if (sba_check_pdir(ioc,"Check after sba_map_sg_attrs()")) |
1483 | { | 1493 | { |
1484 | sba_dump_sg(ioc, sglist, nents); | 1494 | sba_dump_sg(ioc, sglist, nents); |
1485 | panic("Check after sba_map_sg()\n"); | 1495 | panic("Check after sba_map_sg_attrs()\n"); |
1486 | } | 1496 | } |
1487 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1497 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1488 | #endif | 1498 | #endif |
@@ -1492,18 +1502,20 @@ int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int di | |||
1492 | 1502 | ||
1493 | return filled; | 1503 | return filled; |
1494 | } | 1504 | } |
1495 | 1505 | EXPORT_SYMBOL(sba_map_sg_attrs); | |
1496 | 1506 | ||
1497 | /** | 1507 | /** |
1498 | * sba_unmap_sg - unmap Scatter/Gather list | 1508 | * sba_unmap_sg_attrs - unmap Scatter/Gather list |
1499 | * @dev: instance of PCI owned by the driver that's asking. | 1509 | * @dev: instance of PCI owned by the driver that's asking. |
1500 | * @sglist: array of buffer/length pairs | 1510 | * @sglist: array of buffer/length pairs |
1501 | * @nents: number of entries in list | 1511 | * @nents: number of entries in list |
1502 | * @dir: R/W or both. | 1512 | * @dir: R/W or both. |
1513 | * @attrs: optional dma attributes | ||
1503 | * | 1514 | * |
1504 | * See Documentation/DMA-mapping.txt | 1515 | * See Documentation/DMA-mapping.txt |
1505 | */ | 1516 | */ |
1506 | void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) | 1517 | void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, |
1518 | int nents, int dir, struct dma_attrs *attrs) | ||
1507 | { | 1519 | { |
1508 | #ifdef ASSERT_PDIR_SANITY | 1520 | #ifdef ASSERT_PDIR_SANITY |
1509 | struct ioc *ioc; | 1521 | struct ioc *ioc; |
@@ -1518,13 +1530,14 @@ void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, in | |||
1518 | ASSERT(ioc); | 1530 | ASSERT(ioc); |
1519 | 1531 | ||
1520 | spin_lock_irqsave(&ioc->res_lock, flags); | 1532 | spin_lock_irqsave(&ioc->res_lock, flags); |
1521 | sba_check_pdir(ioc,"Check before sba_unmap_sg()"); | 1533 | sba_check_pdir(ioc,"Check before sba_unmap_sg_attrs()"); |
1522 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1534 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1523 | #endif | 1535 | #endif |
1524 | 1536 | ||
1525 | while (nents && sglist->dma_length) { | 1537 | while (nents && sglist->dma_length) { |
1526 | 1538 | ||
1527 | sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir); | 1539 | sba_unmap_single_attrs(dev, sglist->dma_address, |
1540 | sglist->dma_length, dir, attrs); | ||
1528 | sglist = sg_next(sglist); | 1541 | sglist = sg_next(sglist); |
1529 | nents--; | 1542 | nents--; |
1530 | } | 1543 | } |
@@ -1533,11 +1546,12 @@ void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, in | |||
1533 | 1546 | ||
1534 | #ifdef ASSERT_PDIR_SANITY | 1547 | #ifdef ASSERT_PDIR_SANITY |
1535 | spin_lock_irqsave(&ioc->res_lock, flags); | 1548 | spin_lock_irqsave(&ioc->res_lock, flags); |
1536 | sba_check_pdir(ioc,"Check after sba_unmap_sg()"); | 1549 | sba_check_pdir(ioc,"Check after sba_unmap_sg_attrs()"); |
1537 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1550 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1538 | #endif | 1551 | #endif |
1539 | 1552 | ||
1540 | } | 1553 | } |
1554 | EXPORT_SYMBOL(sba_unmap_sg_attrs); | ||
1541 | 1555 | ||
1542 | /************************************************************** | 1556 | /************************************************************** |
1543 | * | 1557 | * |
@@ -1918,15 +1932,13 @@ static const struct file_operations ioc_fops = { | |||
1918 | static void __init | 1932 | static void __init |
1919 | ioc_proc_init(void) | 1933 | ioc_proc_init(void) |
1920 | { | 1934 | { |
1921 | struct proc_dir_entry *dir, *entry; | 1935 | struct proc_dir_entry *dir; |
1922 | 1936 | ||
1923 | dir = proc_mkdir("bus/mckinley", NULL); | 1937 | dir = proc_mkdir("bus/mckinley", NULL); |
1924 | if (!dir) | 1938 | if (!dir) |
1925 | return; | 1939 | return; |
1926 | 1940 | ||
1927 | entry = create_proc_entry(ioc_list->name, 0, dir); | 1941 | proc_create(ioc_list->name, 0, dir, &ioc_fops); |
1928 | if (entry) | ||
1929 | entry->proc_fops = &ioc_fops; | ||
1930 | } | 1942 | } |
1931 | #endif | 1943 | #endif |
1932 | 1944 | ||
@@ -2166,10 +2178,6 @@ sba_page_override(char *str) | |||
2166 | __setup("sbapagesize=",sba_page_override); | 2178 | __setup("sbapagesize=",sba_page_override); |
2167 | 2179 | ||
2168 | EXPORT_SYMBOL(sba_dma_mapping_error); | 2180 | EXPORT_SYMBOL(sba_dma_mapping_error); |
2169 | EXPORT_SYMBOL(sba_map_single); | ||
2170 | EXPORT_SYMBOL(sba_unmap_single); | ||
2171 | EXPORT_SYMBOL(sba_map_sg); | ||
2172 | EXPORT_SYMBOL(sba_unmap_sg); | ||
2173 | EXPORT_SYMBOL(sba_dma_supported); | 2181 | EXPORT_SYMBOL(sba_dma_supported); |
2174 | EXPORT_SYMBOL(sba_alloc_coherent); | 2182 | EXPORT_SYMBOL(sba_alloc_coherent); |
2175 | EXPORT_SYMBOL(sba_free_coherent); | 2183 | EXPORT_SYMBOL(sba_free_coherent); |
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index 230a6f92367f..c64a55af9b95 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/pid.h> | 10 | #include <linux/pid.h> |
11 | #include <linux/clocksource.h> | 11 | #include <linux/clocksource.h> |
12 | 12 | #include <linux/kbuild.h> | |
13 | #include <asm-ia64/processor.h> | 13 | #include <asm-ia64/processor.h> |
14 | #include <asm-ia64/ptrace.h> | 14 | #include <asm-ia64/ptrace.h> |
15 | #include <asm-ia64/siginfo.h> | 15 | #include <asm-ia64/siginfo.h> |
@@ -19,11 +19,6 @@ | |||
19 | #include "../kernel/sigframe.h" | 19 | #include "../kernel/sigframe.h" |
20 | #include "../kernel/fsyscall_gtod_data.h" | 20 | #include "../kernel/fsyscall_gtod_data.h" |
21 | 21 | ||
22 | #define DEFINE(sym, val) \ | ||
23 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
24 | |||
25 | #define BLANK() asm volatile("\n->" : : ) | ||
26 | |||
27 | void foo(void) | 22 | void foo(void) |
28 | { | 23 | { |
29 | DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct)); | 24 | DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct)); |
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index c8e403752a0c..7fbb51e10bbe 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
@@ -6695,16 +6695,12 @@ pfm_init(void) | |||
6695 | /* | 6695 | /* |
6696 | * create /proc/perfmon (mostly for debugging purposes) | 6696 | * create /proc/perfmon (mostly for debugging purposes) |
6697 | */ | 6697 | */ |
6698 | perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL); | 6698 | perfmon_dir = proc_create("perfmon", S_IRUGO, NULL, &pfm_proc_fops); |
6699 | if (perfmon_dir == NULL) { | 6699 | if (perfmon_dir == NULL) { |
6700 | printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); | 6700 | printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); |
6701 | pmu_conf = NULL; | 6701 | pmu_conf = NULL; |
6702 | return -1; | 6702 | return -1; |
6703 | } | 6703 | } |
6704 | /* | ||
6705 | * install customized file operations for /proc/perfmon entry | ||
6706 | */ | ||
6707 | perfmon_dir->proc_fops = &pfm_proc_fops; | ||
6708 | 6704 | ||
6709 | /* | 6705 | /* |
6710 | * create /proc/sys/kernel/perfmon (for debugging purposes) | 6706 | * create /proc/sys/kernel/perfmon (for debugging purposes) |
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index b11bb50a197a..ecb9eb78d687 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c | |||
@@ -648,18 +648,16 @@ salinfo_init(void) | |||
648 | if (!dir) | 648 | if (!dir) |
649 | continue; | 649 | continue; |
650 | 650 | ||
651 | entry = create_proc_entry("event", S_IRUSR, dir); | 651 | entry = proc_create_data("event", S_IRUSR, dir, |
652 | &salinfo_event_fops, data); | ||
652 | if (!entry) | 653 | if (!entry) |
653 | continue; | 654 | continue; |
654 | entry->data = data; | ||
655 | entry->proc_fops = &salinfo_event_fops; | ||
656 | *sdir++ = entry; | 655 | *sdir++ = entry; |
657 | 656 | ||
658 | entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir); | 657 | entry = proc_create_data("data", S_IRUSR | S_IWUSR, dir, |
658 | &salinfo_data_fops, data); | ||
659 | if (!entry) | 659 | if (!entry) |
660 | continue; | 660 | continue; |
661 | entry->data = data; | ||
662 | entry->proc_fops = &salinfo_data_fops; | ||
663 | *sdir++ = entry; | 661 | *sdir++ = entry; |
664 | 662 | ||
665 | /* we missed any events before now */ | 663 | /* we missed any events before now */ |
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig new file mode 100644 index 000000000000..7914e4828504 --- /dev/null +++ b/arch/ia64/kvm/Kconfig | |||
@@ -0,0 +1,49 @@ | |||
1 | # | ||
2 | # KVM configuration | ||
3 | # | ||
4 | config HAVE_KVM | ||
5 | bool | ||
6 | |||
7 | menuconfig VIRTUALIZATION | ||
8 | bool "Virtualization" | ||
9 | depends on HAVE_KVM || IA64 | ||
10 | default y | ||
11 | ---help--- | ||
12 | Say Y here to get to see options for using your Linux host to run other | ||
13 | operating systems inside virtual machines (guests). | ||
14 | This option alone does not add any kernel code. | ||
15 | |||
16 | If you say N, all options in this submenu will be skipped and disabled. | ||
17 | |||
18 | if VIRTUALIZATION | ||
19 | |||
20 | config KVM | ||
21 | tristate "Kernel-based Virtual Machine (KVM) support" | ||
22 | depends on HAVE_KVM && EXPERIMENTAL | ||
23 | select PREEMPT_NOTIFIERS | ||
24 | select ANON_INODES | ||
25 | ---help--- | ||
26 | Support hosting fully virtualized guest machines using hardware | ||
27 | virtualization extensions. You will need a fairly recent | ||
28 | processor equipped with virtualization extensions. You will also | ||
29 | need to select one or more of the processor modules below. | ||
30 | |||
31 | This module provides access to the hardware capabilities through | ||
32 | a character device node named /dev/kvm. | ||
33 | |||
34 | To compile this as a module, choose M here: the module | ||
35 | will be called kvm. | ||
36 | |||
37 | If unsure, say N. | ||
38 | |||
39 | config KVM_INTEL | ||
40 | tristate "KVM for Intel Itanium 2 processors support" | ||
41 | depends on KVM && m | ||
42 | ---help--- | ||
43 | Provides support for KVM on Itanium 2 processors equipped with the VT | ||
44 | extensions. | ||
45 | |||
46 | config KVM_TRACE | ||
47 | bool | ||
48 | |||
49 | endif # VIRTUALIZATION | ||
diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile new file mode 100644 index 000000000000..52353397a1a4 --- /dev/null +++ b/arch/ia64/kvm/Makefile | |||
@@ -0,0 +1,58 @@ | |||
1 | #This Make file is to generate asm-offsets.h and build source. | ||
2 | # | ||
3 | |||
4 | #Generate asm-offsets.h for vmm module build | ||
5 | offsets-file := asm-offsets.h | ||
6 | |||
7 | always := $(offsets-file) | ||
8 | targets := $(offsets-file) | ||
9 | targets += arch/ia64/kvm/asm-offsets.s | ||
10 | clean-files := $(addprefix $(objtree)/,$(targets) $(obj)/memcpy.S $(obj)/memset.S) | ||
11 | |||
12 | # Default sed regexp - multiline due to syntax constraints | ||
13 | define sed-y | ||
14 | "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}" | ||
15 | endef | ||
16 | |||
17 | quiet_cmd_offsets = GEN $@ | ||
18 | define cmd_offsets | ||
19 | (set -e; \ | ||
20 | echo "#ifndef __ASM_KVM_OFFSETS_H__"; \ | ||
21 | echo "#define __ASM_KVM_OFFSETS_H__"; \ | ||
22 | echo "/*"; \ | ||
23 | echo " * DO NOT MODIFY."; \ | ||
24 | echo " *"; \ | ||
25 | echo " * This file was generated by Makefile"; \ | ||
26 | echo " *"; \ | ||
27 | echo " */"; \ | ||
28 | echo ""; \ | ||
29 | sed -ne $(sed-y) $<; \ | ||
30 | echo ""; \ | ||
31 | echo "#endif" ) > $@ | ||
32 | endef | ||
33 | # We use internal rules to avoid the "is up to date" message from make | ||
34 | arch/ia64/kvm/asm-offsets.s: arch/ia64/kvm/asm-offsets.c | ||
35 | $(call if_changed_dep,cc_s_c) | ||
36 | |||
37 | $(obj)/$(offsets-file): arch/ia64/kvm/asm-offsets.s | ||
38 | $(call cmd,offsets) | ||
39 | |||
40 | # | ||
41 | # Makefile for Kernel-based Virtual Machine module | ||
42 | # | ||
43 | |||
44 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/ | ||
45 | EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/ | ||
46 | |||
47 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) | ||
48 | |||
49 | kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o | ||
50 | obj-$(CONFIG_KVM) += kvm.o | ||
51 | |||
52 | FORCE : $(obj)/$(offsets-file) | ||
53 | EXTRA_CFLAGS_vcpu.o += -mfixed-range=f2-f5,f12-f127 | ||
54 | kvm-intel-objs = vmm.o vmm_ivt.o trampoline.o vcpu.o optvfault.o mmio.o \ | ||
55 | vtlb.o process.o | ||
56 | #Add link memcpy and memset to avoid possible structure assignment error | ||
57 | kvm-intel-objs += ../lib/memset.o ../lib/memcpy.o | ||
58 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | ||
diff --git a/arch/ia64/kvm/asm-offsets.c b/arch/ia64/kvm/asm-offsets.c new file mode 100644 index 000000000000..4e3dc13a619c --- /dev/null +++ b/arch/ia64/kvm/asm-offsets.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * asm-offsets.c Generate definitions needed by assembly language modules. | ||
3 | * This code generates raw asm output which is post-processed | ||
4 | * to extract and format the required data. | ||
5 | * | ||
6 | * Anthony Xu <anthony.xu@intel.com> | ||
7 | * Xiantao Zhang <xiantao.zhang@intel.com> | ||
8 | * Copyright (c) 2007 Intel Corporation KVM support. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
21 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/autoconf.h> | ||
26 | #include <linux/kvm_host.h> | ||
27 | |||
28 | #include "vcpu.h" | ||
29 | |||
30 | #define task_struct kvm_vcpu | ||
31 | |||
32 | #define DEFINE(sym, val) \ | ||
33 | asm volatile("\n->" #sym " (%0) " #val : : "i" (val)) | ||
34 | |||
35 | #define BLANK() asm volatile("\n->" : :) | ||
36 | |||
37 | #define OFFSET(_sym, _str, _mem) \ | ||
38 | DEFINE(_sym, offsetof(_str, _mem)); | ||
39 | |||
40 | void foo(void) | ||
41 | { | ||
42 | DEFINE(VMM_TASK_SIZE, sizeof(struct kvm_vcpu)); | ||
43 | DEFINE(VMM_PT_REGS_SIZE, sizeof(struct kvm_pt_regs)); | ||
44 | |||
45 | BLANK(); | ||
46 | |||
47 | DEFINE(VMM_VCPU_META_RR0_OFFSET, | ||
48 | offsetof(struct kvm_vcpu, arch.metaphysical_rr0)); | ||
49 | DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET, | ||
50 | offsetof(struct kvm_vcpu, | ||
51 | arch.metaphysical_saved_rr0)); | ||
52 | DEFINE(VMM_VCPU_VRR0_OFFSET, | ||
53 | offsetof(struct kvm_vcpu, arch.vrr[0])); | ||
54 | DEFINE(VMM_VPD_IRR0_OFFSET, | ||
55 | offsetof(struct vpd, irr[0])); | ||
56 | DEFINE(VMM_VCPU_ITC_CHECK_OFFSET, | ||
57 | offsetof(struct kvm_vcpu, arch.itc_check)); | ||
58 | DEFINE(VMM_VCPU_IRQ_CHECK_OFFSET, | ||
59 | offsetof(struct kvm_vcpu, arch.irq_check)); | ||
60 | DEFINE(VMM_VPD_VHPI_OFFSET, | ||
61 | offsetof(struct vpd, vhpi)); | ||
62 | DEFINE(VMM_VCPU_VSA_BASE_OFFSET, | ||
63 | offsetof(struct kvm_vcpu, arch.vsa_base)); | ||
64 | DEFINE(VMM_VCPU_VPD_OFFSET, | ||
65 | offsetof(struct kvm_vcpu, arch.vpd)); | ||
66 | DEFINE(VMM_VCPU_IRQ_CHECK, | ||
67 | offsetof(struct kvm_vcpu, arch.irq_check)); | ||
68 | DEFINE(VMM_VCPU_TIMER_PENDING, | ||
69 | offsetof(struct kvm_vcpu, arch.timer_pending)); | ||
70 | DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET, | ||
71 | offsetof(struct kvm_vcpu, arch.metaphysical_saved_rr0)); | ||
72 | DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET, | ||
73 | offsetof(struct kvm_vcpu, arch.mode_flags)); | ||
74 | DEFINE(VMM_VCPU_ITC_OFS_OFFSET, | ||
75 | offsetof(struct kvm_vcpu, arch.itc_offset)); | ||
76 | DEFINE(VMM_VCPU_LAST_ITC_OFFSET, | ||
77 | offsetof(struct kvm_vcpu, arch.last_itc)); | ||
78 | DEFINE(VMM_VCPU_SAVED_GP_OFFSET, | ||
79 | offsetof(struct kvm_vcpu, arch.saved_gp)); | ||
80 | |||
81 | BLANK(); | ||
82 | |||
83 | DEFINE(VMM_PT_REGS_B6_OFFSET, | ||
84 | offsetof(struct kvm_pt_regs, b6)); | ||
85 | DEFINE(VMM_PT_REGS_B7_OFFSET, | ||
86 | offsetof(struct kvm_pt_regs, b7)); | ||
87 | DEFINE(VMM_PT_REGS_AR_CSD_OFFSET, | ||
88 | offsetof(struct kvm_pt_regs, ar_csd)); | ||
89 | DEFINE(VMM_PT_REGS_AR_SSD_OFFSET, | ||
90 | offsetof(struct kvm_pt_regs, ar_ssd)); | ||
91 | DEFINE(VMM_PT_REGS_R8_OFFSET, | ||
92 | offsetof(struct kvm_pt_regs, r8)); | ||
93 | DEFINE(VMM_PT_REGS_R9_OFFSET, | ||
94 | offsetof(struct kvm_pt_regs, r9)); | ||
95 | DEFINE(VMM_PT_REGS_R10_OFFSET, | ||
96 | offsetof(struct kvm_pt_regs, r10)); | ||
97 | DEFINE(VMM_PT_REGS_R11_OFFSET, | ||
98 | offsetof(struct kvm_pt_regs, r11)); | ||
99 | DEFINE(VMM_PT_REGS_CR_IPSR_OFFSET, | ||
100 | offsetof(struct kvm_pt_regs, cr_ipsr)); | ||
101 | DEFINE(VMM_PT_REGS_CR_IIP_OFFSET, | ||
102 | offsetof(struct kvm_pt_regs, cr_iip)); | ||
103 | DEFINE(VMM_PT_REGS_CR_IFS_OFFSET, | ||
104 | offsetof(struct kvm_pt_regs, cr_ifs)); | ||
105 | DEFINE(VMM_PT_REGS_AR_UNAT_OFFSET, | ||
106 | offsetof(struct kvm_pt_regs, ar_unat)); | ||
107 | DEFINE(VMM_PT_REGS_AR_PFS_OFFSET, | ||
108 | offsetof(struct kvm_pt_regs, ar_pfs)); | ||
109 | DEFINE(VMM_PT_REGS_AR_RSC_OFFSET, | ||
110 | offsetof(struct kvm_pt_regs, ar_rsc)); | ||
111 | DEFINE(VMM_PT_REGS_AR_RNAT_OFFSET, | ||
112 | offsetof(struct kvm_pt_regs, ar_rnat)); | ||
113 | |||
114 | DEFINE(VMM_PT_REGS_AR_BSPSTORE_OFFSET, | ||
115 | offsetof(struct kvm_pt_regs, ar_bspstore)); | ||
116 | DEFINE(VMM_PT_REGS_PR_OFFSET, | ||
117 | offsetof(struct kvm_pt_regs, pr)); | ||
118 | DEFINE(VMM_PT_REGS_B0_OFFSET, | ||
119 | offsetof(struct kvm_pt_regs, b0)); | ||
120 | DEFINE(VMM_PT_REGS_LOADRS_OFFSET, | ||
121 | offsetof(struct kvm_pt_regs, loadrs)); | ||
122 | DEFINE(VMM_PT_REGS_R1_OFFSET, | ||
123 | offsetof(struct kvm_pt_regs, r1)); | ||
124 | DEFINE(VMM_PT_REGS_R12_OFFSET, | ||
125 | offsetof(struct kvm_pt_regs, r12)); | ||
126 | DEFINE(VMM_PT_REGS_R13_OFFSET, | ||
127 | offsetof(struct kvm_pt_regs, r13)); | ||
128 | DEFINE(VMM_PT_REGS_AR_FPSR_OFFSET, | ||
129 | offsetof(struct kvm_pt_regs, ar_fpsr)); | ||
130 | DEFINE(VMM_PT_REGS_R15_OFFSET, | ||
131 | offsetof(struct kvm_pt_regs, r15)); | ||
132 | DEFINE(VMM_PT_REGS_R14_OFFSET, | ||
133 | offsetof(struct kvm_pt_regs, r14)); | ||
134 | DEFINE(VMM_PT_REGS_R2_OFFSET, | ||
135 | offsetof(struct kvm_pt_regs, r2)); | ||
136 | DEFINE(VMM_PT_REGS_R3_OFFSET, | ||
137 | offsetof(struct kvm_pt_regs, r3)); | ||
138 | DEFINE(VMM_PT_REGS_R16_OFFSET, | ||
139 | offsetof(struct kvm_pt_regs, r16)); | ||
140 | DEFINE(VMM_PT_REGS_R17_OFFSET, | ||
141 | offsetof(struct kvm_pt_regs, r17)); | ||
142 | DEFINE(VMM_PT_REGS_R18_OFFSET, | ||
143 | offsetof(struct kvm_pt_regs, r18)); | ||
144 | DEFINE(VMM_PT_REGS_R19_OFFSET, | ||
145 | offsetof(struct kvm_pt_regs, r19)); | ||
146 | DEFINE(VMM_PT_REGS_R20_OFFSET, | ||
147 | offsetof(struct kvm_pt_regs, r20)); | ||
148 | DEFINE(VMM_PT_REGS_R21_OFFSET, | ||
149 | offsetof(struct kvm_pt_regs, r21)); | ||
150 | DEFINE(VMM_PT_REGS_R22_OFFSET, | ||
151 | offsetof(struct kvm_pt_regs, r22)); | ||
152 | DEFINE(VMM_PT_REGS_R23_OFFSET, | ||
153 | offsetof(struct kvm_pt_regs, r23)); | ||
154 | DEFINE(VMM_PT_REGS_R24_OFFSET, | ||
155 | offsetof(struct kvm_pt_regs, r24)); | ||
156 | DEFINE(VMM_PT_REGS_R25_OFFSET, | ||
157 | offsetof(struct kvm_pt_regs, r25)); | ||
158 | DEFINE(VMM_PT_REGS_R26_OFFSET, | ||
159 | offsetof(struct kvm_pt_regs, r26)); | ||
160 | DEFINE(VMM_PT_REGS_R27_OFFSET, | ||
161 | offsetof(struct kvm_pt_regs, r27)); | ||
162 | DEFINE(VMM_PT_REGS_R28_OFFSET, | ||
163 | offsetof(struct kvm_pt_regs, r28)); | ||
164 | DEFINE(VMM_PT_REGS_R29_OFFSET, | ||
165 | offsetof(struct kvm_pt_regs, r29)); | ||
166 | DEFINE(VMM_PT_REGS_R30_OFFSET, | ||
167 | offsetof(struct kvm_pt_regs, r30)); | ||
168 | DEFINE(VMM_PT_REGS_R31_OFFSET, | ||
169 | offsetof(struct kvm_pt_regs, r31)); | ||
170 | DEFINE(VMM_PT_REGS_AR_CCV_OFFSET, | ||
171 | offsetof(struct kvm_pt_regs, ar_ccv)); | ||
172 | DEFINE(VMM_PT_REGS_F6_OFFSET, | ||
173 | offsetof(struct kvm_pt_regs, f6)); | ||
174 | DEFINE(VMM_PT_REGS_F7_OFFSET, | ||
175 | offsetof(struct kvm_pt_regs, f7)); | ||
176 | DEFINE(VMM_PT_REGS_F8_OFFSET, | ||
177 | offsetof(struct kvm_pt_regs, f8)); | ||
178 | DEFINE(VMM_PT_REGS_F9_OFFSET, | ||
179 | offsetof(struct kvm_pt_regs, f9)); | ||
180 | DEFINE(VMM_PT_REGS_F10_OFFSET, | ||
181 | offsetof(struct kvm_pt_regs, f10)); | ||
182 | DEFINE(VMM_PT_REGS_F11_OFFSET, | ||
183 | offsetof(struct kvm_pt_regs, f11)); | ||
184 | DEFINE(VMM_PT_REGS_R4_OFFSET, | ||
185 | offsetof(struct kvm_pt_regs, r4)); | ||
186 | DEFINE(VMM_PT_REGS_R5_OFFSET, | ||
187 | offsetof(struct kvm_pt_regs, r5)); | ||
188 | DEFINE(VMM_PT_REGS_R6_OFFSET, | ||
189 | offsetof(struct kvm_pt_regs, r6)); | ||
190 | DEFINE(VMM_PT_REGS_R7_OFFSET, | ||
191 | offsetof(struct kvm_pt_regs, r7)); | ||
192 | DEFINE(VMM_PT_REGS_EML_UNAT_OFFSET, | ||
193 | offsetof(struct kvm_pt_regs, eml_unat)); | ||
194 | DEFINE(VMM_VCPU_IIPA_OFFSET, | ||
195 | offsetof(struct kvm_vcpu, arch.cr_iipa)); | ||
196 | DEFINE(VMM_VCPU_OPCODE_OFFSET, | ||
197 | offsetof(struct kvm_vcpu, arch.opcode)); | ||
198 | DEFINE(VMM_VCPU_CAUSE_OFFSET, offsetof(struct kvm_vcpu, arch.cause)); | ||
199 | DEFINE(VMM_VCPU_ISR_OFFSET, | ||
200 | offsetof(struct kvm_vcpu, arch.cr_isr)); | ||
201 | DEFINE(VMM_PT_REGS_R16_SLOT, | ||
202 | (((offsetof(struct kvm_pt_regs, r16) | ||
203 | - sizeof(struct kvm_pt_regs)) >> 3) & 0x3f)); | ||
204 | DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET, | ||
205 | offsetof(struct kvm_vcpu, arch.mode_flags)); | ||
206 | DEFINE(VMM_VCPU_GP_OFFSET, offsetof(struct kvm_vcpu, arch.__gp)); | ||
207 | BLANK(); | ||
208 | |||
209 | DEFINE(VMM_VPD_BASE_OFFSET, offsetof(struct kvm_vcpu, arch.vpd)); | ||
210 | DEFINE(VMM_VPD_VIFS_OFFSET, offsetof(struct vpd, ifs)); | ||
211 | DEFINE(VMM_VLSAPIC_INSVC_BASE_OFFSET, | ||
212 | offsetof(struct kvm_vcpu, arch.insvc[0])); | ||
213 | DEFINE(VMM_VPD_VPTA_OFFSET, offsetof(struct vpd, pta)); | ||
214 | DEFINE(VMM_VPD_VPSR_OFFSET, offsetof(struct vpd, vpsr)); | ||
215 | |||
216 | DEFINE(VMM_CTX_R4_OFFSET, offsetof(union context, gr[4])); | ||
217 | DEFINE(VMM_CTX_R5_OFFSET, offsetof(union context, gr[5])); | ||
218 | DEFINE(VMM_CTX_R12_OFFSET, offsetof(union context, gr[12])); | ||
219 | DEFINE(VMM_CTX_R13_OFFSET, offsetof(union context, gr[13])); | ||
220 | DEFINE(VMM_CTX_KR0_OFFSET, offsetof(union context, ar[0])); | ||
221 | DEFINE(VMM_CTX_KR1_OFFSET, offsetof(union context, ar[1])); | ||
222 | DEFINE(VMM_CTX_B0_OFFSET, offsetof(union context, br[0])); | ||
223 | DEFINE(VMM_CTX_B1_OFFSET, offsetof(union context, br[1])); | ||
224 | DEFINE(VMM_CTX_B2_OFFSET, offsetof(union context, br[2])); | ||
225 | DEFINE(VMM_CTX_RR0_OFFSET, offsetof(union context, rr[0])); | ||
226 | DEFINE(VMM_CTX_RSC_OFFSET, offsetof(union context, ar[16])); | ||
227 | DEFINE(VMM_CTX_BSPSTORE_OFFSET, offsetof(union context, ar[18])); | ||
228 | DEFINE(VMM_CTX_RNAT_OFFSET, offsetof(union context, ar[19])); | ||
229 | DEFINE(VMM_CTX_FCR_OFFSET, offsetof(union context, ar[21])); | ||
230 | DEFINE(VMM_CTX_EFLAG_OFFSET, offsetof(union context, ar[24])); | ||
231 | DEFINE(VMM_CTX_CFLG_OFFSET, offsetof(union context, ar[27])); | ||
232 | DEFINE(VMM_CTX_FSR_OFFSET, offsetof(union context, ar[28])); | ||
233 | DEFINE(VMM_CTX_FIR_OFFSET, offsetof(union context, ar[29])); | ||
234 | DEFINE(VMM_CTX_FDR_OFFSET, offsetof(union context, ar[30])); | ||
235 | DEFINE(VMM_CTX_UNAT_OFFSET, offsetof(union context, ar[36])); | ||
236 | DEFINE(VMM_CTX_FPSR_OFFSET, offsetof(union context, ar[40])); | ||
237 | DEFINE(VMM_CTX_PFS_OFFSET, offsetof(union context, ar[64])); | ||
238 | DEFINE(VMM_CTX_LC_OFFSET, offsetof(union context, ar[65])); | ||
239 | DEFINE(VMM_CTX_DCR_OFFSET, offsetof(union context, cr[0])); | ||
240 | DEFINE(VMM_CTX_IVA_OFFSET, offsetof(union context, cr[2])); | ||
241 | DEFINE(VMM_CTX_PTA_OFFSET, offsetof(union context, cr[8])); | ||
242 | DEFINE(VMM_CTX_IBR0_OFFSET, offsetof(union context, ibr[0])); | ||
243 | DEFINE(VMM_CTX_DBR0_OFFSET, offsetof(union context, dbr[0])); | ||
244 | DEFINE(VMM_CTX_F2_OFFSET, offsetof(union context, fr[2])); | ||
245 | DEFINE(VMM_CTX_F3_OFFSET, offsetof(union context, fr[3])); | ||
246 | DEFINE(VMM_CTX_F32_OFFSET, offsetof(union context, fr[32])); | ||
247 | DEFINE(VMM_CTX_F33_OFFSET, offsetof(union context, fr[33])); | ||
248 | DEFINE(VMM_CTX_PKR0_OFFSET, offsetof(union context, pkr[0])); | ||
249 | DEFINE(VMM_CTX_PSR_OFFSET, offsetof(union context, psr)); | ||
250 | BLANK(); | ||
251 | } | ||
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c new file mode 100644 index 000000000000..6df073240135 --- /dev/null +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -0,0 +1,1806 @@ | |||
1 | |||
2 | /* | ||
3 | * kvm_ia64.c: Basic KVM suppport On Itanium series processors | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007, Intel Corporation. | ||
7 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
20 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/percpu.h> | ||
27 | #include <linux/gfp.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/smp.h> | ||
30 | #include <linux/kvm_host.h> | ||
31 | #include <linux/kvm.h> | ||
32 | #include <linux/bitops.h> | ||
33 | #include <linux/hrtimer.h> | ||
34 | #include <linux/uaccess.h> | ||
35 | |||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/gcc_intrin.h> | ||
38 | #include <asm/pal.h> | ||
39 | #include <asm/cacheflush.h> | ||
40 | #include <asm/div64.h> | ||
41 | #include <asm/tlb.h> | ||
42 | |||
43 | #include "misc.h" | ||
44 | #include "vti.h" | ||
45 | #include "iodev.h" | ||
46 | #include "ioapic.h" | ||
47 | #include "lapic.h" | ||
48 | |||
49 | static unsigned long kvm_vmm_base; | ||
50 | static unsigned long kvm_vsa_base; | ||
51 | static unsigned long kvm_vm_buffer; | ||
52 | static unsigned long kvm_vm_buffer_size; | ||
53 | unsigned long kvm_vmm_gp; | ||
54 | |||
55 | static long vp_env_info; | ||
56 | |||
57 | static struct kvm_vmm_info *kvm_vmm_info; | ||
58 | |||
59 | static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu); | ||
60 | |||
61 | struct kvm_stats_debugfs_item debugfs_entries[] = { | ||
62 | { NULL } | ||
63 | }; | ||
64 | |||
65 | |||
66 | struct fdesc{ | ||
67 | unsigned long ip; | ||
68 | unsigned long gp; | ||
69 | }; | ||
70 | |||
71 | static void kvm_flush_icache(unsigned long start, unsigned long len) | ||
72 | { | ||
73 | int l; | ||
74 | |||
75 | for (l = 0; l < (len + 32); l += 32) | ||
76 | ia64_fc(start + l); | ||
77 | |||
78 | ia64_sync_i(); | ||
79 | ia64_srlz_i(); | ||
80 | } | ||
81 | |||
82 | static void kvm_flush_tlb_all(void) | ||
83 | { | ||
84 | unsigned long i, j, count0, count1, stride0, stride1, addr; | ||
85 | long flags; | ||
86 | |||
87 | addr = local_cpu_data->ptce_base; | ||
88 | count0 = local_cpu_data->ptce_count[0]; | ||
89 | count1 = local_cpu_data->ptce_count[1]; | ||
90 | stride0 = local_cpu_data->ptce_stride[0]; | ||
91 | stride1 = local_cpu_data->ptce_stride[1]; | ||
92 | |||
93 | local_irq_save(flags); | ||
94 | for (i = 0; i < count0; ++i) { | ||
95 | for (j = 0; j < count1; ++j) { | ||
96 | ia64_ptce(addr); | ||
97 | addr += stride1; | ||
98 | } | ||
99 | addr += stride0; | ||
100 | } | ||
101 | local_irq_restore(flags); | ||
102 | ia64_srlz_i(); /* srlz.i implies srlz.d */ | ||
103 | } | ||
104 | |||
105 | long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler) | ||
106 | { | ||
107 | struct ia64_pal_retval iprv; | ||
108 | |||
109 | PAL_CALL_STK(iprv, PAL_VP_CREATE, (u64)vpd, (u64)host_iva, | ||
110 | (u64)opt_handler); | ||
111 | |||
112 | return iprv.status; | ||
113 | } | ||
114 | |||
115 | static DEFINE_SPINLOCK(vp_lock); | ||
116 | |||
117 | void kvm_arch_hardware_enable(void *garbage) | ||
118 | { | ||
119 | long status; | ||
120 | long tmp_base; | ||
121 | unsigned long pte; | ||
122 | unsigned long saved_psr; | ||
123 | int slot; | ||
124 | |||
125 | pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), | ||
126 | PAGE_KERNEL)); | ||
127 | local_irq_save(saved_psr); | ||
128 | slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT); | ||
129 | if (slot < 0) | ||
130 | return; | ||
131 | local_irq_restore(saved_psr); | ||
132 | |||
133 | spin_lock(&vp_lock); | ||
134 | status = ia64_pal_vp_init_env(kvm_vsa_base ? | ||
135 | VP_INIT_ENV : VP_INIT_ENV_INITALIZE, | ||
136 | __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base); | ||
137 | if (status != 0) { | ||
138 | printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n"); | ||
139 | return ; | ||
140 | } | ||
141 | |||
142 | if (!kvm_vsa_base) { | ||
143 | kvm_vsa_base = tmp_base; | ||
144 | printk(KERN_INFO"kvm: kvm_vsa_base:0x%lx\n", kvm_vsa_base); | ||
145 | } | ||
146 | spin_unlock(&vp_lock); | ||
147 | ia64_ptr_entry(0x3, slot); | ||
148 | } | ||
149 | |||
150 | void kvm_arch_hardware_disable(void *garbage) | ||
151 | { | ||
152 | |||
153 | long status; | ||
154 | int slot; | ||
155 | unsigned long pte; | ||
156 | unsigned long saved_psr; | ||
157 | unsigned long host_iva = ia64_getreg(_IA64_REG_CR_IVA); | ||
158 | |||
159 | pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), | ||
160 | PAGE_KERNEL)); | ||
161 | |||
162 | local_irq_save(saved_psr); | ||
163 | slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT); | ||
164 | if (slot < 0) | ||
165 | return; | ||
166 | local_irq_restore(saved_psr); | ||
167 | |||
168 | status = ia64_pal_vp_exit_env(host_iva); | ||
169 | if (status) | ||
170 | printk(KERN_DEBUG"kvm: Failed to disable VT support! :%ld\n", | ||
171 | status); | ||
172 | ia64_ptr_entry(0x3, slot); | ||
173 | } | ||
174 | |||
175 | void kvm_arch_check_processor_compat(void *rtn) | ||
176 | { | ||
177 | *(int *)rtn = 0; | ||
178 | } | ||
179 | |||
180 | int kvm_dev_ioctl_check_extension(long ext) | ||
181 | { | ||
182 | |||
183 | int r; | ||
184 | |||
185 | switch (ext) { | ||
186 | case KVM_CAP_IRQCHIP: | ||
187 | case KVM_CAP_USER_MEMORY: | ||
188 | |||
189 | r = 1; | ||
190 | break; | ||
191 | default: | ||
192 | r = 0; | ||
193 | } | ||
194 | return r; | ||
195 | |||
196 | } | ||
197 | |||
198 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | ||
199 | gpa_t addr) | ||
200 | { | ||
201 | struct kvm_io_device *dev; | ||
202 | |||
203 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | ||
204 | |||
205 | return dev; | ||
206 | } | ||
207 | |||
208 | static int handle_vm_error(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
209 | { | ||
210 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | ||
211 | kvm_run->hw.hardware_exit_reason = 1; | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
216 | { | ||
217 | struct kvm_mmio_req *p; | ||
218 | struct kvm_io_device *mmio_dev; | ||
219 | |||
220 | p = kvm_get_vcpu_ioreq(vcpu); | ||
221 | |||
222 | if ((p->addr & PAGE_MASK) == IOAPIC_DEFAULT_BASE_ADDRESS) | ||
223 | goto mmio; | ||
224 | vcpu->mmio_needed = 1; | ||
225 | vcpu->mmio_phys_addr = kvm_run->mmio.phys_addr = p->addr; | ||
226 | vcpu->mmio_size = kvm_run->mmio.len = p->size; | ||
227 | vcpu->mmio_is_write = kvm_run->mmio.is_write = !p->dir; | ||
228 | |||
229 | if (vcpu->mmio_is_write) | ||
230 | memcpy(vcpu->mmio_data, &p->data, p->size); | ||
231 | memcpy(kvm_run->mmio.data, &p->data, p->size); | ||
232 | kvm_run->exit_reason = KVM_EXIT_MMIO; | ||
233 | return 0; | ||
234 | mmio: | ||
235 | mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr); | ||
236 | if (mmio_dev) { | ||
237 | if (!p->dir) | ||
238 | kvm_iodevice_write(mmio_dev, p->addr, p->size, | ||
239 | &p->data); | ||
240 | else | ||
241 | kvm_iodevice_read(mmio_dev, p->addr, p->size, | ||
242 | &p->data); | ||
243 | |||
244 | } else | ||
245 | printk(KERN_ERR"kvm: No iodevice found! addr:%lx\n", p->addr); | ||
246 | p->state = STATE_IORESP_READY; | ||
247 | |||
248 | return 1; | ||
249 | } | ||
250 | |||
251 | static int handle_pal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
252 | { | ||
253 | struct exit_ctl_data *p; | ||
254 | |||
255 | p = kvm_get_exit_data(vcpu); | ||
256 | |||
257 | if (p->exit_reason == EXIT_REASON_PAL_CALL) | ||
258 | return kvm_pal_emul(vcpu, kvm_run); | ||
259 | else { | ||
260 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | ||
261 | kvm_run->hw.hardware_exit_reason = 2; | ||
262 | return 0; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static int handle_sal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
267 | { | ||
268 | struct exit_ctl_data *p; | ||
269 | |||
270 | p = kvm_get_exit_data(vcpu); | ||
271 | |||
272 | if (p->exit_reason == EXIT_REASON_SAL_CALL) { | ||
273 | kvm_sal_emul(vcpu); | ||
274 | return 1; | ||
275 | } else { | ||
276 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | ||
277 | kvm_run->hw.hardware_exit_reason = 3; | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | } | ||
282 | |||
283 | /* | ||
284 | * offset: address offset to IPI space. | ||
285 | * value: deliver value. | ||
286 | */ | ||
287 | static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm, | ||
288 | uint64_t vector) | ||
289 | { | ||
290 | switch (dm) { | ||
291 | case SAPIC_FIXED: | ||
292 | kvm_apic_set_irq(vcpu, vector, 0); | ||
293 | break; | ||
294 | case SAPIC_NMI: | ||
295 | kvm_apic_set_irq(vcpu, 2, 0); | ||
296 | break; | ||
297 | case SAPIC_EXTINT: | ||
298 | kvm_apic_set_irq(vcpu, 0, 0); | ||
299 | break; | ||
300 | case SAPIC_INIT: | ||
301 | case SAPIC_PMI: | ||
302 | default: | ||
303 | printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n"); | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id, | ||
309 | unsigned long eid) | ||
310 | { | ||
311 | union ia64_lid lid; | ||
312 | int i; | ||
313 | |||
314 | for (i = 0; i < KVM_MAX_VCPUS; i++) { | ||
315 | if (kvm->vcpus[i]) { | ||
316 | lid.val = VCPU_LID(kvm->vcpus[i]); | ||
317 | if (lid.id == id && lid.eid == eid) | ||
318 | return kvm->vcpus[i]; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | return NULL; | ||
323 | } | ||
324 | |||
325 | static int handle_ipi(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
326 | { | ||
327 | struct exit_ctl_data *p = kvm_get_exit_data(vcpu); | ||
328 | struct kvm_vcpu *target_vcpu; | ||
329 | struct kvm_pt_regs *regs; | ||
330 | union ia64_ipi_a addr = p->u.ipi_data.addr; | ||
331 | union ia64_ipi_d data = p->u.ipi_data.data; | ||
332 | |||
333 | target_vcpu = lid_to_vcpu(vcpu->kvm, addr.id, addr.eid); | ||
334 | if (!target_vcpu) | ||
335 | return handle_vm_error(vcpu, kvm_run); | ||
336 | |||
337 | if (!target_vcpu->arch.launched) { | ||
338 | regs = vcpu_regs(target_vcpu); | ||
339 | |||
340 | regs->cr_iip = vcpu->kvm->arch.rdv_sal_data.boot_ip; | ||
341 | regs->r1 = vcpu->kvm->arch.rdv_sal_data.boot_gp; | ||
342 | |||
343 | target_vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
344 | if (waitqueue_active(&target_vcpu->wq)) | ||
345 | wake_up_interruptible(&target_vcpu->wq); | ||
346 | } else { | ||
347 | vcpu_deliver_ipi(target_vcpu, data.dm, data.vector); | ||
348 | if (target_vcpu != vcpu) | ||
349 | kvm_vcpu_kick(target_vcpu); | ||
350 | } | ||
351 | |||
352 | return 1; | ||
353 | } | ||
354 | |||
355 | struct call_data { | ||
356 | struct kvm_ptc_g ptc_g_data; | ||
357 | struct kvm_vcpu *vcpu; | ||
358 | }; | ||
359 | |||
360 | static void vcpu_global_purge(void *info) | ||
361 | { | ||
362 | struct call_data *p = (struct call_data *)info; | ||
363 | struct kvm_vcpu *vcpu = p->vcpu; | ||
364 | |||
365 | if (test_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) | ||
366 | return; | ||
367 | |||
368 | set_bit(KVM_REQ_PTC_G, &vcpu->requests); | ||
369 | if (vcpu->arch.ptc_g_count < MAX_PTC_G_NUM) { | ||
370 | vcpu->arch.ptc_g_data[vcpu->arch.ptc_g_count++] = | ||
371 | p->ptc_g_data; | ||
372 | } else { | ||
373 | clear_bit(KVM_REQ_PTC_G, &vcpu->requests); | ||
374 | vcpu->arch.ptc_g_count = 0; | ||
375 | set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | static int handle_global_purge(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
380 | { | ||
381 | struct exit_ctl_data *p = kvm_get_exit_data(vcpu); | ||
382 | struct kvm *kvm = vcpu->kvm; | ||
383 | struct call_data call_data; | ||
384 | int i; | ||
385 | call_data.ptc_g_data = p->u.ptc_g_data; | ||
386 | |||
387 | for (i = 0; i < KVM_MAX_VCPUS; i++) { | ||
388 | if (!kvm->vcpus[i] || kvm->vcpus[i]->arch.mp_state == | ||
389 | KVM_MP_STATE_UNINITIALIZED || | ||
390 | vcpu == kvm->vcpus[i]) | ||
391 | continue; | ||
392 | |||
393 | if (waitqueue_active(&kvm->vcpus[i]->wq)) | ||
394 | wake_up_interruptible(&kvm->vcpus[i]->wq); | ||
395 | |||
396 | if (kvm->vcpus[i]->cpu != -1) { | ||
397 | call_data.vcpu = kvm->vcpus[i]; | ||
398 | smp_call_function_single(kvm->vcpus[i]->cpu, | ||
399 | vcpu_global_purge, &call_data, 0, 1); | ||
400 | } else | ||
401 | printk(KERN_WARNING"kvm: Uninit vcpu received ipi!\n"); | ||
402 | |||
403 | } | ||
404 | return 1; | ||
405 | } | ||
406 | |||
407 | static int handle_switch_rr6(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
408 | { | ||
409 | return 1; | ||
410 | } | ||
411 | |||
412 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) | ||
413 | { | ||
414 | |||
415 | ktime_t kt; | ||
416 | long itc_diff; | ||
417 | unsigned long vcpu_now_itc; | ||
418 | |||
419 | unsigned long expires; | ||
420 | struct hrtimer *p_ht = &vcpu->arch.hlt_timer; | ||
421 | unsigned long cyc_per_usec = local_cpu_data->cyc_per_usec; | ||
422 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
423 | |||
424 | vcpu_now_itc = ia64_getreg(_IA64_REG_AR_ITC) + vcpu->arch.itc_offset; | ||
425 | |||
426 | if (time_after(vcpu_now_itc, vpd->itm)) { | ||
427 | vcpu->arch.timer_check = 1; | ||
428 | return 1; | ||
429 | } | ||
430 | itc_diff = vpd->itm - vcpu_now_itc; | ||
431 | if (itc_diff < 0) | ||
432 | itc_diff = -itc_diff; | ||
433 | |||
434 | expires = div64_64(itc_diff, cyc_per_usec); | ||
435 | kt = ktime_set(0, 1000 * expires); | ||
436 | vcpu->arch.ht_active = 1; | ||
437 | hrtimer_start(p_ht, kt, HRTIMER_MODE_ABS); | ||
438 | |||
439 | if (irqchip_in_kernel(vcpu->kvm)) { | ||
440 | vcpu->arch.mp_state = KVM_MP_STATE_HALTED; | ||
441 | kvm_vcpu_block(vcpu); | ||
442 | hrtimer_cancel(p_ht); | ||
443 | vcpu->arch.ht_active = 0; | ||
444 | |||
445 | if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) | ||
446 | return -EINTR; | ||
447 | return 1; | ||
448 | } else { | ||
449 | printk(KERN_ERR"kvm: Unsupported userspace halt!"); | ||
450 | return 0; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | static int handle_vm_shutdown(struct kvm_vcpu *vcpu, | ||
455 | struct kvm_run *kvm_run) | ||
456 | { | ||
457 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int handle_external_interrupt(struct kvm_vcpu *vcpu, | ||
462 | struct kvm_run *kvm_run) | ||
463 | { | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | static int (*kvm_vti_exit_handlers[])(struct kvm_vcpu *vcpu, | ||
468 | struct kvm_run *kvm_run) = { | ||
469 | [EXIT_REASON_VM_PANIC] = handle_vm_error, | ||
470 | [EXIT_REASON_MMIO_INSTRUCTION] = handle_mmio, | ||
471 | [EXIT_REASON_PAL_CALL] = handle_pal_call, | ||
472 | [EXIT_REASON_SAL_CALL] = handle_sal_call, | ||
473 | [EXIT_REASON_SWITCH_RR6] = handle_switch_rr6, | ||
474 | [EXIT_REASON_VM_DESTROY] = handle_vm_shutdown, | ||
475 | [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, | ||
476 | [EXIT_REASON_IPI] = handle_ipi, | ||
477 | [EXIT_REASON_PTC_G] = handle_global_purge, | ||
478 | |||
479 | }; | ||
480 | |||
481 | static const int kvm_vti_max_exit_handlers = | ||
482 | sizeof(kvm_vti_exit_handlers)/sizeof(*kvm_vti_exit_handlers); | ||
483 | |||
484 | static void kvm_prepare_guest_switch(struct kvm_vcpu *vcpu) | ||
485 | { | ||
486 | } | ||
487 | |||
488 | static uint32_t kvm_get_exit_reason(struct kvm_vcpu *vcpu) | ||
489 | { | ||
490 | struct exit_ctl_data *p_exit_data; | ||
491 | |||
492 | p_exit_data = kvm_get_exit_data(vcpu); | ||
493 | return p_exit_data->exit_reason; | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * The guest has exited. See if we can fix it or if we need userspace | ||
498 | * assistance. | ||
499 | */ | ||
500 | static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||
501 | { | ||
502 | u32 exit_reason = kvm_get_exit_reason(vcpu); | ||
503 | vcpu->arch.last_exit = exit_reason; | ||
504 | |||
505 | if (exit_reason < kvm_vti_max_exit_handlers | ||
506 | && kvm_vti_exit_handlers[exit_reason]) | ||
507 | return kvm_vti_exit_handlers[exit_reason](vcpu, kvm_run); | ||
508 | else { | ||
509 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | ||
510 | kvm_run->hw.hardware_exit_reason = exit_reason; | ||
511 | } | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static inline void vti_set_rr6(unsigned long rr6) | ||
516 | { | ||
517 | ia64_set_rr(RR6, rr6); | ||
518 | ia64_srlz_i(); | ||
519 | } | ||
520 | |||
521 | static int kvm_insert_vmm_mapping(struct kvm_vcpu *vcpu) | ||
522 | { | ||
523 | unsigned long pte; | ||
524 | struct kvm *kvm = vcpu->kvm; | ||
525 | int r; | ||
526 | |||
527 | /*Insert a pair of tr to map vmm*/ | ||
528 | pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), PAGE_KERNEL)); | ||
529 | r = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT); | ||
530 | if (r < 0) | ||
531 | goto out; | ||
532 | vcpu->arch.vmm_tr_slot = r; | ||
533 | /*Insert a pairt of tr to map data of vm*/ | ||
534 | pte = pte_val(mk_pte_phys(__pa(kvm->arch.vm_base), PAGE_KERNEL)); | ||
535 | r = ia64_itr_entry(0x3, KVM_VM_DATA_BASE, | ||
536 | pte, KVM_VM_DATA_SHIFT); | ||
537 | if (r < 0) | ||
538 | goto out; | ||
539 | vcpu->arch.vm_tr_slot = r; | ||
540 | r = 0; | ||
541 | out: | ||
542 | return r; | ||
543 | |||
544 | } | ||
545 | |||
546 | static void kvm_purge_vmm_mapping(struct kvm_vcpu *vcpu) | ||
547 | { | ||
548 | |||
549 | ia64_ptr_entry(0x3, vcpu->arch.vmm_tr_slot); | ||
550 | ia64_ptr_entry(0x3, vcpu->arch.vm_tr_slot); | ||
551 | |||
552 | } | ||
553 | |||
554 | static int kvm_vcpu_pre_transition(struct kvm_vcpu *vcpu) | ||
555 | { | ||
556 | int cpu = smp_processor_id(); | ||
557 | |||
558 | if (vcpu->arch.last_run_cpu != cpu || | ||
559 | per_cpu(last_vcpu, cpu) != vcpu) { | ||
560 | per_cpu(last_vcpu, cpu) = vcpu; | ||
561 | vcpu->arch.last_run_cpu = cpu; | ||
562 | kvm_flush_tlb_all(); | ||
563 | } | ||
564 | |||
565 | vcpu->arch.host_rr6 = ia64_get_rr(RR6); | ||
566 | vti_set_rr6(vcpu->arch.vmm_rr); | ||
567 | return kvm_insert_vmm_mapping(vcpu); | ||
568 | } | ||
569 | static void kvm_vcpu_post_transition(struct kvm_vcpu *vcpu) | ||
570 | { | ||
571 | kvm_purge_vmm_mapping(vcpu); | ||
572 | vti_set_rr6(vcpu->arch.host_rr6); | ||
573 | } | ||
574 | |||
575 | static int vti_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
576 | { | ||
577 | union context *host_ctx, *guest_ctx; | ||
578 | int r; | ||
579 | |||
580 | /*Get host and guest context with guest address space.*/ | ||
581 | host_ctx = kvm_get_host_context(vcpu); | ||
582 | guest_ctx = kvm_get_guest_context(vcpu); | ||
583 | |||
584 | r = kvm_vcpu_pre_transition(vcpu); | ||
585 | if (r < 0) | ||
586 | goto out; | ||
587 | kvm_vmm_info->tramp_entry(host_ctx, guest_ctx); | ||
588 | kvm_vcpu_post_transition(vcpu); | ||
589 | r = 0; | ||
590 | out: | ||
591 | return r; | ||
592 | } | ||
593 | |||
594 | static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
595 | { | ||
596 | int r; | ||
597 | |||
598 | again: | ||
599 | preempt_disable(); | ||
600 | |||
601 | kvm_prepare_guest_switch(vcpu); | ||
602 | local_irq_disable(); | ||
603 | |||
604 | if (signal_pending(current)) { | ||
605 | local_irq_enable(); | ||
606 | preempt_enable(); | ||
607 | r = -EINTR; | ||
608 | kvm_run->exit_reason = KVM_EXIT_INTR; | ||
609 | goto out; | ||
610 | } | ||
611 | |||
612 | vcpu->guest_mode = 1; | ||
613 | kvm_guest_enter(); | ||
614 | |||
615 | r = vti_vcpu_run(vcpu, kvm_run); | ||
616 | if (r < 0) { | ||
617 | local_irq_enable(); | ||
618 | preempt_enable(); | ||
619 | kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; | ||
620 | goto out; | ||
621 | } | ||
622 | |||
623 | vcpu->arch.launched = 1; | ||
624 | vcpu->guest_mode = 0; | ||
625 | local_irq_enable(); | ||
626 | |||
627 | /* | ||
628 | * We must have an instruction between local_irq_enable() and | ||
629 | * kvm_guest_exit(), so the timer interrupt isn't delayed by | ||
630 | * the interrupt shadow. The stat.exits increment will do nicely. | ||
631 | * But we need to prevent reordering, hence this barrier(): | ||
632 | */ | ||
633 | barrier(); | ||
634 | |||
635 | kvm_guest_exit(); | ||
636 | |||
637 | preempt_enable(); | ||
638 | |||
639 | r = kvm_handle_exit(kvm_run, vcpu); | ||
640 | |||
641 | if (r > 0) { | ||
642 | if (!need_resched()) | ||
643 | goto again; | ||
644 | } | ||
645 | |||
646 | out: | ||
647 | if (r > 0) { | ||
648 | kvm_resched(vcpu); | ||
649 | goto again; | ||
650 | } | ||
651 | |||
652 | return r; | ||
653 | } | ||
654 | |||
655 | static void kvm_set_mmio_data(struct kvm_vcpu *vcpu) | ||
656 | { | ||
657 | struct kvm_mmio_req *p = kvm_get_vcpu_ioreq(vcpu); | ||
658 | |||
659 | if (!vcpu->mmio_is_write) | ||
660 | memcpy(&p->data, vcpu->mmio_data, 8); | ||
661 | p->state = STATE_IORESP_READY; | ||
662 | } | ||
663 | |||
664 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
665 | { | ||
666 | int r; | ||
667 | sigset_t sigsaved; | ||
668 | |||
669 | vcpu_load(vcpu); | ||
670 | |||
671 | if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) { | ||
672 | kvm_vcpu_block(vcpu); | ||
673 | vcpu_put(vcpu); | ||
674 | return -EAGAIN; | ||
675 | } | ||
676 | |||
677 | if (vcpu->sigset_active) | ||
678 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); | ||
679 | |||
680 | if (vcpu->mmio_needed) { | ||
681 | memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); | ||
682 | kvm_set_mmio_data(vcpu); | ||
683 | vcpu->mmio_read_completed = 1; | ||
684 | vcpu->mmio_needed = 0; | ||
685 | } | ||
686 | r = __vcpu_run(vcpu, kvm_run); | ||
687 | |||
688 | if (vcpu->sigset_active) | ||
689 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
690 | |||
691 | vcpu_put(vcpu); | ||
692 | return r; | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * Allocate 16M memory for every vm to hold its specific data. | ||
697 | * Its memory map is defined in kvm_host.h. | ||
698 | */ | ||
699 | static struct kvm *kvm_alloc_kvm(void) | ||
700 | { | ||
701 | |||
702 | struct kvm *kvm; | ||
703 | uint64_t vm_base; | ||
704 | |||
705 | vm_base = __get_free_pages(GFP_KERNEL, get_order(KVM_VM_DATA_SIZE)); | ||
706 | |||
707 | if (!vm_base) | ||
708 | return ERR_PTR(-ENOMEM); | ||
709 | printk(KERN_DEBUG"kvm: VM data's base Address:0x%lx\n", vm_base); | ||
710 | |||
711 | /* Zero all pages before use! */ | ||
712 | memset((void *)vm_base, 0, KVM_VM_DATA_SIZE); | ||
713 | |||
714 | kvm = (struct kvm *)(vm_base + KVM_VM_OFS); | ||
715 | kvm->arch.vm_base = vm_base; | ||
716 | |||
717 | return kvm; | ||
718 | } | ||
719 | |||
720 | struct kvm_io_range { | ||
721 | unsigned long start; | ||
722 | unsigned long size; | ||
723 | unsigned long type; | ||
724 | }; | ||
725 | |||
726 | static const struct kvm_io_range io_ranges[] = { | ||
727 | {VGA_IO_START, VGA_IO_SIZE, GPFN_FRAME_BUFFER}, | ||
728 | {MMIO_START, MMIO_SIZE, GPFN_LOW_MMIO}, | ||
729 | {LEGACY_IO_START, LEGACY_IO_SIZE, GPFN_LEGACY_IO}, | ||
730 | {IO_SAPIC_START, IO_SAPIC_SIZE, GPFN_IOSAPIC}, | ||
731 | {PIB_START, PIB_SIZE, GPFN_PIB}, | ||
732 | }; | ||
733 | |||
734 | static void kvm_build_io_pmt(struct kvm *kvm) | ||
735 | { | ||
736 | unsigned long i, j; | ||
737 | |||
738 | /* Mark I/O ranges */ | ||
739 | for (i = 0; i < (sizeof(io_ranges) / sizeof(struct kvm_io_range)); | ||
740 | i++) { | ||
741 | for (j = io_ranges[i].start; | ||
742 | j < io_ranges[i].start + io_ranges[i].size; | ||
743 | j += PAGE_SIZE) | ||
744 | kvm_set_pmt_entry(kvm, j >> PAGE_SHIFT, | ||
745 | io_ranges[i].type, 0); | ||
746 | } | ||
747 | |||
748 | } | ||
749 | |||
750 | /*Use unused rids to virtualize guest rid.*/ | ||
751 | #define GUEST_PHYSICAL_RR0 0x1739 | ||
752 | #define GUEST_PHYSICAL_RR4 0x2739 | ||
753 | #define VMM_INIT_RR 0x1660 | ||
754 | |||
755 | static void kvm_init_vm(struct kvm *kvm) | ||
756 | { | ||
757 | long vm_base; | ||
758 | |||
759 | BUG_ON(!kvm); | ||
760 | |||
761 | kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0; | ||
762 | kvm->arch.metaphysical_rr4 = GUEST_PHYSICAL_RR4; | ||
763 | kvm->arch.vmm_init_rr = VMM_INIT_RR; | ||
764 | |||
765 | vm_base = kvm->arch.vm_base; | ||
766 | if (vm_base) { | ||
767 | kvm->arch.vhpt_base = vm_base + KVM_VHPT_OFS; | ||
768 | kvm->arch.vtlb_base = vm_base + KVM_VTLB_OFS; | ||
769 | kvm->arch.vpd_base = vm_base + KVM_VPD_OFS; | ||
770 | } | ||
771 | |||
772 | /* | ||
773 | *Fill P2M entries for MMIO/IO ranges | ||
774 | */ | ||
775 | kvm_build_io_pmt(kvm); | ||
776 | |||
777 | } | ||
778 | |||
779 | struct kvm *kvm_arch_create_vm(void) | ||
780 | { | ||
781 | struct kvm *kvm = kvm_alloc_kvm(); | ||
782 | |||
783 | if (IS_ERR(kvm)) | ||
784 | return ERR_PTR(-ENOMEM); | ||
785 | kvm_init_vm(kvm); | ||
786 | |||
787 | return kvm; | ||
788 | |||
789 | } | ||
790 | |||
791 | static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, | ||
792 | struct kvm_irqchip *chip) | ||
793 | { | ||
794 | int r; | ||
795 | |||
796 | r = 0; | ||
797 | switch (chip->chip_id) { | ||
798 | case KVM_IRQCHIP_IOAPIC: | ||
799 | memcpy(&chip->chip.ioapic, ioapic_irqchip(kvm), | ||
800 | sizeof(struct kvm_ioapic_state)); | ||
801 | break; | ||
802 | default: | ||
803 | r = -EINVAL; | ||
804 | break; | ||
805 | } | ||
806 | return r; | ||
807 | } | ||
808 | |||
809 | static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | ||
810 | { | ||
811 | int r; | ||
812 | |||
813 | r = 0; | ||
814 | switch (chip->chip_id) { | ||
815 | case KVM_IRQCHIP_IOAPIC: | ||
816 | memcpy(ioapic_irqchip(kvm), | ||
817 | &chip->chip.ioapic, | ||
818 | sizeof(struct kvm_ioapic_state)); | ||
819 | break; | ||
820 | default: | ||
821 | r = -EINVAL; | ||
822 | break; | ||
823 | } | ||
824 | return r; | ||
825 | } | ||
826 | |||
827 | #define RESTORE_REGS(_x) vcpu->arch._x = regs->_x | ||
828 | |||
829 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
830 | { | ||
831 | int i; | ||
832 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
833 | int r; | ||
834 | |||
835 | vcpu_load(vcpu); | ||
836 | |||
837 | for (i = 0; i < 16; i++) { | ||
838 | vpd->vgr[i] = regs->vpd.vgr[i]; | ||
839 | vpd->vbgr[i] = regs->vpd.vbgr[i]; | ||
840 | } | ||
841 | for (i = 0; i < 128; i++) | ||
842 | vpd->vcr[i] = regs->vpd.vcr[i]; | ||
843 | vpd->vhpi = regs->vpd.vhpi; | ||
844 | vpd->vnat = regs->vpd.vnat; | ||
845 | vpd->vbnat = regs->vpd.vbnat; | ||
846 | vpd->vpsr = regs->vpd.vpsr; | ||
847 | |||
848 | vpd->vpr = regs->vpd.vpr; | ||
849 | |||
850 | r = -EFAULT; | ||
851 | r = copy_from_user(&vcpu->arch.guest, regs->saved_guest, | ||
852 | sizeof(union context)); | ||
853 | if (r) | ||
854 | goto out; | ||
855 | r = copy_from_user(vcpu + 1, regs->saved_stack + | ||
856 | sizeof(struct kvm_vcpu), | ||
857 | IA64_STK_OFFSET - sizeof(struct kvm_vcpu)); | ||
858 | if (r) | ||
859 | goto out; | ||
860 | vcpu->arch.exit_data = | ||
861 | ((struct kvm_vcpu *)(regs->saved_stack))->arch.exit_data; | ||
862 | |||
863 | RESTORE_REGS(mp_state); | ||
864 | RESTORE_REGS(vmm_rr); | ||
865 | memcpy(vcpu->arch.itrs, regs->itrs, sizeof(struct thash_data) * NITRS); | ||
866 | memcpy(vcpu->arch.dtrs, regs->dtrs, sizeof(struct thash_data) * NDTRS); | ||
867 | RESTORE_REGS(itr_regions); | ||
868 | RESTORE_REGS(dtr_regions); | ||
869 | RESTORE_REGS(tc_regions); | ||
870 | RESTORE_REGS(irq_check); | ||
871 | RESTORE_REGS(itc_check); | ||
872 | RESTORE_REGS(timer_check); | ||
873 | RESTORE_REGS(timer_pending); | ||
874 | RESTORE_REGS(last_itc); | ||
875 | for (i = 0; i < 8; i++) { | ||
876 | vcpu->arch.vrr[i] = regs->vrr[i]; | ||
877 | vcpu->arch.ibr[i] = regs->ibr[i]; | ||
878 | vcpu->arch.dbr[i] = regs->dbr[i]; | ||
879 | } | ||
880 | for (i = 0; i < 4; i++) | ||
881 | vcpu->arch.insvc[i] = regs->insvc[i]; | ||
882 | RESTORE_REGS(xtp); | ||
883 | RESTORE_REGS(metaphysical_rr0); | ||
884 | RESTORE_REGS(metaphysical_rr4); | ||
885 | RESTORE_REGS(metaphysical_saved_rr0); | ||
886 | RESTORE_REGS(metaphysical_saved_rr4); | ||
887 | RESTORE_REGS(fp_psr); | ||
888 | RESTORE_REGS(saved_gp); | ||
889 | |||
890 | vcpu->arch.irq_new_pending = 1; | ||
891 | vcpu->arch.itc_offset = regs->saved_itc - ia64_getreg(_IA64_REG_AR_ITC); | ||
892 | set_bit(KVM_REQ_RESUME, &vcpu->requests); | ||
893 | |||
894 | vcpu_put(vcpu); | ||
895 | r = 0; | ||
896 | out: | ||
897 | return r; | ||
898 | } | ||
899 | |||
900 | long kvm_arch_vm_ioctl(struct file *filp, | ||
901 | unsigned int ioctl, unsigned long arg) | ||
902 | { | ||
903 | struct kvm *kvm = filp->private_data; | ||
904 | void __user *argp = (void __user *)arg; | ||
905 | int r = -EINVAL; | ||
906 | |||
907 | switch (ioctl) { | ||
908 | case KVM_SET_MEMORY_REGION: { | ||
909 | struct kvm_memory_region kvm_mem; | ||
910 | struct kvm_userspace_memory_region kvm_userspace_mem; | ||
911 | |||
912 | r = -EFAULT; | ||
913 | if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) | ||
914 | goto out; | ||
915 | kvm_userspace_mem.slot = kvm_mem.slot; | ||
916 | kvm_userspace_mem.flags = kvm_mem.flags; | ||
917 | kvm_userspace_mem.guest_phys_addr = | ||
918 | kvm_mem.guest_phys_addr; | ||
919 | kvm_userspace_mem.memory_size = kvm_mem.memory_size; | ||
920 | r = kvm_vm_ioctl_set_memory_region(kvm, | ||
921 | &kvm_userspace_mem, 0); | ||
922 | if (r) | ||
923 | goto out; | ||
924 | break; | ||
925 | } | ||
926 | case KVM_CREATE_IRQCHIP: | ||
927 | r = -EFAULT; | ||
928 | r = kvm_ioapic_init(kvm); | ||
929 | if (r) | ||
930 | goto out; | ||
931 | break; | ||
932 | case KVM_IRQ_LINE: { | ||
933 | struct kvm_irq_level irq_event; | ||
934 | |||
935 | r = -EFAULT; | ||
936 | if (copy_from_user(&irq_event, argp, sizeof irq_event)) | ||
937 | goto out; | ||
938 | if (irqchip_in_kernel(kvm)) { | ||
939 | mutex_lock(&kvm->lock); | ||
940 | kvm_ioapic_set_irq(kvm->arch.vioapic, | ||
941 | irq_event.irq, | ||
942 | irq_event.level); | ||
943 | mutex_unlock(&kvm->lock); | ||
944 | r = 0; | ||
945 | } | ||
946 | break; | ||
947 | } | ||
948 | case KVM_GET_IRQCHIP: { | ||
949 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
950 | struct kvm_irqchip chip; | ||
951 | |||
952 | r = -EFAULT; | ||
953 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
954 | goto out; | ||
955 | r = -ENXIO; | ||
956 | if (!irqchip_in_kernel(kvm)) | ||
957 | goto out; | ||
958 | r = kvm_vm_ioctl_get_irqchip(kvm, &chip); | ||
959 | if (r) | ||
960 | goto out; | ||
961 | r = -EFAULT; | ||
962 | if (copy_to_user(argp, &chip, sizeof chip)) | ||
963 | goto out; | ||
964 | r = 0; | ||
965 | break; | ||
966 | } | ||
967 | case KVM_SET_IRQCHIP: { | ||
968 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
969 | struct kvm_irqchip chip; | ||
970 | |||
971 | r = -EFAULT; | ||
972 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
973 | goto out; | ||
974 | r = -ENXIO; | ||
975 | if (!irqchip_in_kernel(kvm)) | ||
976 | goto out; | ||
977 | r = kvm_vm_ioctl_set_irqchip(kvm, &chip); | ||
978 | if (r) | ||
979 | goto out; | ||
980 | r = 0; | ||
981 | break; | ||
982 | } | ||
983 | default: | ||
984 | ; | ||
985 | } | ||
986 | out: | ||
987 | return r; | ||
988 | } | ||
989 | |||
990 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||
991 | struct kvm_sregs *sregs) | ||
992 | { | ||
993 | return -EINVAL; | ||
994 | } | ||
995 | |||
996 | int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||
997 | struct kvm_sregs *sregs) | ||
998 | { | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | } | ||
1002 | int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||
1003 | struct kvm_translation *tr) | ||
1004 | { | ||
1005 | |||
1006 | return -EINVAL; | ||
1007 | } | ||
1008 | |||
1009 | static int kvm_alloc_vmm_area(void) | ||
1010 | { | ||
1011 | if (!kvm_vmm_base && (kvm_vm_buffer_size < KVM_VM_BUFFER_SIZE)) { | ||
1012 | kvm_vmm_base = __get_free_pages(GFP_KERNEL, | ||
1013 | get_order(KVM_VMM_SIZE)); | ||
1014 | if (!kvm_vmm_base) | ||
1015 | return -ENOMEM; | ||
1016 | |||
1017 | memset((void *)kvm_vmm_base, 0, KVM_VMM_SIZE); | ||
1018 | kvm_vm_buffer = kvm_vmm_base + VMM_SIZE; | ||
1019 | |||
1020 | printk(KERN_DEBUG"kvm:VMM's Base Addr:0x%lx, vm_buffer:0x%lx\n", | ||
1021 | kvm_vmm_base, kvm_vm_buffer); | ||
1022 | } | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static void kvm_free_vmm_area(void) | ||
1028 | { | ||
1029 | if (kvm_vmm_base) { | ||
1030 | /*Zero this area before free to avoid bits leak!!*/ | ||
1031 | memset((void *)kvm_vmm_base, 0, KVM_VMM_SIZE); | ||
1032 | free_pages(kvm_vmm_base, get_order(KVM_VMM_SIZE)); | ||
1033 | kvm_vmm_base = 0; | ||
1034 | kvm_vm_buffer = 0; | ||
1035 | kvm_vsa_base = 0; | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | /* | ||
1040 | * Make sure that a cpu that is being hot-unplugged does not have any vcpus | ||
1041 | * cached on it. Leave it as blank for IA64. | ||
1042 | */ | ||
1043 | void decache_vcpus_on_cpu(int cpu) | ||
1044 | { | ||
1045 | } | ||
1046 | |||
1047 | static void vti_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
1048 | { | ||
1049 | } | ||
1050 | |||
1051 | static int vti_init_vpd(struct kvm_vcpu *vcpu) | ||
1052 | { | ||
1053 | int i; | ||
1054 | union cpuid3_t cpuid3; | ||
1055 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
1056 | |||
1057 | if (IS_ERR(vpd)) | ||
1058 | return PTR_ERR(vpd); | ||
1059 | |||
1060 | /* CPUID init */ | ||
1061 | for (i = 0; i < 5; i++) | ||
1062 | vpd->vcpuid[i] = ia64_get_cpuid(i); | ||
1063 | |||
1064 | /* Limit the CPUID number to 5 */ | ||
1065 | cpuid3.value = vpd->vcpuid[3]; | ||
1066 | cpuid3.number = 4; /* 5 - 1 */ | ||
1067 | vpd->vcpuid[3] = cpuid3.value; | ||
1068 | |||
1069 | /*Set vac and vdc fields*/ | ||
1070 | vpd->vac.a_from_int_cr = 1; | ||
1071 | vpd->vac.a_to_int_cr = 1; | ||
1072 | vpd->vac.a_from_psr = 1; | ||
1073 | vpd->vac.a_from_cpuid = 1; | ||
1074 | vpd->vac.a_cover = 1; | ||
1075 | vpd->vac.a_bsw = 1; | ||
1076 | vpd->vac.a_int = 1; | ||
1077 | vpd->vdc.d_vmsw = 1; | ||
1078 | |||
1079 | /*Set virtual buffer*/ | ||
1080 | vpd->virt_env_vaddr = KVM_VM_BUFFER_BASE; | ||
1081 | |||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static int vti_create_vp(struct kvm_vcpu *vcpu) | ||
1086 | { | ||
1087 | long ret; | ||
1088 | struct vpd *vpd = vcpu->arch.vpd; | ||
1089 | unsigned long vmm_ivt; | ||
1090 | |||
1091 | vmm_ivt = kvm_vmm_info->vmm_ivt; | ||
1092 | |||
1093 | printk(KERN_DEBUG "kvm: vcpu:%p,ivt: 0x%lx\n", vcpu, vmm_ivt); | ||
1094 | |||
1095 | ret = ia64_pal_vp_create((u64 *)vpd, (u64 *)vmm_ivt, 0); | ||
1096 | |||
1097 | if (ret) { | ||
1098 | printk(KERN_ERR"kvm: ia64_pal_vp_create failed!\n"); | ||
1099 | return -EINVAL; | ||
1100 | } | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static void init_ptce_info(struct kvm_vcpu *vcpu) | ||
1105 | { | ||
1106 | ia64_ptce_info_t ptce = {0}; | ||
1107 | |||
1108 | ia64_get_ptce(&ptce); | ||
1109 | vcpu->arch.ptce_base = ptce.base; | ||
1110 | vcpu->arch.ptce_count[0] = ptce.count[0]; | ||
1111 | vcpu->arch.ptce_count[1] = ptce.count[1]; | ||
1112 | vcpu->arch.ptce_stride[0] = ptce.stride[0]; | ||
1113 | vcpu->arch.ptce_stride[1] = ptce.stride[1]; | ||
1114 | } | ||
1115 | |||
1116 | static void kvm_migrate_hlt_timer(struct kvm_vcpu *vcpu) | ||
1117 | { | ||
1118 | struct hrtimer *p_ht = &vcpu->arch.hlt_timer; | ||
1119 | |||
1120 | if (hrtimer_cancel(p_ht)) | ||
1121 | hrtimer_start(p_ht, p_ht->expires, HRTIMER_MODE_ABS); | ||
1122 | } | ||
1123 | |||
1124 | static enum hrtimer_restart hlt_timer_fn(struct hrtimer *data) | ||
1125 | { | ||
1126 | struct kvm_vcpu *vcpu; | ||
1127 | wait_queue_head_t *q; | ||
1128 | |||
1129 | vcpu = container_of(data, struct kvm_vcpu, arch.hlt_timer); | ||
1130 | if (vcpu->arch.mp_state != KVM_MP_STATE_HALTED) | ||
1131 | goto out; | ||
1132 | |||
1133 | q = &vcpu->wq; | ||
1134 | if (waitqueue_active(q)) { | ||
1135 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
1136 | wake_up_interruptible(q); | ||
1137 | } | ||
1138 | out: | ||
1139 | vcpu->arch.timer_check = 1; | ||
1140 | return HRTIMER_NORESTART; | ||
1141 | } | ||
1142 | |||
1143 | #define PALE_RESET_ENTRY 0x80000000ffffffb0UL | ||
1144 | |||
1145 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | ||
1146 | { | ||
1147 | struct kvm_vcpu *v; | ||
1148 | int r; | ||
1149 | int i; | ||
1150 | long itc_offset; | ||
1151 | struct kvm *kvm = vcpu->kvm; | ||
1152 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1153 | |||
1154 | union context *p_ctx = &vcpu->arch.guest; | ||
1155 | struct kvm_vcpu *vmm_vcpu = to_guest(vcpu->kvm, vcpu); | ||
1156 | |||
1157 | /*Init vcpu context for first run.*/ | ||
1158 | if (IS_ERR(vmm_vcpu)) | ||
1159 | return PTR_ERR(vmm_vcpu); | ||
1160 | |||
1161 | if (vcpu->vcpu_id == 0) { | ||
1162 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
1163 | |||
1164 | /*Set entry address for first run.*/ | ||
1165 | regs->cr_iip = PALE_RESET_ENTRY; | ||
1166 | |||
1167 | /*Initilize itc offset for vcpus*/ | ||
1168 | itc_offset = 0UL - ia64_getreg(_IA64_REG_AR_ITC); | ||
1169 | for (i = 0; i < MAX_VCPU_NUM; i++) { | ||
1170 | v = (struct kvm_vcpu *)((char *)vcpu + VCPU_SIZE * i); | ||
1171 | v->arch.itc_offset = itc_offset; | ||
1172 | v->arch.last_itc = 0; | ||
1173 | } | ||
1174 | } else | ||
1175 | vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED; | ||
1176 | |||
1177 | r = -ENOMEM; | ||
1178 | vcpu->arch.apic = kzalloc(sizeof(struct kvm_lapic), GFP_KERNEL); | ||
1179 | if (!vcpu->arch.apic) | ||
1180 | goto out; | ||
1181 | vcpu->arch.apic->vcpu = vcpu; | ||
1182 | |||
1183 | p_ctx->gr[1] = 0; | ||
1184 | p_ctx->gr[12] = (unsigned long)((char *)vmm_vcpu + IA64_STK_OFFSET); | ||
1185 | p_ctx->gr[13] = (unsigned long)vmm_vcpu; | ||
1186 | p_ctx->psr = 0x1008522000UL; | ||
1187 | p_ctx->ar[40] = FPSR_DEFAULT; /*fpsr*/ | ||
1188 | p_ctx->caller_unat = 0; | ||
1189 | p_ctx->pr = 0x0; | ||
1190 | p_ctx->ar[36] = 0x0; /*unat*/ | ||
1191 | p_ctx->ar[19] = 0x0; /*rnat*/ | ||
1192 | p_ctx->ar[18] = (unsigned long)vmm_vcpu + | ||
1193 | ((sizeof(struct kvm_vcpu)+15) & ~15); | ||
1194 | p_ctx->ar[64] = 0x0; /*pfs*/ | ||
1195 | p_ctx->cr[0] = 0x7e04UL; | ||
1196 | p_ctx->cr[2] = (unsigned long)kvm_vmm_info->vmm_ivt; | ||
1197 | p_ctx->cr[8] = 0x3c; | ||
1198 | |||
1199 | /*Initilize region register*/ | ||
1200 | p_ctx->rr[0] = 0x30; | ||
1201 | p_ctx->rr[1] = 0x30; | ||
1202 | p_ctx->rr[2] = 0x30; | ||
1203 | p_ctx->rr[3] = 0x30; | ||
1204 | p_ctx->rr[4] = 0x30; | ||
1205 | p_ctx->rr[5] = 0x30; | ||
1206 | p_ctx->rr[7] = 0x30; | ||
1207 | |||
1208 | /*Initilize branch register 0*/ | ||
1209 | p_ctx->br[0] = *(unsigned long *)kvm_vmm_info->vmm_entry; | ||
1210 | |||
1211 | vcpu->arch.vmm_rr = kvm->arch.vmm_init_rr; | ||
1212 | vcpu->arch.metaphysical_rr0 = kvm->arch.metaphysical_rr0; | ||
1213 | vcpu->arch.metaphysical_rr4 = kvm->arch.metaphysical_rr4; | ||
1214 | |||
1215 | hrtimer_init(&vcpu->arch.hlt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
1216 | vcpu->arch.hlt_timer.function = hlt_timer_fn; | ||
1217 | |||
1218 | vcpu->arch.last_run_cpu = -1; | ||
1219 | vcpu->arch.vpd = (struct vpd *)VPD_ADDR(vcpu->vcpu_id); | ||
1220 | vcpu->arch.vsa_base = kvm_vsa_base; | ||
1221 | vcpu->arch.__gp = kvm_vmm_gp; | ||
1222 | vcpu->arch.dirty_log_lock_pa = __pa(&kvm->arch.dirty_log_lock); | ||
1223 | vcpu->arch.vhpt.hash = (struct thash_data *)VHPT_ADDR(vcpu->vcpu_id); | ||
1224 | vcpu->arch.vtlb.hash = (struct thash_data *)VTLB_ADDR(vcpu->vcpu_id); | ||
1225 | init_ptce_info(vcpu); | ||
1226 | |||
1227 | r = 0; | ||
1228 | out: | ||
1229 | return r; | ||
1230 | } | ||
1231 | |||
1232 | static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id) | ||
1233 | { | ||
1234 | unsigned long psr; | ||
1235 | int r; | ||
1236 | |||
1237 | local_irq_save(psr); | ||
1238 | r = kvm_insert_vmm_mapping(vcpu); | ||
1239 | if (r) | ||
1240 | goto fail; | ||
1241 | r = kvm_vcpu_init(vcpu, vcpu->kvm, id); | ||
1242 | if (r) | ||
1243 | goto fail; | ||
1244 | |||
1245 | r = vti_init_vpd(vcpu); | ||
1246 | if (r) { | ||
1247 | printk(KERN_DEBUG"kvm: vpd init error!!\n"); | ||
1248 | goto uninit; | ||
1249 | } | ||
1250 | |||
1251 | r = vti_create_vp(vcpu); | ||
1252 | if (r) | ||
1253 | goto uninit; | ||
1254 | |||
1255 | kvm_purge_vmm_mapping(vcpu); | ||
1256 | local_irq_restore(psr); | ||
1257 | |||
1258 | return 0; | ||
1259 | uninit: | ||
1260 | kvm_vcpu_uninit(vcpu); | ||
1261 | fail: | ||
1262 | return r; | ||
1263 | } | ||
1264 | |||
1265 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | ||
1266 | unsigned int id) | ||
1267 | { | ||
1268 | struct kvm_vcpu *vcpu; | ||
1269 | unsigned long vm_base = kvm->arch.vm_base; | ||
1270 | int r; | ||
1271 | int cpu; | ||
1272 | |||
1273 | r = -ENOMEM; | ||
1274 | if (!vm_base) { | ||
1275 | printk(KERN_ERR"kvm: Create vcpu[%d] error!\n", id); | ||
1276 | goto fail; | ||
1277 | } | ||
1278 | vcpu = (struct kvm_vcpu *)(vm_base + KVM_VCPU_OFS + VCPU_SIZE * id); | ||
1279 | vcpu->kvm = kvm; | ||
1280 | |||
1281 | cpu = get_cpu(); | ||
1282 | vti_vcpu_load(vcpu, cpu); | ||
1283 | r = vti_vcpu_setup(vcpu, id); | ||
1284 | put_cpu(); | ||
1285 | |||
1286 | if (r) { | ||
1287 | printk(KERN_DEBUG"kvm: vcpu_setup error!!\n"); | ||
1288 | goto fail; | ||
1289 | } | ||
1290 | |||
1291 | return vcpu; | ||
1292 | fail: | ||
1293 | return ERR_PTR(r); | ||
1294 | } | ||
1295 | |||
1296 | int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||
1297 | { | ||
1298 | return 0; | ||
1299 | } | ||
1300 | |||
1301 | int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
1302 | { | ||
1303 | return -EINVAL; | ||
1304 | } | ||
1305 | |||
1306 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
1307 | { | ||
1308 | return -EINVAL; | ||
1309 | } | ||
1310 | |||
1311 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | ||
1312 | struct kvm_debug_guest *dbg) | ||
1313 | { | ||
1314 | return -EINVAL; | ||
1315 | } | ||
1316 | |||
1317 | static void free_kvm(struct kvm *kvm) | ||
1318 | { | ||
1319 | unsigned long vm_base = kvm->arch.vm_base; | ||
1320 | |||
1321 | if (vm_base) { | ||
1322 | memset((void *)vm_base, 0, KVM_VM_DATA_SIZE); | ||
1323 | free_pages(vm_base, get_order(KVM_VM_DATA_SIZE)); | ||
1324 | } | ||
1325 | |||
1326 | } | ||
1327 | |||
1328 | static void kvm_release_vm_pages(struct kvm *kvm) | ||
1329 | { | ||
1330 | struct kvm_memory_slot *memslot; | ||
1331 | int i, j; | ||
1332 | unsigned long base_gfn; | ||
1333 | |||
1334 | for (i = 0; i < kvm->nmemslots; i++) { | ||
1335 | memslot = &kvm->memslots[i]; | ||
1336 | base_gfn = memslot->base_gfn; | ||
1337 | |||
1338 | for (j = 0; j < memslot->npages; j++) { | ||
1339 | if (memslot->rmap[j]) | ||
1340 | put_page((struct page *)memslot->rmap[j]); | ||
1341 | } | ||
1342 | } | ||
1343 | } | ||
1344 | |||
1345 | void kvm_arch_destroy_vm(struct kvm *kvm) | ||
1346 | { | ||
1347 | kfree(kvm->arch.vioapic); | ||
1348 | kvm_release_vm_pages(kvm); | ||
1349 | kvm_free_physmem(kvm); | ||
1350 | free_kvm(kvm); | ||
1351 | } | ||
1352 | |||
1353 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | ||
1354 | { | ||
1355 | } | ||
1356 | |||
1357 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
1358 | { | ||
1359 | if (cpu != vcpu->cpu) { | ||
1360 | vcpu->cpu = cpu; | ||
1361 | if (vcpu->arch.ht_active) | ||
1362 | kvm_migrate_hlt_timer(vcpu); | ||
1363 | } | ||
1364 | } | ||
1365 | |||
1366 | #define SAVE_REGS(_x) regs->_x = vcpu->arch._x | ||
1367 | |||
1368 | int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
1369 | { | ||
1370 | int i; | ||
1371 | int r; | ||
1372 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
1373 | vcpu_load(vcpu); | ||
1374 | |||
1375 | for (i = 0; i < 16; i++) { | ||
1376 | regs->vpd.vgr[i] = vpd->vgr[i]; | ||
1377 | regs->vpd.vbgr[i] = vpd->vbgr[i]; | ||
1378 | } | ||
1379 | for (i = 0; i < 128; i++) | ||
1380 | regs->vpd.vcr[i] = vpd->vcr[i]; | ||
1381 | regs->vpd.vhpi = vpd->vhpi; | ||
1382 | regs->vpd.vnat = vpd->vnat; | ||
1383 | regs->vpd.vbnat = vpd->vbnat; | ||
1384 | regs->vpd.vpsr = vpd->vpsr; | ||
1385 | regs->vpd.vpr = vpd->vpr; | ||
1386 | |||
1387 | r = -EFAULT; | ||
1388 | r = copy_to_user(regs->saved_guest, &vcpu->arch.guest, | ||
1389 | sizeof(union context)); | ||
1390 | if (r) | ||
1391 | goto out; | ||
1392 | r = copy_to_user(regs->saved_stack, (void *)vcpu, IA64_STK_OFFSET); | ||
1393 | if (r) | ||
1394 | goto out; | ||
1395 | SAVE_REGS(mp_state); | ||
1396 | SAVE_REGS(vmm_rr); | ||
1397 | memcpy(regs->itrs, vcpu->arch.itrs, sizeof(struct thash_data) * NITRS); | ||
1398 | memcpy(regs->dtrs, vcpu->arch.dtrs, sizeof(struct thash_data) * NDTRS); | ||
1399 | SAVE_REGS(itr_regions); | ||
1400 | SAVE_REGS(dtr_regions); | ||
1401 | SAVE_REGS(tc_regions); | ||
1402 | SAVE_REGS(irq_check); | ||
1403 | SAVE_REGS(itc_check); | ||
1404 | SAVE_REGS(timer_check); | ||
1405 | SAVE_REGS(timer_pending); | ||
1406 | SAVE_REGS(last_itc); | ||
1407 | for (i = 0; i < 8; i++) { | ||
1408 | regs->vrr[i] = vcpu->arch.vrr[i]; | ||
1409 | regs->ibr[i] = vcpu->arch.ibr[i]; | ||
1410 | regs->dbr[i] = vcpu->arch.dbr[i]; | ||
1411 | } | ||
1412 | for (i = 0; i < 4; i++) | ||
1413 | regs->insvc[i] = vcpu->arch.insvc[i]; | ||
1414 | regs->saved_itc = vcpu->arch.itc_offset + ia64_getreg(_IA64_REG_AR_ITC); | ||
1415 | SAVE_REGS(xtp); | ||
1416 | SAVE_REGS(metaphysical_rr0); | ||
1417 | SAVE_REGS(metaphysical_rr4); | ||
1418 | SAVE_REGS(metaphysical_saved_rr0); | ||
1419 | SAVE_REGS(metaphysical_saved_rr4); | ||
1420 | SAVE_REGS(fp_psr); | ||
1421 | SAVE_REGS(saved_gp); | ||
1422 | vcpu_put(vcpu); | ||
1423 | r = 0; | ||
1424 | out: | ||
1425 | return r; | ||
1426 | } | ||
1427 | |||
1428 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | ||
1429 | { | ||
1430 | |||
1431 | hrtimer_cancel(&vcpu->arch.hlt_timer); | ||
1432 | kfree(vcpu->arch.apic); | ||
1433 | } | ||
1434 | |||
1435 | |||
1436 | long kvm_arch_vcpu_ioctl(struct file *filp, | ||
1437 | unsigned int ioctl, unsigned long arg) | ||
1438 | { | ||
1439 | return -EINVAL; | ||
1440 | } | ||
1441 | |||
1442 | int kvm_arch_set_memory_region(struct kvm *kvm, | ||
1443 | struct kvm_userspace_memory_region *mem, | ||
1444 | struct kvm_memory_slot old, | ||
1445 | int user_alloc) | ||
1446 | { | ||
1447 | unsigned long i; | ||
1448 | struct page *page; | ||
1449 | int npages = mem->memory_size >> PAGE_SHIFT; | ||
1450 | struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot]; | ||
1451 | unsigned long base_gfn = memslot->base_gfn; | ||
1452 | |||
1453 | for (i = 0; i < npages; i++) { | ||
1454 | page = gfn_to_page(kvm, base_gfn + i); | ||
1455 | kvm_set_pmt_entry(kvm, base_gfn + i, | ||
1456 | page_to_pfn(page) << PAGE_SHIFT, | ||
1457 | _PAGE_AR_RWX|_PAGE_MA_WB); | ||
1458 | memslot->rmap[i] = (unsigned long)page; | ||
1459 | } | ||
1460 | |||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | |||
1465 | long kvm_arch_dev_ioctl(struct file *filp, | ||
1466 | unsigned int ioctl, unsigned long arg) | ||
1467 | { | ||
1468 | return -EINVAL; | ||
1469 | } | ||
1470 | |||
1471 | void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) | ||
1472 | { | ||
1473 | kvm_vcpu_uninit(vcpu); | ||
1474 | } | ||
1475 | |||
1476 | static int vti_cpu_has_kvm_support(void) | ||
1477 | { | ||
1478 | long avail = 1, status = 1, control = 1; | ||
1479 | long ret; | ||
1480 | |||
1481 | ret = ia64_pal_proc_get_features(&avail, &status, &control, 0); | ||
1482 | if (ret) | ||
1483 | goto out; | ||
1484 | |||
1485 | if (!(avail & PAL_PROC_VM_BIT)) | ||
1486 | goto out; | ||
1487 | |||
1488 | printk(KERN_DEBUG"kvm: Hardware Supports VT\n"); | ||
1489 | |||
1490 | ret = ia64_pal_vp_env_info(&kvm_vm_buffer_size, &vp_env_info); | ||
1491 | if (ret) | ||
1492 | goto out; | ||
1493 | printk(KERN_DEBUG"kvm: VM Buffer Size:0x%lx\n", kvm_vm_buffer_size); | ||
1494 | |||
1495 | if (!(vp_env_info & VP_OPCODE)) { | ||
1496 | printk(KERN_WARNING"kvm: No opcode ability on hardware, " | ||
1497 | "vm_env_info:0x%lx\n", vp_env_info); | ||
1498 | } | ||
1499 | |||
1500 | return 1; | ||
1501 | out: | ||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info, | ||
1506 | struct module *module) | ||
1507 | { | ||
1508 | unsigned long module_base; | ||
1509 | unsigned long vmm_size; | ||
1510 | |||
1511 | unsigned long vmm_offset, func_offset, fdesc_offset; | ||
1512 | struct fdesc *p_fdesc; | ||
1513 | |||
1514 | BUG_ON(!module); | ||
1515 | |||
1516 | if (!kvm_vmm_base) { | ||
1517 | printk("kvm: kvm area hasn't been initilized yet!!\n"); | ||
1518 | return -EFAULT; | ||
1519 | } | ||
1520 | |||
1521 | /*Calculate new position of relocated vmm module.*/ | ||
1522 | module_base = (unsigned long)module->module_core; | ||
1523 | vmm_size = module->core_size; | ||
1524 | if (unlikely(vmm_size > KVM_VMM_SIZE)) | ||
1525 | return -EFAULT; | ||
1526 | |||
1527 | memcpy((void *)kvm_vmm_base, (void *)module_base, vmm_size); | ||
1528 | kvm_flush_icache(kvm_vmm_base, vmm_size); | ||
1529 | |||
1530 | /*Recalculate kvm_vmm_info based on new VMM*/ | ||
1531 | vmm_offset = vmm_info->vmm_ivt - module_base; | ||
1532 | kvm_vmm_info->vmm_ivt = KVM_VMM_BASE + vmm_offset; | ||
1533 | printk(KERN_DEBUG"kvm: Relocated VMM's IVT Base Addr:%lx\n", | ||
1534 | kvm_vmm_info->vmm_ivt); | ||
1535 | |||
1536 | fdesc_offset = (unsigned long)vmm_info->vmm_entry - module_base; | ||
1537 | kvm_vmm_info->vmm_entry = (kvm_vmm_entry *)(KVM_VMM_BASE + | ||
1538 | fdesc_offset); | ||
1539 | func_offset = *(unsigned long *)vmm_info->vmm_entry - module_base; | ||
1540 | p_fdesc = (struct fdesc *)(kvm_vmm_base + fdesc_offset); | ||
1541 | p_fdesc->ip = KVM_VMM_BASE + func_offset; | ||
1542 | p_fdesc->gp = KVM_VMM_BASE+(p_fdesc->gp - module_base); | ||
1543 | |||
1544 | printk(KERN_DEBUG"kvm: Relocated VMM's Init Entry Addr:%lx\n", | ||
1545 | KVM_VMM_BASE+func_offset); | ||
1546 | |||
1547 | fdesc_offset = (unsigned long)vmm_info->tramp_entry - module_base; | ||
1548 | kvm_vmm_info->tramp_entry = (kvm_tramp_entry *)(KVM_VMM_BASE + | ||
1549 | fdesc_offset); | ||
1550 | func_offset = *(unsigned long *)vmm_info->tramp_entry - module_base; | ||
1551 | p_fdesc = (struct fdesc *)(kvm_vmm_base + fdesc_offset); | ||
1552 | p_fdesc->ip = KVM_VMM_BASE + func_offset; | ||
1553 | p_fdesc->gp = KVM_VMM_BASE + (p_fdesc->gp - module_base); | ||
1554 | |||
1555 | kvm_vmm_gp = p_fdesc->gp; | ||
1556 | |||
1557 | printk(KERN_DEBUG"kvm: Relocated VMM's Entry IP:%p\n", | ||
1558 | kvm_vmm_info->vmm_entry); | ||
1559 | printk(KERN_DEBUG"kvm: Relocated VMM's Trampoline Entry IP:0x%lx\n", | ||
1560 | KVM_VMM_BASE + func_offset); | ||
1561 | |||
1562 | return 0; | ||
1563 | } | ||
1564 | |||
1565 | int kvm_arch_init(void *opaque) | ||
1566 | { | ||
1567 | int r; | ||
1568 | struct kvm_vmm_info *vmm_info = (struct kvm_vmm_info *)opaque; | ||
1569 | |||
1570 | if (!vti_cpu_has_kvm_support()) { | ||
1571 | printk(KERN_ERR "kvm: No Hardware Virtualization Support!\n"); | ||
1572 | r = -EOPNOTSUPP; | ||
1573 | goto out; | ||
1574 | } | ||
1575 | |||
1576 | if (kvm_vmm_info) { | ||
1577 | printk(KERN_ERR "kvm: Already loaded VMM module!\n"); | ||
1578 | r = -EEXIST; | ||
1579 | goto out; | ||
1580 | } | ||
1581 | |||
1582 | r = -ENOMEM; | ||
1583 | kvm_vmm_info = kzalloc(sizeof(struct kvm_vmm_info), GFP_KERNEL); | ||
1584 | if (!kvm_vmm_info) | ||
1585 | goto out; | ||
1586 | |||
1587 | if (kvm_alloc_vmm_area()) | ||
1588 | goto out_free0; | ||
1589 | |||
1590 | r = kvm_relocate_vmm(vmm_info, vmm_info->module); | ||
1591 | if (r) | ||
1592 | goto out_free1; | ||
1593 | |||
1594 | return 0; | ||
1595 | |||
1596 | out_free1: | ||
1597 | kvm_free_vmm_area(); | ||
1598 | out_free0: | ||
1599 | kfree(kvm_vmm_info); | ||
1600 | out: | ||
1601 | return r; | ||
1602 | } | ||
1603 | |||
1604 | void kvm_arch_exit(void) | ||
1605 | { | ||
1606 | kvm_free_vmm_area(); | ||
1607 | kfree(kvm_vmm_info); | ||
1608 | kvm_vmm_info = NULL; | ||
1609 | } | ||
1610 | |||
1611 | static int kvm_ia64_sync_dirty_log(struct kvm *kvm, | ||
1612 | struct kvm_dirty_log *log) | ||
1613 | { | ||
1614 | struct kvm_memory_slot *memslot; | ||
1615 | int r, i; | ||
1616 | long n, base; | ||
1617 | unsigned long *dirty_bitmap = (unsigned long *)((void *)kvm - KVM_VM_OFS | ||
1618 | + KVM_MEM_DIRTY_LOG_OFS); | ||
1619 | |||
1620 | r = -EINVAL; | ||
1621 | if (log->slot >= KVM_MEMORY_SLOTS) | ||
1622 | goto out; | ||
1623 | |||
1624 | memslot = &kvm->memslots[log->slot]; | ||
1625 | r = -ENOENT; | ||
1626 | if (!memslot->dirty_bitmap) | ||
1627 | goto out; | ||
1628 | |||
1629 | n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; | ||
1630 | base = memslot->base_gfn / BITS_PER_LONG; | ||
1631 | |||
1632 | for (i = 0; i < n/sizeof(long); ++i) { | ||
1633 | memslot->dirty_bitmap[i] = dirty_bitmap[base + i]; | ||
1634 | dirty_bitmap[base + i] = 0; | ||
1635 | } | ||
1636 | r = 0; | ||
1637 | out: | ||
1638 | return r; | ||
1639 | } | ||
1640 | |||
1641 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | ||
1642 | struct kvm_dirty_log *log) | ||
1643 | { | ||
1644 | int r; | ||
1645 | int n; | ||
1646 | struct kvm_memory_slot *memslot; | ||
1647 | int is_dirty = 0; | ||
1648 | |||
1649 | spin_lock(&kvm->arch.dirty_log_lock); | ||
1650 | |||
1651 | r = kvm_ia64_sync_dirty_log(kvm, log); | ||
1652 | if (r) | ||
1653 | goto out; | ||
1654 | |||
1655 | r = kvm_get_dirty_log(kvm, log, &is_dirty); | ||
1656 | if (r) | ||
1657 | goto out; | ||
1658 | |||
1659 | /* If nothing is dirty, don't bother messing with page tables. */ | ||
1660 | if (is_dirty) { | ||
1661 | kvm_flush_remote_tlbs(kvm); | ||
1662 | memslot = &kvm->memslots[log->slot]; | ||
1663 | n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; | ||
1664 | memset(memslot->dirty_bitmap, 0, n); | ||
1665 | } | ||
1666 | r = 0; | ||
1667 | out: | ||
1668 | spin_unlock(&kvm->arch.dirty_log_lock); | ||
1669 | return r; | ||
1670 | } | ||
1671 | |||
1672 | int kvm_arch_hardware_setup(void) | ||
1673 | { | ||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | void kvm_arch_hardware_unsetup(void) | ||
1678 | { | ||
1679 | } | ||
1680 | |||
1681 | static void vcpu_kick_intr(void *info) | ||
1682 | { | ||
1683 | #ifdef DEBUG | ||
1684 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; | ||
1685 | printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu); | ||
1686 | #endif | ||
1687 | } | ||
1688 | |||
1689 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | ||
1690 | { | ||
1691 | int ipi_pcpu = vcpu->cpu; | ||
1692 | |||
1693 | if (waitqueue_active(&vcpu->wq)) | ||
1694 | wake_up_interruptible(&vcpu->wq); | ||
1695 | |||
1696 | if (vcpu->guest_mode) | ||
1697 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); | ||
1698 | } | ||
1699 | |||
1700 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig) | ||
1701 | { | ||
1702 | |||
1703 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
1704 | |||
1705 | if (!test_and_set_bit(vec, &vpd->irr[0])) { | ||
1706 | vcpu->arch.irq_new_pending = 1; | ||
1707 | if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) | ||
1708 | kvm_vcpu_kick(vcpu); | ||
1709 | else if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED) { | ||
1710 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
1711 | if (waitqueue_active(&vcpu->wq)) | ||
1712 | wake_up_interruptible(&vcpu->wq); | ||
1713 | } | ||
1714 | return 1; | ||
1715 | } | ||
1716 | return 0; | ||
1717 | } | ||
1718 | |||
1719 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) | ||
1720 | { | ||
1721 | return apic->vcpu->vcpu_id == dest; | ||
1722 | } | ||
1723 | |||
1724 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) | ||
1725 | { | ||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1729 | struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, | ||
1730 | unsigned long bitmap) | ||
1731 | { | ||
1732 | struct kvm_vcpu *lvcpu = kvm->vcpus[0]; | ||
1733 | int i; | ||
1734 | |||
1735 | for (i = 1; i < KVM_MAX_VCPUS; i++) { | ||
1736 | if (!kvm->vcpus[i]) | ||
1737 | continue; | ||
1738 | if (lvcpu->arch.xtp > kvm->vcpus[i]->arch.xtp) | ||
1739 | lvcpu = kvm->vcpus[i]; | ||
1740 | } | ||
1741 | |||
1742 | return lvcpu; | ||
1743 | } | ||
1744 | |||
1745 | static int find_highest_bits(int *dat) | ||
1746 | { | ||
1747 | u32 bits, bitnum; | ||
1748 | int i; | ||
1749 | |||
1750 | /* loop for all 256 bits */ | ||
1751 | for (i = 7; i >= 0 ; i--) { | ||
1752 | bits = dat[i]; | ||
1753 | if (bits) { | ||
1754 | bitnum = fls(bits); | ||
1755 | return i * 32 + bitnum - 1; | ||
1756 | } | ||
1757 | } | ||
1758 | |||
1759 | return -1; | ||
1760 | } | ||
1761 | |||
1762 | int kvm_highest_pending_irq(struct kvm_vcpu *vcpu) | ||
1763 | { | ||
1764 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
1765 | |||
1766 | if (vpd->irr[0] & (1UL << NMI_VECTOR)) | ||
1767 | return NMI_VECTOR; | ||
1768 | if (vpd->irr[0] & (1UL << ExtINT_VECTOR)) | ||
1769 | return ExtINT_VECTOR; | ||
1770 | |||
1771 | return find_highest_bits((int *)&vpd->irr[0]); | ||
1772 | } | ||
1773 | |||
1774 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) | ||
1775 | { | ||
1776 | if (kvm_highest_pending_irq(vcpu) != -1) | ||
1777 | return 1; | ||
1778 | return 0; | ||
1779 | } | ||
1780 | |||
1781 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | ||
1782 | { | ||
1783 | return 0; | ||
1784 | } | ||
1785 | |||
1786 | gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | ||
1787 | { | ||
1788 | return gfn; | ||
1789 | } | ||
1790 | |||
1791 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) | ||
1792 | { | ||
1793 | return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE; | ||
1794 | } | ||
1795 | |||
1796 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | ||
1797 | struct kvm_mp_state *mp_state) | ||
1798 | { | ||
1799 | return -EINVAL; | ||
1800 | } | ||
1801 | |||
1802 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | ||
1803 | struct kvm_mp_state *mp_state) | ||
1804 | { | ||
1805 | return -EINVAL; | ||
1806 | } | ||
diff --git a/arch/ia64/kvm/kvm_fw.c b/arch/ia64/kvm/kvm_fw.c new file mode 100644 index 000000000000..091f936c4485 --- /dev/null +++ b/arch/ia64/kvm/kvm_fw.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * PAL/SAL call delegation | ||
3 | * | ||
4 | * Copyright (c) 2004 Li Susie <susie.li@intel.com> | ||
5 | * Copyright (c) 2005 Yu Ke <ke.yu@intel.com> | ||
6 | * Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
19 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kvm_host.h> | ||
23 | #include <linux/smp.h> | ||
24 | |||
25 | #include "vti.h" | ||
26 | #include "misc.h" | ||
27 | |||
28 | #include <asm/pal.h> | ||
29 | #include <asm/sal.h> | ||
30 | #include <asm/tlb.h> | ||
31 | |||
32 | /* | ||
33 | * Handy macros to make sure that the PAL return values start out | ||
34 | * as something meaningful. | ||
35 | */ | ||
36 | #define INIT_PAL_STATUS_UNIMPLEMENTED(x) \ | ||
37 | { \ | ||
38 | x.status = PAL_STATUS_UNIMPLEMENTED; \ | ||
39 | x.v0 = 0; \ | ||
40 | x.v1 = 0; \ | ||
41 | x.v2 = 0; \ | ||
42 | } | ||
43 | |||
44 | #define INIT_PAL_STATUS_SUCCESS(x) \ | ||
45 | { \ | ||
46 | x.status = PAL_STATUS_SUCCESS; \ | ||
47 | x.v0 = 0; \ | ||
48 | x.v1 = 0; \ | ||
49 | x.v2 = 0; \ | ||
50 | } | ||
51 | |||
52 | static void kvm_get_pal_call_data(struct kvm_vcpu *vcpu, | ||
53 | u64 *gr28, u64 *gr29, u64 *gr30, u64 *gr31) { | ||
54 | struct exit_ctl_data *p; | ||
55 | |||
56 | if (vcpu) { | ||
57 | p = &vcpu->arch.exit_data; | ||
58 | if (p->exit_reason == EXIT_REASON_PAL_CALL) { | ||
59 | *gr28 = p->u.pal_data.gr28; | ||
60 | *gr29 = p->u.pal_data.gr29; | ||
61 | *gr30 = p->u.pal_data.gr30; | ||
62 | *gr31 = p->u.pal_data.gr31; | ||
63 | return ; | ||
64 | } | ||
65 | } | ||
66 | printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n"); | ||
67 | } | ||
68 | |||
69 | static void set_pal_result(struct kvm_vcpu *vcpu, | ||
70 | struct ia64_pal_retval result) { | ||
71 | |||
72 | struct exit_ctl_data *p; | ||
73 | |||
74 | p = kvm_get_exit_data(vcpu); | ||
75 | if (p && p->exit_reason == EXIT_REASON_PAL_CALL) { | ||
76 | p->u.pal_data.ret = result; | ||
77 | return ; | ||
78 | } | ||
79 | INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret); | ||
80 | } | ||
81 | |||
82 | static void set_sal_result(struct kvm_vcpu *vcpu, | ||
83 | struct sal_ret_values result) { | ||
84 | struct exit_ctl_data *p; | ||
85 | |||
86 | p = kvm_get_exit_data(vcpu); | ||
87 | if (p && p->exit_reason == EXIT_REASON_SAL_CALL) { | ||
88 | p->u.sal_data.ret = result; | ||
89 | return ; | ||
90 | } | ||
91 | printk(KERN_WARNING"Failed to set sal result!!\n"); | ||
92 | } | ||
93 | |||
94 | struct cache_flush_args { | ||
95 | u64 cache_type; | ||
96 | u64 operation; | ||
97 | u64 progress; | ||
98 | long status; | ||
99 | }; | ||
100 | |||
101 | cpumask_t cpu_cache_coherent_map; | ||
102 | |||
103 | static void remote_pal_cache_flush(void *data) | ||
104 | { | ||
105 | struct cache_flush_args *args = data; | ||
106 | long status; | ||
107 | u64 progress = args->progress; | ||
108 | |||
109 | status = ia64_pal_cache_flush(args->cache_type, args->operation, | ||
110 | &progress, NULL); | ||
111 | if (status != 0) | ||
112 | args->status = status; | ||
113 | } | ||
114 | |||
115 | static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu) | ||
116 | { | ||
117 | u64 gr28, gr29, gr30, gr31; | ||
118 | struct ia64_pal_retval result = {0, 0, 0, 0}; | ||
119 | struct cache_flush_args args = {0, 0, 0, 0}; | ||
120 | long psr; | ||
121 | |||
122 | gr28 = gr29 = gr30 = gr31 = 0; | ||
123 | kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31); | ||
124 | |||
125 | if (gr31 != 0) | ||
126 | printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu); | ||
127 | |||
128 | /* Always call Host Pal in int=1 */ | ||
129 | gr30 &= ~PAL_CACHE_FLUSH_CHK_INTRS; | ||
130 | args.cache_type = gr29; | ||
131 | args.operation = gr30; | ||
132 | smp_call_function(remote_pal_cache_flush, | ||
133 | (void *)&args, 1, 1); | ||
134 | if (args.status != 0) | ||
135 | printk(KERN_ERR"pal_cache_flush error!," | ||
136 | "status:0x%lx\n", args.status); | ||
137 | /* | ||
138 | * Call Host PAL cache flush | ||
139 | * Clear psr.ic when call PAL_CACHE_FLUSH | ||
140 | */ | ||
141 | local_irq_save(psr); | ||
142 | result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1, | ||
143 | &result.v0); | ||
144 | local_irq_restore(psr); | ||
145 | if (result.status != 0) | ||
146 | printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld" | ||
147 | "in1:%lx,in2:%lx\n", | ||
148 | vcpu, result.status, gr29, gr30); | ||
149 | |||
150 | #if 0 | ||
151 | if (gr29 == PAL_CACHE_TYPE_COHERENT) { | ||
152 | cpus_setall(vcpu->arch.cache_coherent_map); | ||
153 | cpu_clear(vcpu->cpu, vcpu->arch.cache_coherent_map); | ||
154 | cpus_setall(cpu_cache_coherent_map); | ||
155 | cpu_clear(vcpu->cpu, cpu_cache_coherent_map); | ||
156 | } | ||
157 | #endif | ||
158 | return result; | ||
159 | } | ||
160 | |||
161 | struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu) | ||
162 | { | ||
163 | |||
164 | struct ia64_pal_retval result; | ||
165 | |||
166 | PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0); | ||
167 | return result; | ||
168 | } | ||
169 | |||
170 | static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu) | ||
171 | { | ||
172 | |||
173 | struct ia64_pal_retval result; | ||
174 | |||
175 | PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0); | ||
176 | |||
177 | /* | ||
178 | * PAL_FREQ_BASE may not be implemented in some platforms, | ||
179 | * call SAL instead. | ||
180 | */ | ||
181 | if (result.v0 == 0) { | ||
182 | result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, | ||
183 | &result.v0, | ||
184 | &result.v1); | ||
185 | result.v2 = 0; | ||
186 | } | ||
187 | |||
188 | return result; | ||
189 | } | ||
190 | |||
191 | static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu) | ||
192 | { | ||
193 | |||
194 | struct ia64_pal_retval result; | ||
195 | |||
196 | PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0); | ||
197 | return result; | ||
198 | } | ||
199 | |||
200 | static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu) | ||
201 | { | ||
202 | struct ia64_pal_retval result; | ||
203 | |||
204 | INIT_PAL_STATUS_UNIMPLEMENTED(result); | ||
205 | return result; | ||
206 | } | ||
207 | |||
208 | static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu) | ||
209 | { | ||
210 | |||
211 | struct ia64_pal_retval result; | ||
212 | |||
213 | INIT_PAL_STATUS_SUCCESS(result); | ||
214 | return result; | ||
215 | } | ||
216 | |||
217 | static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu) | ||
218 | { | ||
219 | |||
220 | struct ia64_pal_retval result = {0, 0, 0, 0}; | ||
221 | long in0, in1, in2, in3; | ||
222 | |||
223 | kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3); | ||
224 | result.status = ia64_pal_proc_get_features(&result.v0, &result.v1, | ||
225 | &result.v2, in2); | ||
226 | |||
227 | return result; | ||
228 | } | ||
229 | |||
230 | static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu) | ||
231 | { | ||
232 | |||
233 | pal_cache_config_info_t ci; | ||
234 | long status; | ||
235 | unsigned long in0, in1, in2, in3, r9, r10; | ||
236 | |||
237 | kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3); | ||
238 | status = ia64_pal_cache_config_info(in1, in2, &ci); | ||
239 | r9 = ci.pcci_info_1.pcci1_data; | ||
240 | r10 = ci.pcci_info_2.pcci2_data; | ||
241 | return ((struct ia64_pal_retval){status, r9, r10, 0}); | ||
242 | } | ||
243 | |||
244 | #define GUEST_IMPL_VA_MSB 59 | ||
245 | #define GUEST_RID_BITS 18 | ||
246 | |||
247 | static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu) | ||
248 | { | ||
249 | |||
250 | pal_vm_info_1_u_t vminfo1; | ||
251 | pal_vm_info_2_u_t vminfo2; | ||
252 | struct ia64_pal_retval result; | ||
253 | |||
254 | PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0); | ||
255 | if (!result.status) { | ||
256 | vminfo1.pvi1_val = result.v0; | ||
257 | vminfo1.pal_vm_info_1_s.max_itr_entry = 8; | ||
258 | vminfo1.pal_vm_info_1_s.max_dtr_entry = 8; | ||
259 | result.v0 = vminfo1.pvi1_val; | ||
260 | vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB; | ||
261 | vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS; | ||
262 | result.v1 = vminfo2.pvi2_val; | ||
263 | } | ||
264 | |||
265 | return result; | ||
266 | } | ||
267 | |||
268 | static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu) | ||
269 | { | ||
270 | struct ia64_pal_retval result; | ||
271 | |||
272 | INIT_PAL_STATUS_UNIMPLEMENTED(result); | ||
273 | |||
274 | return result; | ||
275 | } | ||
276 | |||
277 | static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu) | ||
278 | { | ||
279 | u64 index = 0; | ||
280 | struct exit_ctl_data *p; | ||
281 | |||
282 | p = kvm_get_exit_data(vcpu); | ||
283 | if (p && (p->exit_reason == EXIT_REASON_PAL_CALL)) | ||
284 | index = p->u.pal_data.gr28; | ||
285 | |||
286 | return index; | ||
287 | } | ||
288 | |||
289 | int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
290 | { | ||
291 | |||
292 | u64 gr28; | ||
293 | struct ia64_pal_retval result; | ||
294 | int ret = 1; | ||
295 | |||
296 | gr28 = kvm_get_pal_call_index(vcpu); | ||
297 | /*printk("pal_call index:%lx\n",gr28);*/ | ||
298 | switch (gr28) { | ||
299 | case PAL_CACHE_FLUSH: | ||
300 | result = pal_cache_flush(vcpu); | ||
301 | break; | ||
302 | case PAL_CACHE_SUMMARY: | ||
303 | result = pal_cache_summary(vcpu); | ||
304 | break; | ||
305 | case PAL_HALT_LIGHT: | ||
306 | { | ||
307 | vcpu->arch.timer_pending = 1; | ||
308 | INIT_PAL_STATUS_SUCCESS(result); | ||
309 | if (kvm_highest_pending_irq(vcpu) == -1) | ||
310 | ret = kvm_emulate_halt(vcpu); | ||
311 | |||
312 | } | ||
313 | break; | ||
314 | |||
315 | case PAL_FREQ_RATIOS: | ||
316 | result = pal_freq_ratios(vcpu); | ||
317 | break; | ||
318 | |||
319 | case PAL_FREQ_BASE: | ||
320 | result = pal_freq_base(vcpu); | ||
321 | break; | ||
322 | |||
323 | case PAL_LOGICAL_TO_PHYSICAL : | ||
324 | result = pal_logical_to_physica(vcpu); | ||
325 | break; | ||
326 | |||
327 | case PAL_VM_SUMMARY : | ||
328 | result = pal_vm_summary(vcpu); | ||
329 | break; | ||
330 | |||
331 | case PAL_VM_INFO : | ||
332 | result = pal_vm_info(vcpu); | ||
333 | break; | ||
334 | case PAL_PLATFORM_ADDR : | ||
335 | result = pal_platform_addr(vcpu); | ||
336 | break; | ||
337 | case PAL_CACHE_INFO: | ||
338 | result = pal_cache_info(vcpu); | ||
339 | break; | ||
340 | case PAL_PTCE_INFO: | ||
341 | INIT_PAL_STATUS_SUCCESS(result); | ||
342 | result.v1 = (1L << 32) | 1L; | ||
343 | break; | ||
344 | case PAL_VM_PAGE_SIZE: | ||
345 | result.status = ia64_pal_vm_page_size(&result.v0, | ||
346 | &result.v1); | ||
347 | break; | ||
348 | case PAL_RSE_INFO: | ||
349 | result.status = ia64_pal_rse_info(&result.v0, | ||
350 | (pal_hints_u_t *)&result.v1); | ||
351 | break; | ||
352 | case PAL_PROC_GET_FEATURES: | ||
353 | result = pal_proc_get_features(vcpu); | ||
354 | break; | ||
355 | case PAL_DEBUG_INFO: | ||
356 | result.status = ia64_pal_debug_info(&result.v0, | ||
357 | &result.v1); | ||
358 | break; | ||
359 | case PAL_VERSION: | ||
360 | result.status = ia64_pal_version( | ||
361 | (pal_version_u_t *)&result.v0, | ||
362 | (pal_version_u_t *)&result.v1); | ||
363 | |||
364 | break; | ||
365 | case PAL_FIXED_ADDR: | ||
366 | result.status = PAL_STATUS_SUCCESS; | ||
367 | result.v0 = vcpu->vcpu_id; | ||
368 | break; | ||
369 | default: | ||
370 | INIT_PAL_STATUS_UNIMPLEMENTED(result); | ||
371 | printk(KERN_WARNING"kvm: Unsupported pal call," | ||
372 | " index:0x%lx\n", gr28); | ||
373 | } | ||
374 | set_pal_result(vcpu, result); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | static struct sal_ret_values sal_emulator(struct kvm *kvm, | ||
379 | long index, unsigned long in1, | ||
380 | unsigned long in2, unsigned long in3, | ||
381 | unsigned long in4, unsigned long in5, | ||
382 | unsigned long in6, unsigned long in7) | ||
383 | { | ||
384 | unsigned long r9 = 0; | ||
385 | unsigned long r10 = 0; | ||
386 | long r11 = 0; | ||
387 | long status; | ||
388 | |||
389 | status = 0; | ||
390 | switch (index) { | ||
391 | case SAL_FREQ_BASE: | ||
392 | status = ia64_sal_freq_base(in1, &r9, &r10); | ||
393 | break; | ||
394 | case SAL_PCI_CONFIG_READ: | ||
395 | printk(KERN_WARNING"kvm: Not allowed to call here!" | ||
396 | " SAL_PCI_CONFIG_READ\n"); | ||
397 | break; | ||
398 | case SAL_PCI_CONFIG_WRITE: | ||
399 | printk(KERN_WARNING"kvm: Not allowed to call here!" | ||
400 | " SAL_PCI_CONFIG_WRITE\n"); | ||
401 | break; | ||
402 | case SAL_SET_VECTORS: | ||
403 | if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { | ||
404 | if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) { | ||
405 | status = -2; | ||
406 | } else { | ||
407 | kvm->arch.rdv_sal_data.boot_ip = in2; | ||
408 | kvm->arch.rdv_sal_data.boot_gp = in3; | ||
409 | } | ||
410 | printk("Rendvous called! iip:%lx\n\n", in2); | ||
411 | } else | ||
412 | printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu." | ||
413 | "ignored...\n", in1); | ||
414 | break; | ||
415 | case SAL_GET_STATE_INFO: | ||
416 | /* No more info. */ | ||
417 | status = -5; | ||
418 | r9 = 0; | ||
419 | break; | ||
420 | case SAL_GET_STATE_INFO_SIZE: | ||
421 | /* Return a dummy size. */ | ||
422 | status = 0; | ||
423 | r9 = 128; | ||
424 | break; | ||
425 | case SAL_CLEAR_STATE_INFO: | ||
426 | /* Noop. */ | ||
427 | break; | ||
428 | case SAL_MC_RENDEZ: | ||
429 | printk(KERN_WARNING | ||
430 | "kvm: called SAL_MC_RENDEZ. ignored...\n"); | ||
431 | break; | ||
432 | case SAL_MC_SET_PARAMS: | ||
433 | printk(KERN_WARNING | ||
434 | "kvm: called SAL_MC_SET_PARAMS.ignored!\n"); | ||
435 | break; | ||
436 | case SAL_CACHE_FLUSH: | ||
437 | if (1) { | ||
438 | /*Flush using SAL. | ||
439 | This method is faster but has a side | ||
440 | effect on other vcpu running on | ||
441 | this cpu. */ | ||
442 | status = ia64_sal_cache_flush(in1); | ||
443 | } else { | ||
444 | /*Maybe need to implement the method | ||
445 | without side effect!*/ | ||
446 | status = 0; | ||
447 | } | ||
448 | break; | ||
449 | case SAL_CACHE_INIT: | ||
450 | printk(KERN_WARNING | ||
451 | "kvm: called SAL_CACHE_INIT. ignored...\n"); | ||
452 | break; | ||
453 | case SAL_UPDATE_PAL: | ||
454 | printk(KERN_WARNING | ||
455 | "kvm: CALLED SAL_UPDATE_PAL. ignored...\n"); | ||
456 | break; | ||
457 | default: | ||
458 | printk(KERN_WARNING"kvm: called SAL_CALL with unknown index." | ||
459 | " index:%ld\n", index); | ||
460 | status = -1; | ||
461 | break; | ||
462 | } | ||
463 | return ((struct sal_ret_values) {status, r9, r10, r11}); | ||
464 | } | ||
465 | |||
466 | static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1, | ||
467 | u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){ | ||
468 | |||
469 | struct exit_ctl_data *p; | ||
470 | |||
471 | p = kvm_get_exit_data(vcpu); | ||
472 | |||
473 | if (p) { | ||
474 | if (p->exit_reason == EXIT_REASON_SAL_CALL) { | ||
475 | *in0 = p->u.sal_data.in0; | ||
476 | *in1 = p->u.sal_data.in1; | ||
477 | *in2 = p->u.sal_data.in2; | ||
478 | *in3 = p->u.sal_data.in3; | ||
479 | *in4 = p->u.sal_data.in4; | ||
480 | *in5 = p->u.sal_data.in5; | ||
481 | *in6 = p->u.sal_data.in6; | ||
482 | *in7 = p->u.sal_data.in7; | ||
483 | return ; | ||
484 | } | ||
485 | } | ||
486 | *in0 = 0; | ||
487 | } | ||
488 | |||
489 | void kvm_sal_emul(struct kvm_vcpu *vcpu) | ||
490 | { | ||
491 | |||
492 | struct sal_ret_values result; | ||
493 | u64 index, in1, in2, in3, in4, in5, in6, in7; | ||
494 | |||
495 | kvm_get_sal_call_data(vcpu, &index, &in1, &in2, | ||
496 | &in3, &in4, &in5, &in6, &in7); | ||
497 | result = sal_emulator(vcpu->kvm, index, in1, in2, in3, | ||
498 | in4, in5, in6, in7); | ||
499 | set_sal_result(vcpu, result); | ||
500 | } | ||
diff --git a/arch/ia64/kvm/kvm_minstate.h b/arch/ia64/kvm/kvm_minstate.h new file mode 100644 index 000000000000..13980d9b8bcf --- /dev/null +++ b/arch/ia64/kvm/kvm_minstate.h | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * kvm_minstate.h: min save macros | ||
3 | * Copyright (c) 2007, Intel Corporation. | ||
4 | * | ||
5 | * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) | ||
6 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
19 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <asm/asmmacro.h> | ||
25 | #include <asm/types.h> | ||
26 | #include <asm/kregs.h> | ||
27 | #include "asm-offsets.h" | ||
28 | |||
29 | #define KVM_MINSTATE_START_SAVE_MIN \ | ||
30 | mov ar.rsc = 0;/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */\ | ||
31 | ;; \ | ||
32 | mov.m r28 = ar.rnat; \ | ||
33 | addl r22 = VMM_RBS_OFFSET,r1; /* compute base of RBS */ \ | ||
34 | ;; \ | ||
35 | lfetch.fault.excl.nt1 [r22]; \ | ||
36 | addl r1 = IA64_STK_OFFSET-VMM_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ | ||
37 | mov r23 = ar.bspstore; /* save ar.bspstore */ \ | ||
38 | ;; \ | ||
39 | mov ar.bspstore = r22; /* switch to kernel RBS */\ | ||
40 | ;; \ | ||
41 | mov r18 = ar.bsp; \ | ||
42 | mov ar.rsc = 0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ | ||
43 | |||
44 | |||
45 | |||
46 | #define KVM_MINSTATE_END_SAVE_MIN \ | ||
47 | bsw.1; /* switch back to bank 1 (must be last in insn group) */\ | ||
48 | ;; | ||
49 | |||
50 | |||
51 | #define PAL_VSA_SYNC_READ \ | ||
52 | /* begin to call pal vps sync_read */ \ | ||
53 | add r25 = VMM_VPD_BASE_OFFSET, r21; \ | ||
54 | adds r20 = VMM_VCPU_VSA_BASE_OFFSET, r21; /* entry point */ \ | ||
55 | ;; \ | ||
56 | ld8 r25 = [r25]; /* read vpd base */ \ | ||
57 | ld8 r20 = [r20]; \ | ||
58 | ;; \ | ||
59 | add r20 = PAL_VPS_SYNC_READ,r20; \ | ||
60 | ;; \ | ||
61 | { .mii; \ | ||
62 | nop 0x0; \ | ||
63 | mov r24 = ip; \ | ||
64 | mov b0 = r20; \ | ||
65 | ;; \ | ||
66 | }; \ | ||
67 | { .mmb; \ | ||
68 | add r24 = 0x20, r24; \ | ||
69 | nop 0x0; \ | ||
70 | br.cond.sptk b0; /* call the service */ \ | ||
71 | ;; \ | ||
72 | }; | ||
73 | |||
74 | |||
75 | |||
76 | #define KVM_MINSTATE_GET_CURRENT(reg) mov reg=r21 | ||
77 | |||
78 | /* | ||
79 | * KVM_DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves | ||
80 | * the minimum state necessary that allows us to turn psr.ic back | ||
81 | * on. | ||
82 | * | ||
83 | * Assumed state upon entry: | ||
84 | * psr.ic: off | ||
85 | * r31: contains saved predicates (pr) | ||
86 | * | ||
87 | * Upon exit, the state is as follows: | ||
88 | * psr.ic: off | ||
89 | * r2 = points to &pt_regs.r16 | ||
90 | * r8 = contents of ar.ccv | ||
91 | * r9 = contents of ar.csd | ||
92 | * r10 = contents of ar.ssd | ||
93 | * r11 = FPSR_DEFAULT | ||
94 | * r12 = kernel sp (kernel virtual address) | ||
95 | * r13 = points to current task_struct (kernel virtual address) | ||
96 | * p15 = TRUE if psr.i is set in cr.ipsr | ||
97 | * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: | ||
98 | * preserved | ||
99 | * | ||
100 | * Note that psr.ic is NOT turned on by this macro. This is so that | ||
101 | * we can pass interruption state as arguments to a handler. | ||
102 | */ | ||
103 | |||
104 | |||
105 | #define PT(f) (VMM_PT_REGS_##f##_OFFSET) | ||
106 | |||
107 | #define KVM_DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ | ||
108 | KVM_MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ | ||
109 | mov r27 = ar.rsc; /* M */ \ | ||
110 | mov r20 = r1; /* A */ \ | ||
111 | mov r25 = ar.unat; /* M */ \ | ||
112 | mov r29 = cr.ipsr; /* M */ \ | ||
113 | mov r26 = ar.pfs; /* I */ \ | ||
114 | mov r18 = cr.isr; \ | ||
115 | COVER; /* B;; (or nothing) */ \ | ||
116 | ;; \ | ||
117 | tbit.z p0,p15 = r29,IA64_PSR_I_BIT; \ | ||
118 | mov r1 = r16; \ | ||
119 | /* mov r21=r16; */ \ | ||
120 | /* switch from user to kernel RBS: */ \ | ||
121 | ;; \ | ||
122 | invala; /* M */ \ | ||
123 | SAVE_IFS; \ | ||
124 | ;; \ | ||
125 | KVM_MINSTATE_START_SAVE_MIN \ | ||
126 | adds r17 = 2*L1_CACHE_BYTES,r1;/* cache-line size */ \ | ||
127 | adds r16 = PT(CR_IPSR),r1; \ | ||
128 | ;; \ | ||
129 | lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ | ||
130 | st8 [r16] = r29; /* save cr.ipsr */ \ | ||
131 | ;; \ | ||
132 | lfetch.fault.excl.nt1 [r17]; \ | ||
133 | tbit.nz p15,p0 = r29,IA64_PSR_I_BIT; \ | ||
134 | mov r29 = b0 \ | ||
135 | ;; \ | ||
136 | adds r16 = PT(R8),r1; /* initialize first base pointer */\ | ||
137 | adds r17 = PT(R9),r1; /* initialize second base pointer */\ | ||
138 | ;; \ | ||
139 | .mem.offset 0,0; st8.spill [r16] = r8,16; \ | ||
140 | .mem.offset 8,0; st8.spill [r17] = r9,16; \ | ||
141 | ;; \ | ||
142 | .mem.offset 0,0; st8.spill [r16] = r10,24; \ | ||
143 | .mem.offset 8,0; st8.spill [r17] = r11,24; \ | ||
144 | ;; \ | ||
145 | mov r9 = cr.iip; /* M */ \ | ||
146 | mov r10 = ar.fpsr; /* M */ \ | ||
147 | ;; \ | ||
148 | st8 [r16] = r9,16; /* save cr.iip */ \ | ||
149 | st8 [r17] = r30,16; /* save cr.ifs */ \ | ||
150 | sub r18 = r18,r22; /* r18=RSE.ndirty*8 */ \ | ||
151 | ;; \ | ||
152 | st8 [r16] = r25,16; /* save ar.unat */ \ | ||
153 | st8 [r17] = r26,16; /* save ar.pfs */ \ | ||
154 | shl r18 = r18,16; /* calu ar.rsc used for "loadrs" */\ | ||
155 | ;; \ | ||
156 | st8 [r16] = r27,16; /* save ar.rsc */ \ | ||
157 | st8 [r17] = r28,16; /* save ar.rnat */ \ | ||
158 | ;; /* avoid RAW on r16 & r17 */ \ | ||
159 | st8 [r16] = r23,16; /* save ar.bspstore */ \ | ||
160 | st8 [r17] = r31,16; /* save predicates */ \ | ||
161 | ;; \ | ||
162 | st8 [r16] = r29,16; /* save b0 */ \ | ||
163 | st8 [r17] = r18,16; /* save ar.rsc value for "loadrs" */\ | ||
164 | ;; \ | ||
165 | .mem.offset 0,0; st8.spill [r16] = r20,16;/* save original r1 */ \ | ||
166 | .mem.offset 8,0; st8.spill [r17] = r12,16; \ | ||
167 | adds r12 = -16,r1; /* switch to kernel memory stack */ \ | ||
168 | ;; \ | ||
169 | .mem.offset 0,0; st8.spill [r16] = r13,16; \ | ||
170 | .mem.offset 8,0; st8.spill [r17] = r10,16; /* save ar.fpsr */\ | ||
171 | mov r13 = r21; /* establish `current' */ \ | ||
172 | ;; \ | ||
173 | .mem.offset 0,0; st8.spill [r16] = r15,16; \ | ||
174 | .mem.offset 8,0; st8.spill [r17] = r14,16; \ | ||
175 | ;; \ | ||
176 | .mem.offset 0,0; st8.spill [r16] = r2,16; \ | ||
177 | .mem.offset 8,0; st8.spill [r17] = r3,16; \ | ||
178 | adds r2 = VMM_PT_REGS_R16_OFFSET,r1; \ | ||
179 | ;; \ | ||
180 | adds r16 = VMM_VCPU_IIPA_OFFSET,r13; \ | ||
181 | adds r17 = VMM_VCPU_ISR_OFFSET,r13; \ | ||
182 | mov r26 = cr.iipa; \ | ||
183 | mov r27 = cr.isr; \ | ||
184 | ;; \ | ||
185 | st8 [r16] = r26; \ | ||
186 | st8 [r17] = r27; \ | ||
187 | ;; \ | ||
188 | EXTRA; \ | ||
189 | mov r8 = ar.ccv; \ | ||
190 | mov r9 = ar.csd; \ | ||
191 | mov r10 = ar.ssd; \ | ||
192 | movl r11 = FPSR_DEFAULT; /* L-unit */ \ | ||
193 | adds r17 = VMM_VCPU_GP_OFFSET,r13; \ | ||
194 | ;; \ | ||
195 | ld8 r1 = [r17];/* establish kernel global pointer */ \ | ||
196 | ;; \ | ||
197 | PAL_VSA_SYNC_READ \ | ||
198 | KVM_MINSTATE_END_SAVE_MIN | ||
199 | |||
200 | /* | ||
201 | * SAVE_REST saves the remainder of pt_regs (with psr.ic on). | ||
202 | * | ||
203 | * Assumed state upon entry: | ||
204 | * psr.ic: on | ||
205 | * r2: points to &pt_regs.f6 | ||
206 | * r3: points to &pt_regs.f7 | ||
207 | * r8: contents of ar.ccv | ||
208 | * r9: contents of ar.csd | ||
209 | * r10: contents of ar.ssd | ||
210 | * r11: FPSR_DEFAULT | ||
211 | * | ||
212 | * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. | ||
213 | */ | ||
214 | #define KVM_SAVE_REST \ | ||
215 | .mem.offset 0,0; st8.spill [r2] = r16,16; \ | ||
216 | .mem.offset 8,0; st8.spill [r3] = r17,16; \ | ||
217 | ;; \ | ||
218 | .mem.offset 0,0; st8.spill [r2] = r18,16; \ | ||
219 | .mem.offset 8,0; st8.spill [r3] = r19,16; \ | ||
220 | ;; \ | ||
221 | .mem.offset 0,0; st8.spill [r2] = r20,16; \ | ||
222 | .mem.offset 8,0; st8.spill [r3] = r21,16; \ | ||
223 | mov r18=b6; \ | ||
224 | ;; \ | ||
225 | .mem.offset 0,0; st8.spill [r2] = r22,16; \ | ||
226 | .mem.offset 8,0; st8.spill [r3] = r23,16; \ | ||
227 | mov r19 = b7; \ | ||
228 | ;; \ | ||
229 | .mem.offset 0,0; st8.spill [r2] = r24,16; \ | ||
230 | .mem.offset 8,0; st8.spill [r3] = r25,16; \ | ||
231 | ;; \ | ||
232 | .mem.offset 0,0; st8.spill [r2] = r26,16; \ | ||
233 | .mem.offset 8,0; st8.spill [r3] = r27,16; \ | ||
234 | ;; \ | ||
235 | .mem.offset 0,0; st8.spill [r2] = r28,16; \ | ||
236 | .mem.offset 8,0; st8.spill [r3] = r29,16; \ | ||
237 | ;; \ | ||
238 | .mem.offset 0,0; st8.spill [r2] = r30,16; \ | ||
239 | .mem.offset 8,0; st8.spill [r3] = r31,32; \ | ||
240 | ;; \ | ||
241 | mov ar.fpsr = r11; \ | ||
242 | st8 [r2] = r8,8; \ | ||
243 | adds r24 = PT(B6)-PT(F7),r3; \ | ||
244 | adds r25 = PT(B7)-PT(F7),r3; \ | ||
245 | ;; \ | ||
246 | st8 [r24] = r18,16; /* b6 */ \ | ||
247 | st8 [r25] = r19,16; /* b7 */ \ | ||
248 | adds r2 = PT(R4)-PT(F6),r2; \ | ||
249 | adds r3 = PT(R5)-PT(F7),r3; \ | ||
250 | ;; \ | ||
251 | st8 [r24] = r9; /* ar.csd */ \ | ||
252 | st8 [r25] = r10; /* ar.ssd */ \ | ||
253 | ;; \ | ||
254 | mov r18 = ar.unat; \ | ||
255 | adds r19 = PT(EML_UNAT)-PT(R4),r2; \ | ||
256 | ;; \ | ||
257 | st8 [r19] = r18; /* eml_unat */ \ | ||
258 | |||
259 | |||
260 | #define KVM_SAVE_EXTRA \ | ||
261 | .mem.offset 0,0; st8.spill [r2] = r4,16; \ | ||
262 | .mem.offset 8,0; st8.spill [r3] = r5,16; \ | ||
263 | ;; \ | ||
264 | .mem.offset 0,0; st8.spill [r2] = r6,16; \ | ||
265 | .mem.offset 8,0; st8.spill [r3] = r7; \ | ||
266 | ;; \ | ||
267 | mov r26 = ar.unat; \ | ||
268 | ;; \ | ||
269 | st8 [r2] = r26;/* eml_unat */ \ | ||
270 | |||
271 | #define KVM_SAVE_MIN_WITH_COVER KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs,) | ||
272 | #define KVM_SAVE_MIN_WITH_COVER_R19 KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs, mov r15 = r19) | ||
273 | #define KVM_SAVE_MIN KVM_DO_SAVE_MIN( , mov r30 = r0, ) | ||
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h new file mode 100644 index 000000000000..6d6cbcb14893 --- /dev/null +++ b/arch/ia64/kvm/lapic.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef __KVM_IA64_LAPIC_H | ||
2 | #define __KVM_IA64_LAPIC_H | ||
3 | |||
4 | #include <linux/kvm_host.h> | ||
5 | |||
6 | /* | ||
7 | * vlsapic | ||
8 | */ | ||
9 | struct kvm_lapic{ | ||
10 | struct kvm_vcpu *vcpu; | ||
11 | uint64_t insvc[4]; | ||
12 | uint64_t vhpi; | ||
13 | uint8_t xtp; | ||
14 | uint8_t pal_init_pending; | ||
15 | uint8_t pad[2]; | ||
16 | }; | ||
17 | |||
18 | int kvm_create_lapic(struct kvm_vcpu *vcpu); | ||
19 | void kvm_free_lapic(struct kvm_vcpu *vcpu); | ||
20 | |||
21 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); | ||
22 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); | ||
23 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig); | ||
24 | |||
25 | #endif | ||
diff --git a/arch/ia64/kvm/misc.h b/arch/ia64/kvm/misc.h new file mode 100644 index 000000000000..e585c4607344 --- /dev/null +++ b/arch/ia64/kvm/misc.h | |||
@@ -0,0 +1,93 @@ | |||
1 | #ifndef __KVM_IA64_MISC_H | ||
2 | #define __KVM_IA64_MISC_H | ||
3 | |||
4 | #include <linux/kvm_host.h> | ||
5 | /* | ||
6 | * misc.h | ||
7 | * Copyright (C) 2007, Intel Corporation. | ||
8 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
21 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | *Return p2m base address at host side! | ||
27 | */ | ||
28 | static inline uint64_t *kvm_host_get_pmt(struct kvm *kvm) | ||
29 | { | ||
30 | return (uint64_t *)(kvm->arch.vm_base + KVM_P2M_OFS); | ||
31 | } | ||
32 | |||
33 | static inline void kvm_set_pmt_entry(struct kvm *kvm, gfn_t gfn, | ||
34 | u64 paddr, u64 mem_flags) | ||
35 | { | ||
36 | uint64_t *pmt_base = kvm_host_get_pmt(kvm); | ||
37 | unsigned long pte; | ||
38 | |||
39 | pte = PAGE_ALIGN(paddr) | mem_flags; | ||
40 | pmt_base[gfn] = pte; | ||
41 | } | ||
42 | |||
43 | /*Function for translating host address to guest address*/ | ||
44 | |||
45 | static inline void *to_guest(struct kvm *kvm, void *addr) | ||
46 | { | ||
47 | return (void *)((unsigned long)(addr) - kvm->arch.vm_base + | ||
48 | KVM_VM_DATA_BASE); | ||
49 | } | ||
50 | |||
51 | /*Function for translating guest address to host address*/ | ||
52 | |||
53 | static inline void *to_host(struct kvm *kvm, void *addr) | ||
54 | { | ||
55 | return (void *)((unsigned long)addr - KVM_VM_DATA_BASE | ||
56 | + kvm->arch.vm_base); | ||
57 | } | ||
58 | |||
59 | /* Get host context of the vcpu */ | ||
60 | static inline union context *kvm_get_host_context(struct kvm_vcpu *vcpu) | ||
61 | { | ||
62 | union context *ctx = &vcpu->arch.host; | ||
63 | return to_guest(vcpu->kvm, ctx); | ||
64 | } | ||
65 | |||
66 | /* Get guest context of the vcpu */ | ||
67 | static inline union context *kvm_get_guest_context(struct kvm_vcpu *vcpu) | ||
68 | { | ||
69 | union context *ctx = &vcpu->arch.guest; | ||
70 | return to_guest(vcpu->kvm, ctx); | ||
71 | } | ||
72 | |||
73 | /* kvm get exit data from gvmm! */ | ||
74 | static inline struct exit_ctl_data *kvm_get_exit_data(struct kvm_vcpu *vcpu) | ||
75 | { | ||
76 | return &vcpu->arch.exit_data; | ||
77 | } | ||
78 | |||
79 | /*kvm get vcpu ioreq for kvm module!*/ | ||
80 | static inline struct kvm_mmio_req *kvm_get_vcpu_ioreq(struct kvm_vcpu *vcpu) | ||
81 | { | ||
82 | struct exit_ctl_data *p_ctl_data; | ||
83 | |||
84 | if (vcpu) { | ||
85 | p_ctl_data = kvm_get_exit_data(vcpu); | ||
86 | if (p_ctl_data->exit_reason == EXIT_REASON_MMIO_INSTRUCTION) | ||
87 | return &p_ctl_data->u.ioreq; | ||
88 | } | ||
89 | |||
90 | return NULL; | ||
91 | } | ||
92 | |||
93 | #endif | ||
diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c new file mode 100644 index 000000000000..351bf70da463 --- /dev/null +++ b/arch/ia64/kvm/mmio.c | |||
@@ -0,0 +1,341 @@ | |||
1 | /* | ||
2 | * mmio.c: MMIO emulation components. | ||
3 | * Copyright (c) 2004, Intel Corporation. | ||
4 | * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com) | ||
5 | * Kun Tian (Kevin Tian) (Kevin.tian@intel.com) | ||
6 | * | ||
7 | * Copyright (c) 2007 Intel Corporation KVM support. | ||
8 | * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com) | ||
9 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms and conditions of the GNU General Public License, | ||
13 | * version 2, as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along with | ||
21 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
22 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/kvm_host.h> | ||
27 | |||
28 | #include "vcpu.h" | ||
29 | |||
30 | static void vlsapic_write_xtp(struct kvm_vcpu *v, uint8_t val) | ||
31 | { | ||
32 | VLSAPIC_XTP(v) = val; | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * LSAPIC OFFSET | ||
37 | */ | ||
38 | #define PIB_LOW_HALF(ofst) !(ofst & (1 << 20)) | ||
39 | #define PIB_OFST_INTA 0x1E0000 | ||
40 | #define PIB_OFST_XTP 0x1E0008 | ||
41 | |||
42 | /* | ||
43 | * execute write IPI op. | ||
44 | */ | ||
45 | static void vlsapic_write_ipi(struct kvm_vcpu *vcpu, | ||
46 | uint64_t addr, uint64_t data) | ||
47 | { | ||
48 | struct exit_ctl_data *p = ¤t_vcpu->arch.exit_data; | ||
49 | unsigned long psr; | ||
50 | |||
51 | local_irq_save(psr); | ||
52 | |||
53 | p->exit_reason = EXIT_REASON_IPI; | ||
54 | p->u.ipi_data.addr.val = addr; | ||
55 | p->u.ipi_data.data.val = data; | ||
56 | vmm_transition(current_vcpu); | ||
57 | |||
58 | local_irq_restore(psr); | ||
59 | |||
60 | } | ||
61 | |||
62 | void lsapic_write(struct kvm_vcpu *v, unsigned long addr, | ||
63 | unsigned long length, unsigned long val) | ||
64 | { | ||
65 | addr &= (PIB_SIZE - 1); | ||
66 | |||
67 | switch (addr) { | ||
68 | case PIB_OFST_INTA: | ||
69 | /*panic_domain(NULL, "Undefined write on PIB INTA\n");*/ | ||
70 | panic_vm(v); | ||
71 | break; | ||
72 | case PIB_OFST_XTP: | ||
73 | if (length == 1) { | ||
74 | vlsapic_write_xtp(v, val); | ||
75 | } else { | ||
76 | /*panic_domain(NULL, | ||
77 | "Undefined write on PIB XTP\n");*/ | ||
78 | panic_vm(v); | ||
79 | } | ||
80 | break; | ||
81 | default: | ||
82 | if (PIB_LOW_HALF(addr)) { | ||
83 | /*lower half */ | ||
84 | if (length != 8) | ||
85 | /*panic_domain(NULL, | ||
86 | "Can't LHF write with size %ld!\n", | ||
87 | length);*/ | ||
88 | panic_vm(v); | ||
89 | else | ||
90 | vlsapic_write_ipi(v, addr, val); | ||
91 | } else { /* upper half | ||
92 | printk("IPI-UHF write %lx\n",addr);*/ | ||
93 | panic_vm(v); | ||
94 | } | ||
95 | break; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | unsigned long lsapic_read(struct kvm_vcpu *v, unsigned long addr, | ||
100 | unsigned long length) | ||
101 | { | ||
102 | uint64_t result = 0; | ||
103 | |||
104 | addr &= (PIB_SIZE - 1); | ||
105 | |||
106 | switch (addr) { | ||
107 | case PIB_OFST_INTA: | ||
108 | if (length == 1) /* 1 byte load */ | ||
109 | ; /* There is no i8259, there is no INTA access*/ | ||
110 | else | ||
111 | /*panic_domain(NULL,"Undefined read on PIB INTA\n"); */ | ||
112 | panic_vm(v); | ||
113 | |||
114 | break; | ||
115 | case PIB_OFST_XTP: | ||
116 | if (length == 1) { | ||
117 | result = VLSAPIC_XTP(v); | ||
118 | /* printk("read xtp %lx\n", result); */ | ||
119 | } else { | ||
120 | /*panic_domain(NULL, | ||
121 | "Undefined read on PIB XTP\n");*/ | ||
122 | panic_vm(v); | ||
123 | } | ||
124 | break; | ||
125 | default: | ||
126 | panic_vm(v); | ||
127 | break; | ||
128 | } | ||
129 | return result; | ||
130 | } | ||
131 | |||
132 | static void mmio_access(struct kvm_vcpu *vcpu, u64 src_pa, u64 *dest, | ||
133 | u16 s, int ma, int dir) | ||
134 | { | ||
135 | unsigned long iot; | ||
136 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
137 | unsigned long psr; | ||
138 | |||
139 | iot = __gpfn_is_io(src_pa >> PAGE_SHIFT); | ||
140 | |||
141 | local_irq_save(psr); | ||
142 | |||
143 | /*Intercept the acces for PIB range*/ | ||
144 | if (iot == GPFN_PIB) { | ||
145 | if (!dir) | ||
146 | lsapic_write(vcpu, src_pa, s, *dest); | ||
147 | else | ||
148 | *dest = lsapic_read(vcpu, src_pa, s); | ||
149 | goto out; | ||
150 | } | ||
151 | p->exit_reason = EXIT_REASON_MMIO_INSTRUCTION; | ||
152 | p->u.ioreq.addr = src_pa; | ||
153 | p->u.ioreq.size = s; | ||
154 | p->u.ioreq.dir = dir; | ||
155 | if (dir == IOREQ_WRITE) | ||
156 | p->u.ioreq.data = *dest; | ||
157 | p->u.ioreq.state = STATE_IOREQ_READY; | ||
158 | vmm_transition(vcpu); | ||
159 | |||
160 | if (p->u.ioreq.state == STATE_IORESP_READY) { | ||
161 | if (dir == IOREQ_READ) | ||
162 | *dest = p->u.ioreq.data; | ||
163 | } else | ||
164 | panic_vm(vcpu); | ||
165 | out: | ||
166 | local_irq_restore(psr); | ||
167 | return ; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | dir 1: read 0:write | ||
172 | inst_type 0:integer 1:floating point | ||
173 | */ | ||
174 | #define SL_INTEGER 0 /* store/load interger*/ | ||
175 | #define SL_FLOATING 1 /* store/load floating*/ | ||
176 | |||
177 | void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma) | ||
178 | { | ||
179 | struct kvm_pt_regs *regs; | ||
180 | IA64_BUNDLE bundle; | ||
181 | int slot, dir = 0; | ||
182 | int inst_type = -1; | ||
183 | u16 size = 0; | ||
184 | u64 data, slot1a, slot1b, temp, update_reg; | ||
185 | s32 imm; | ||
186 | INST64 inst; | ||
187 | |||
188 | regs = vcpu_regs(vcpu); | ||
189 | |||
190 | if (fetch_code(vcpu, regs->cr_iip, &bundle)) { | ||
191 | /* if fetch code fail, return and try again */ | ||
192 | return; | ||
193 | } | ||
194 | slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; | ||
195 | if (!slot) | ||
196 | inst.inst = bundle.slot0; | ||
197 | else if (slot == 1) { | ||
198 | slot1a = bundle.slot1a; | ||
199 | slot1b = bundle.slot1b; | ||
200 | inst.inst = slot1a + (slot1b << 18); | ||
201 | } else if (slot == 2) | ||
202 | inst.inst = bundle.slot2; | ||
203 | |||
204 | /* Integer Load/Store */ | ||
205 | if (inst.M1.major == 4 && inst.M1.m == 0 && inst.M1.x == 0) { | ||
206 | inst_type = SL_INTEGER; | ||
207 | size = (inst.M1.x6 & 0x3); | ||
208 | if ((inst.M1.x6 >> 2) > 0xb) { | ||
209 | /*write*/ | ||
210 | dir = IOREQ_WRITE; | ||
211 | data = vcpu_get_gr(vcpu, inst.M4.r2); | ||
212 | } else if ((inst.M1.x6 >> 2) < 0xb) { | ||
213 | /*read*/ | ||
214 | dir = IOREQ_READ; | ||
215 | } | ||
216 | } else if (inst.M2.major == 4 && inst.M2.m == 1 && inst.M2.x == 0) { | ||
217 | /* Integer Load + Reg update */ | ||
218 | inst_type = SL_INTEGER; | ||
219 | dir = IOREQ_READ; | ||
220 | size = (inst.M2.x6 & 0x3); | ||
221 | temp = vcpu_get_gr(vcpu, inst.M2.r3); | ||
222 | update_reg = vcpu_get_gr(vcpu, inst.M2.r2); | ||
223 | temp += update_reg; | ||
224 | vcpu_set_gr(vcpu, inst.M2.r3, temp, 0); | ||
225 | } else if (inst.M3.major == 5) { | ||
226 | /*Integer Load/Store + Imm update*/ | ||
227 | inst_type = SL_INTEGER; | ||
228 | size = (inst.M3.x6&0x3); | ||
229 | if ((inst.M5.x6 >> 2) > 0xb) { | ||
230 | /*write*/ | ||
231 | dir = IOREQ_WRITE; | ||
232 | data = vcpu_get_gr(vcpu, inst.M5.r2); | ||
233 | temp = vcpu_get_gr(vcpu, inst.M5.r3); | ||
234 | imm = (inst.M5.s << 31) | (inst.M5.i << 30) | | ||
235 | (inst.M5.imm7 << 23); | ||
236 | temp += imm >> 23; | ||
237 | vcpu_set_gr(vcpu, inst.M5.r3, temp, 0); | ||
238 | |||
239 | } else if ((inst.M3.x6 >> 2) < 0xb) { | ||
240 | /*read*/ | ||
241 | dir = IOREQ_READ; | ||
242 | temp = vcpu_get_gr(vcpu, inst.M3.r3); | ||
243 | imm = (inst.M3.s << 31) | (inst.M3.i << 30) | | ||
244 | (inst.M3.imm7 << 23); | ||
245 | temp += imm >> 23; | ||
246 | vcpu_set_gr(vcpu, inst.M3.r3, temp, 0); | ||
247 | |||
248 | } | ||
249 | } else if (inst.M9.major == 6 && inst.M9.x6 == 0x3B | ||
250 | && inst.M9.m == 0 && inst.M9.x == 0) { | ||
251 | /* Floating-point spill*/ | ||
252 | struct ia64_fpreg v; | ||
253 | |||
254 | inst_type = SL_FLOATING; | ||
255 | dir = IOREQ_WRITE; | ||
256 | vcpu_get_fpreg(vcpu, inst.M9.f2, &v); | ||
257 | /* Write high word. FIXME: this is a kludge! */ | ||
258 | v.u.bits[1] &= 0x3ffff; | ||
259 | mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); | ||
260 | data = v.u.bits[0]; | ||
261 | size = 3; | ||
262 | } else if (inst.M10.major == 7 && inst.M10.x6 == 0x3B) { | ||
263 | /* Floating-point spill + Imm update */ | ||
264 | struct ia64_fpreg v; | ||
265 | |||
266 | inst_type = SL_FLOATING; | ||
267 | dir = IOREQ_WRITE; | ||
268 | vcpu_get_fpreg(vcpu, inst.M10.f2, &v); | ||
269 | temp = vcpu_get_gr(vcpu, inst.M10.r3); | ||
270 | imm = (inst.M10.s << 31) | (inst.M10.i << 30) | | ||
271 | (inst.M10.imm7 << 23); | ||
272 | temp += imm >> 23; | ||
273 | vcpu_set_gr(vcpu, inst.M10.r3, temp, 0); | ||
274 | |||
275 | /* Write high word.FIXME: this is a kludge! */ | ||
276 | v.u.bits[1] &= 0x3ffff; | ||
277 | mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE); | ||
278 | data = v.u.bits[0]; | ||
279 | size = 3; | ||
280 | } else if (inst.M10.major == 7 && inst.M10.x6 == 0x31) { | ||
281 | /* Floating-point stf8 + Imm update */ | ||
282 | struct ia64_fpreg v; | ||
283 | inst_type = SL_FLOATING; | ||
284 | dir = IOREQ_WRITE; | ||
285 | size = 3; | ||
286 | vcpu_get_fpreg(vcpu, inst.M10.f2, &v); | ||
287 | data = v.u.bits[0]; /* Significand. */ | ||
288 | temp = vcpu_get_gr(vcpu, inst.M10.r3); | ||
289 | imm = (inst.M10.s << 31) | (inst.M10.i << 30) | | ||
290 | (inst.M10.imm7 << 23); | ||
291 | temp += imm >> 23; | ||
292 | vcpu_set_gr(vcpu, inst.M10.r3, temp, 0); | ||
293 | } else if (inst.M15.major == 7 && inst.M15.x6 >= 0x2c | ||
294 | && inst.M15.x6 <= 0x2f) { | ||
295 | temp = vcpu_get_gr(vcpu, inst.M15.r3); | ||
296 | imm = (inst.M15.s << 31) | (inst.M15.i << 30) | | ||
297 | (inst.M15.imm7 << 23); | ||
298 | temp += imm >> 23; | ||
299 | vcpu_set_gr(vcpu, inst.M15.r3, temp, 0); | ||
300 | |||
301 | vcpu_increment_iip(vcpu); | ||
302 | return; | ||
303 | } else if (inst.M12.major == 6 && inst.M12.m == 1 | ||
304 | && inst.M12.x == 1 && inst.M12.x6 == 1) { | ||
305 | /* Floating-point Load Pair + Imm ldfp8 M12*/ | ||
306 | struct ia64_fpreg v; | ||
307 | |||
308 | inst_type = SL_FLOATING; | ||
309 | dir = IOREQ_READ; | ||
310 | size = 8; /*ldfd*/ | ||
311 | mmio_access(vcpu, padr, &data, size, ma, dir); | ||
312 | v.u.bits[0] = data; | ||
313 | v.u.bits[1] = 0x1003E; | ||
314 | vcpu_set_fpreg(vcpu, inst.M12.f1, &v); | ||
315 | padr += 8; | ||
316 | mmio_access(vcpu, padr, &data, size, ma, dir); | ||
317 | v.u.bits[0] = data; | ||
318 | v.u.bits[1] = 0x1003E; | ||
319 | vcpu_set_fpreg(vcpu, inst.M12.f2, &v); | ||
320 | padr += 8; | ||
321 | vcpu_set_gr(vcpu, inst.M12.r3, padr, 0); | ||
322 | vcpu_increment_iip(vcpu); | ||
323 | return; | ||
324 | } else { | ||
325 | inst_type = -1; | ||
326 | panic_vm(vcpu); | ||
327 | } | ||
328 | |||
329 | size = 1 << size; | ||
330 | if (dir == IOREQ_WRITE) { | ||
331 | mmio_access(vcpu, padr, &data, size, ma, dir); | ||
332 | } else { | ||
333 | mmio_access(vcpu, padr, &data, size, ma, dir); | ||
334 | if (inst_type == SL_INTEGER) | ||
335 | vcpu_set_gr(vcpu, inst.M1.r1, data, 0); | ||
336 | else | ||
337 | panic_vm(vcpu); | ||
338 | |||
339 | } | ||
340 | vcpu_increment_iip(vcpu); | ||
341 | } | ||
diff --git a/arch/ia64/kvm/optvfault.S b/arch/ia64/kvm/optvfault.S new file mode 100644 index 000000000000..e4f15d641b22 --- /dev/null +++ b/arch/ia64/kvm/optvfault.S | |||
@@ -0,0 +1,918 @@ | |||
1 | /* | ||
2 | * arch/ia64/vmx/optvfault.S | ||
3 | * optimize virtualization fault handler | ||
4 | * | ||
5 | * Copyright (C) 2006 Intel Co | ||
6 | * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com> | ||
7 | */ | ||
8 | |||
9 | #include <asm/asmmacro.h> | ||
10 | #include <asm/processor.h> | ||
11 | |||
12 | #include "vti.h" | ||
13 | #include "asm-offsets.h" | ||
14 | |||
15 | #define ACCE_MOV_FROM_AR | ||
16 | #define ACCE_MOV_FROM_RR | ||
17 | #define ACCE_MOV_TO_RR | ||
18 | #define ACCE_RSM | ||
19 | #define ACCE_SSM | ||
20 | #define ACCE_MOV_TO_PSR | ||
21 | #define ACCE_THASH | ||
22 | |||
23 | //mov r1=ar3 | ||
24 | GLOBAL_ENTRY(kvm_asm_mov_from_ar) | ||
25 | #ifndef ACCE_MOV_FROM_AR | ||
26 | br.many kvm_virtualization_fault_back | ||
27 | #endif | ||
28 | add r18=VMM_VCPU_ITC_OFS_OFFSET, r21 | ||
29 | add r16=VMM_VCPU_LAST_ITC_OFFSET,r21 | ||
30 | extr.u r17=r25,6,7 | ||
31 | ;; | ||
32 | ld8 r18=[r18] | ||
33 | mov r19=ar.itc | ||
34 | mov r24=b0 | ||
35 | ;; | ||
36 | add r19=r19,r18 | ||
37 | addl r20=@gprel(asm_mov_to_reg),gp | ||
38 | ;; | ||
39 | st8 [r16] = r19 | ||
40 | adds r30=kvm_resume_to_guest-asm_mov_to_reg,r20 | ||
41 | shladd r17=r17,4,r20 | ||
42 | ;; | ||
43 | mov b0=r17 | ||
44 | br.sptk.few b0 | ||
45 | ;; | ||
46 | END(kvm_asm_mov_from_ar) | ||
47 | |||
48 | |||
49 | // mov r1=rr[r3] | ||
50 | GLOBAL_ENTRY(kvm_asm_mov_from_rr) | ||
51 | #ifndef ACCE_MOV_FROM_RR | ||
52 | br.many kvm_virtualization_fault_back | ||
53 | #endif | ||
54 | extr.u r16=r25,20,7 | ||
55 | extr.u r17=r25,6,7 | ||
56 | addl r20=@gprel(asm_mov_from_reg),gp | ||
57 | ;; | ||
58 | adds r30=kvm_asm_mov_from_rr_back_1-asm_mov_from_reg,r20 | ||
59 | shladd r16=r16,4,r20 | ||
60 | mov r24=b0 | ||
61 | ;; | ||
62 | add r27=VMM_VCPU_VRR0_OFFSET,r21 | ||
63 | mov b0=r16 | ||
64 | br.many b0 | ||
65 | ;; | ||
66 | kvm_asm_mov_from_rr_back_1: | ||
67 | adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 | ||
68 | adds r22=asm_mov_to_reg-asm_mov_from_reg,r20 | ||
69 | shr.u r26=r19,61 | ||
70 | ;; | ||
71 | shladd r17=r17,4,r22 | ||
72 | shladd r27=r26,3,r27 | ||
73 | ;; | ||
74 | ld8 r19=[r27] | ||
75 | mov b0=r17 | ||
76 | br.many b0 | ||
77 | END(kvm_asm_mov_from_rr) | ||
78 | |||
79 | |||
80 | // mov rr[r3]=r2 | ||
81 | GLOBAL_ENTRY(kvm_asm_mov_to_rr) | ||
82 | #ifndef ACCE_MOV_TO_RR | ||
83 | br.many kvm_virtualization_fault_back | ||
84 | #endif | ||
85 | extr.u r16=r25,20,7 | ||
86 | extr.u r17=r25,13,7 | ||
87 | addl r20=@gprel(asm_mov_from_reg),gp | ||
88 | ;; | ||
89 | adds r30=kvm_asm_mov_to_rr_back_1-asm_mov_from_reg,r20 | ||
90 | shladd r16=r16,4,r20 | ||
91 | mov r22=b0 | ||
92 | ;; | ||
93 | add r27=VMM_VCPU_VRR0_OFFSET,r21 | ||
94 | mov b0=r16 | ||
95 | br.many b0 | ||
96 | ;; | ||
97 | kvm_asm_mov_to_rr_back_1: | ||
98 | adds r30=kvm_asm_mov_to_rr_back_2-asm_mov_from_reg,r20 | ||
99 | shr.u r23=r19,61 | ||
100 | shladd r17=r17,4,r20 | ||
101 | ;; | ||
102 | //if rr6, go back | ||
103 | cmp.eq p6,p0=6,r23 | ||
104 | mov b0=r22 | ||
105 | (p6) br.cond.dpnt.many kvm_virtualization_fault_back | ||
106 | ;; | ||
107 | mov r28=r19 | ||
108 | mov b0=r17 | ||
109 | br.many b0 | ||
110 | kvm_asm_mov_to_rr_back_2: | ||
111 | adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 | ||
112 | shladd r27=r23,3,r27 | ||
113 | ;; // vrr.rid<<4 |0xe | ||
114 | st8 [r27]=r19 | ||
115 | mov b0=r30 | ||
116 | ;; | ||
117 | extr.u r16=r19,8,26 | ||
118 | extr.u r18 =r19,2,6 | ||
119 | mov r17 =0xe | ||
120 | ;; | ||
121 | shladd r16 = r16, 4, r17 | ||
122 | extr.u r19 =r19,0,8 | ||
123 | ;; | ||
124 | shl r16 = r16,8 | ||
125 | ;; | ||
126 | add r19 = r19, r16 | ||
127 | ;; //set ve 1 | ||
128 | dep r19=-1,r19,0,1 | ||
129 | cmp.lt p6,p0=14,r18 | ||
130 | ;; | ||
131 | (p6) mov r18=14 | ||
132 | ;; | ||
133 | (p6) dep r19=r18,r19,2,6 | ||
134 | ;; | ||
135 | cmp.eq p6,p0=0,r23 | ||
136 | ;; | ||
137 | cmp.eq.or p6,p0=4,r23 | ||
138 | ;; | ||
139 | adds r16=VMM_VCPU_MODE_FLAGS_OFFSET,r21 | ||
140 | (p6) adds r17=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 | ||
141 | ;; | ||
142 | ld4 r16=[r16] | ||
143 | cmp.eq p7,p0=r0,r0 | ||
144 | (p6) shladd r17=r23,1,r17 | ||
145 | ;; | ||
146 | (p6) st8 [r17]=r19 | ||
147 | (p6) tbit.nz p6,p7=r16,0 | ||
148 | ;; | ||
149 | (p7) mov rr[r28]=r19 | ||
150 | mov r24=r22 | ||
151 | br.many b0 | ||
152 | END(kvm_asm_mov_to_rr) | ||
153 | |||
154 | |||
155 | //rsm | ||
156 | GLOBAL_ENTRY(kvm_asm_rsm) | ||
157 | #ifndef ACCE_RSM | ||
158 | br.many kvm_virtualization_fault_back | ||
159 | #endif | ||
160 | add r16=VMM_VPD_BASE_OFFSET,r21 | ||
161 | extr.u r26=r25,6,21 | ||
162 | extr.u r27=r25,31,2 | ||
163 | ;; | ||
164 | ld8 r16=[r16] | ||
165 | extr.u r28=r25,36,1 | ||
166 | dep r26=r27,r26,21,2 | ||
167 | ;; | ||
168 | add r17=VPD_VPSR_START_OFFSET,r16 | ||
169 | add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 | ||
170 | //r26 is imm24 | ||
171 | dep r26=r28,r26,23,1 | ||
172 | ;; | ||
173 | ld8 r18=[r17] | ||
174 | movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI | ||
175 | ld4 r23=[r22] | ||
176 | sub r27=-1,r26 | ||
177 | mov r24=b0 | ||
178 | ;; | ||
179 | mov r20=cr.ipsr | ||
180 | or r28=r27,r28 | ||
181 | and r19=r18,r27 | ||
182 | ;; | ||
183 | st8 [r17]=r19 | ||
184 | and r20=r20,r28 | ||
185 | /* Comment it out due to short of fp lazy alorgithm support | ||
186 | adds r27=IA64_VCPU_FP_PSR_OFFSET,r21 | ||
187 | ;; | ||
188 | ld8 r27=[r27] | ||
189 | ;; | ||
190 | tbit.nz p8,p0= r27,IA64_PSR_DFH_BIT | ||
191 | ;; | ||
192 | (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1 | ||
193 | */ | ||
194 | ;; | ||
195 | mov cr.ipsr=r20 | ||
196 | tbit.nz p6,p0=r23,0 | ||
197 | ;; | ||
198 | tbit.z.or p6,p0=r26,IA64_PSR_DT_BIT | ||
199 | (p6) br.dptk kvm_resume_to_guest | ||
200 | ;; | ||
201 | add r26=VMM_VCPU_META_RR0_OFFSET,r21 | ||
202 | add r27=VMM_VCPU_META_RR0_OFFSET+8,r21 | ||
203 | dep r23=-1,r23,0,1 | ||
204 | ;; | ||
205 | ld8 r26=[r26] | ||
206 | ld8 r27=[r27] | ||
207 | st4 [r22]=r23 | ||
208 | dep.z r28=4,61,3 | ||
209 | ;; | ||
210 | mov rr[r0]=r26 | ||
211 | ;; | ||
212 | mov rr[r28]=r27 | ||
213 | ;; | ||
214 | srlz.d | ||
215 | br.many kvm_resume_to_guest | ||
216 | END(kvm_asm_rsm) | ||
217 | |||
218 | |||
219 | //ssm | ||
220 | GLOBAL_ENTRY(kvm_asm_ssm) | ||
221 | #ifndef ACCE_SSM | ||
222 | br.many kvm_virtualization_fault_back | ||
223 | #endif | ||
224 | add r16=VMM_VPD_BASE_OFFSET,r21 | ||
225 | extr.u r26=r25,6,21 | ||
226 | extr.u r27=r25,31,2 | ||
227 | ;; | ||
228 | ld8 r16=[r16] | ||
229 | extr.u r28=r25,36,1 | ||
230 | dep r26=r27,r26,21,2 | ||
231 | ;; //r26 is imm24 | ||
232 | add r27=VPD_VPSR_START_OFFSET,r16 | ||
233 | dep r26=r28,r26,23,1 | ||
234 | ;; //r19 vpsr | ||
235 | ld8 r29=[r27] | ||
236 | mov r24=b0 | ||
237 | ;; | ||
238 | add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 | ||
239 | mov r20=cr.ipsr | ||
240 | or r19=r29,r26 | ||
241 | ;; | ||
242 | ld4 r23=[r22] | ||
243 | st8 [r27]=r19 | ||
244 | or r20=r20,r26 | ||
245 | ;; | ||
246 | mov cr.ipsr=r20 | ||
247 | movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT | ||
248 | ;; | ||
249 | and r19=r28,r19 | ||
250 | tbit.z p6,p0=r23,0 | ||
251 | ;; | ||
252 | cmp.ne.or p6,p0=r28,r19 | ||
253 | (p6) br.dptk kvm_asm_ssm_1 | ||
254 | ;; | ||
255 | add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 | ||
256 | add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21 | ||
257 | dep r23=0,r23,0,1 | ||
258 | ;; | ||
259 | ld8 r26=[r26] | ||
260 | ld8 r27=[r27] | ||
261 | st4 [r22]=r23 | ||
262 | dep.z r28=4,61,3 | ||
263 | ;; | ||
264 | mov rr[r0]=r26 | ||
265 | ;; | ||
266 | mov rr[r28]=r27 | ||
267 | ;; | ||
268 | srlz.d | ||
269 | ;; | ||
270 | kvm_asm_ssm_1: | ||
271 | tbit.nz p6,p0=r29,IA64_PSR_I_BIT | ||
272 | ;; | ||
273 | tbit.z.or p6,p0=r19,IA64_PSR_I_BIT | ||
274 | (p6) br.dptk kvm_resume_to_guest | ||
275 | ;; | ||
276 | add r29=VPD_VTPR_START_OFFSET,r16 | ||
277 | add r30=VPD_VHPI_START_OFFSET,r16 | ||
278 | ;; | ||
279 | ld8 r29=[r29] | ||
280 | ld8 r30=[r30] | ||
281 | ;; | ||
282 | extr.u r17=r29,4,4 | ||
283 | extr.u r18=r29,16,1 | ||
284 | ;; | ||
285 | dep r17=r18,r17,4,1 | ||
286 | ;; | ||
287 | cmp.gt p6,p0=r30,r17 | ||
288 | (p6) br.dpnt.few kvm_asm_dispatch_vexirq | ||
289 | br.many kvm_resume_to_guest | ||
290 | END(kvm_asm_ssm) | ||
291 | |||
292 | |||
293 | //mov psr.l=r2 | ||
294 | GLOBAL_ENTRY(kvm_asm_mov_to_psr) | ||
295 | #ifndef ACCE_MOV_TO_PSR | ||
296 | br.many kvm_virtualization_fault_back | ||
297 | #endif | ||
298 | add r16=VMM_VPD_BASE_OFFSET,r21 | ||
299 | extr.u r26=r25,13,7 //r2 | ||
300 | ;; | ||
301 | ld8 r16=[r16] | ||
302 | addl r20=@gprel(asm_mov_from_reg),gp | ||
303 | ;; | ||
304 | adds r30=kvm_asm_mov_to_psr_back-asm_mov_from_reg,r20 | ||
305 | shladd r26=r26,4,r20 | ||
306 | mov r24=b0 | ||
307 | ;; | ||
308 | add r27=VPD_VPSR_START_OFFSET,r16 | ||
309 | mov b0=r26 | ||
310 | br.many b0 | ||
311 | ;; | ||
312 | kvm_asm_mov_to_psr_back: | ||
313 | ld8 r17=[r27] | ||
314 | add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 | ||
315 | dep r19=0,r19,32,32 | ||
316 | ;; | ||
317 | ld4 r23=[r22] | ||
318 | dep r18=0,r17,0,32 | ||
319 | ;; | ||
320 | add r30=r18,r19 | ||
321 | movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT | ||
322 | ;; | ||
323 | st8 [r27]=r30 | ||
324 | and r27=r28,r30 | ||
325 | and r29=r28,r17 | ||
326 | ;; | ||
327 | cmp.eq p5,p0=r29,r27 | ||
328 | cmp.eq p6,p7=r28,r27 | ||
329 | (p5) br.many kvm_asm_mov_to_psr_1 | ||
330 | ;; | ||
331 | //virtual to physical | ||
332 | (p7) add r26=VMM_VCPU_META_RR0_OFFSET,r21 | ||
333 | (p7) add r27=VMM_VCPU_META_RR0_OFFSET+8,r21 | ||
334 | (p7) dep r23=-1,r23,0,1 | ||
335 | ;; | ||
336 | //physical to virtual | ||
337 | (p6) add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 | ||
338 | (p6) add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21 | ||
339 | (p6) dep r23=0,r23,0,1 | ||
340 | ;; | ||
341 | ld8 r26=[r26] | ||
342 | ld8 r27=[r27] | ||
343 | st4 [r22]=r23 | ||
344 | dep.z r28=4,61,3 | ||
345 | ;; | ||
346 | mov rr[r0]=r26 | ||
347 | ;; | ||
348 | mov rr[r28]=r27 | ||
349 | ;; | ||
350 | srlz.d | ||
351 | ;; | ||
352 | kvm_asm_mov_to_psr_1: | ||
353 | mov r20=cr.ipsr | ||
354 | movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI+IA64_PSR_RT | ||
355 | ;; | ||
356 | or r19=r19,r28 | ||
357 | dep r20=0,r20,0,32 | ||
358 | ;; | ||
359 | add r20=r19,r20 | ||
360 | mov b0=r24 | ||
361 | ;; | ||
362 | /* Comment it out due to short of fp lazy algorithm support | ||
363 | adds r27=IA64_VCPU_FP_PSR_OFFSET,r21 | ||
364 | ;; | ||
365 | ld8 r27=[r27] | ||
366 | ;; | ||
367 | tbit.nz p8,p0=r27,IA64_PSR_DFH_BIT | ||
368 | ;; | ||
369 | (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1 | ||
370 | ;; | ||
371 | */ | ||
372 | mov cr.ipsr=r20 | ||
373 | cmp.ne p6,p0=r0,r0 | ||
374 | ;; | ||
375 | tbit.nz.or p6,p0=r17,IA64_PSR_I_BIT | ||
376 | tbit.z.or p6,p0=r30,IA64_PSR_I_BIT | ||
377 | (p6) br.dpnt.few kvm_resume_to_guest | ||
378 | ;; | ||
379 | add r29=VPD_VTPR_START_OFFSET,r16 | ||
380 | add r30=VPD_VHPI_START_OFFSET,r16 | ||
381 | ;; | ||
382 | ld8 r29=[r29] | ||
383 | ld8 r30=[r30] | ||
384 | ;; | ||
385 | extr.u r17=r29,4,4 | ||
386 | extr.u r18=r29,16,1 | ||
387 | ;; | ||
388 | dep r17=r18,r17,4,1 | ||
389 | ;; | ||
390 | cmp.gt p6,p0=r30,r17 | ||
391 | (p6) br.dpnt.few kvm_asm_dispatch_vexirq | ||
392 | br.many kvm_resume_to_guest | ||
393 | END(kvm_asm_mov_to_psr) | ||
394 | |||
395 | |||
396 | ENTRY(kvm_asm_dispatch_vexirq) | ||
397 | //increment iip | ||
398 | mov r16=cr.ipsr | ||
399 | ;; | ||
400 | extr.u r17=r16,IA64_PSR_RI_BIT,2 | ||
401 | tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1 | ||
402 | ;; | ||
403 | (p6) mov r18=cr.iip | ||
404 | (p6) mov r17=r0 | ||
405 | (p7) add r17=1,r17 | ||
406 | ;; | ||
407 | (p6) add r18=0x10,r18 | ||
408 | dep r16=r17,r16,IA64_PSR_RI_BIT,2 | ||
409 | ;; | ||
410 | (p6) mov cr.iip=r18 | ||
411 | mov cr.ipsr=r16 | ||
412 | mov r30 =1 | ||
413 | br.many kvm_dispatch_vexirq | ||
414 | END(kvm_asm_dispatch_vexirq) | ||
415 | |||
416 | // thash | ||
417 | // TODO: add support when pta.vf = 1 | ||
418 | GLOBAL_ENTRY(kvm_asm_thash) | ||
419 | #ifndef ACCE_THASH | ||
420 | br.many kvm_virtualization_fault_back | ||
421 | #endif | ||
422 | extr.u r17=r25,20,7 // get r3 from opcode in r25 | ||
423 | extr.u r18=r25,6,7 // get r1 from opcode in r25 | ||
424 | addl r20=@gprel(asm_mov_from_reg),gp | ||
425 | ;; | ||
426 | adds r30=kvm_asm_thash_back1-asm_mov_from_reg,r20 | ||
427 | shladd r17=r17,4,r20 // get addr of MOVE_FROM_REG(r17) | ||
428 | adds r16=VMM_VPD_BASE_OFFSET,r21 // get vcpu.arch.priveregs | ||
429 | ;; | ||
430 | mov r24=b0 | ||
431 | ;; | ||
432 | ld8 r16=[r16] // get VPD addr | ||
433 | mov b0=r17 | ||
434 | br.many b0 // r19 return value | ||
435 | ;; | ||
436 | kvm_asm_thash_back1: | ||
437 | shr.u r23=r19,61 // get RR number | ||
438 | adds r25=VMM_VCPU_VRR0_OFFSET,r21 // get vcpu->arch.vrr[0]'s addr | ||
439 | adds r16=VMM_VPD_VPTA_OFFSET,r16 // get vpta | ||
440 | ;; | ||
441 | shladd r27=r23,3,r25 // get vcpu->arch.vrr[r23]'s addr | ||
442 | ld8 r17=[r16] // get PTA | ||
443 | mov r26=1 | ||
444 | ;; | ||
445 | extr.u r29=r17,2,6 // get pta.size | ||
446 | ld8 r25=[r27] // get vcpu->arch.vrr[r23]'s value | ||
447 | ;; | ||
448 | extr.u r25=r25,2,6 // get rr.ps | ||
449 | shl r22=r26,r29 // 1UL << pta.size | ||
450 | ;; | ||
451 | shr.u r23=r19,r25 // vaddr >> rr.ps | ||
452 | adds r26=3,r29 // pta.size + 3 | ||
453 | shl r27=r17,3 // pta << 3 | ||
454 | ;; | ||
455 | shl r23=r23,3 // (vaddr >> rr.ps) << 3 | ||
456 | shr.u r27=r27,r26 // (pta << 3) >> (pta.size+3) | ||
457 | movl r16=7<<61 | ||
458 | ;; | ||
459 | adds r22=-1,r22 // (1UL << pta.size) - 1 | ||
460 | shl r27=r27,r29 // ((pta<<3)>>(pta.size+3))<<pta.size | ||
461 | and r19=r19,r16 // vaddr & VRN_MASK | ||
462 | ;; | ||
463 | and r22=r22,r23 // vhpt_offset | ||
464 | or r19=r19,r27 // (vadr&VRN_MASK)|(((pta<<3)>>(pta.size + 3))<<pta.size) | ||
465 | adds r26=asm_mov_to_reg-asm_mov_from_reg,r20 | ||
466 | ;; | ||
467 | or r19=r19,r22 // calc pval | ||
468 | shladd r17=r18,4,r26 | ||
469 | adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 | ||
470 | ;; | ||
471 | mov b0=r17 | ||
472 | br.many b0 | ||
473 | END(kvm_asm_thash) | ||
474 | |||
475 | #define MOV_TO_REG0 \ | ||
476 | {; \ | ||
477 | nop.b 0x0; \ | ||
478 | nop.b 0x0; \ | ||
479 | nop.b 0x0; \ | ||
480 | ;; \ | ||
481 | }; | ||
482 | |||
483 | |||
484 | #define MOV_TO_REG(n) \ | ||
485 | {; \ | ||
486 | mov r##n##=r19; \ | ||
487 | mov b0=r30; \ | ||
488 | br.sptk.many b0; \ | ||
489 | ;; \ | ||
490 | }; | ||
491 | |||
492 | |||
493 | #define MOV_FROM_REG(n) \ | ||
494 | {; \ | ||
495 | mov r19=r##n##; \ | ||
496 | mov b0=r30; \ | ||
497 | br.sptk.many b0; \ | ||
498 | ;; \ | ||
499 | }; | ||
500 | |||
501 | |||
502 | #define MOV_TO_BANK0_REG(n) \ | ||
503 | ENTRY_MIN_ALIGN(asm_mov_to_bank0_reg##n##); \ | ||
504 | {; \ | ||
505 | mov r26=r2; \ | ||
506 | mov r2=r19; \ | ||
507 | bsw.1; \ | ||
508 | ;; \ | ||
509 | }; \ | ||
510 | {; \ | ||
511 | mov r##n##=r2; \ | ||
512 | nop.b 0x0; \ | ||
513 | bsw.0; \ | ||
514 | ;; \ | ||
515 | }; \ | ||
516 | {; \ | ||
517 | mov r2=r26; \ | ||
518 | mov b0=r30; \ | ||
519 | br.sptk.many b0; \ | ||
520 | ;; \ | ||
521 | }; \ | ||
522 | END(asm_mov_to_bank0_reg##n##) | ||
523 | |||
524 | |||
525 | #define MOV_FROM_BANK0_REG(n) \ | ||
526 | ENTRY_MIN_ALIGN(asm_mov_from_bank0_reg##n##); \ | ||
527 | {; \ | ||
528 | mov r26=r2; \ | ||
529 | nop.b 0x0; \ | ||
530 | bsw.1; \ | ||
531 | ;; \ | ||
532 | }; \ | ||
533 | {; \ | ||
534 | mov r2=r##n##; \ | ||
535 | nop.b 0x0; \ | ||
536 | bsw.0; \ | ||
537 | ;; \ | ||
538 | }; \ | ||
539 | {; \ | ||
540 | mov r19=r2; \ | ||
541 | mov r2=r26; \ | ||
542 | mov b0=r30; \ | ||
543 | }; \ | ||
544 | {; \ | ||
545 | nop.b 0x0; \ | ||
546 | nop.b 0x0; \ | ||
547 | br.sptk.many b0; \ | ||
548 | ;; \ | ||
549 | }; \ | ||
550 | END(asm_mov_from_bank0_reg##n##) | ||
551 | |||
552 | |||
553 | #define JMP_TO_MOV_TO_BANK0_REG(n) \ | ||
554 | {; \ | ||
555 | nop.b 0x0; \ | ||
556 | nop.b 0x0; \ | ||
557 | br.sptk.many asm_mov_to_bank0_reg##n##; \ | ||
558 | ;; \ | ||
559 | } | ||
560 | |||
561 | |||
562 | #define JMP_TO_MOV_FROM_BANK0_REG(n) \ | ||
563 | {; \ | ||
564 | nop.b 0x0; \ | ||
565 | nop.b 0x0; \ | ||
566 | br.sptk.many asm_mov_from_bank0_reg##n##; \ | ||
567 | ;; \ | ||
568 | } | ||
569 | |||
570 | |||
571 | MOV_FROM_BANK0_REG(16) | ||
572 | MOV_FROM_BANK0_REG(17) | ||
573 | MOV_FROM_BANK0_REG(18) | ||
574 | MOV_FROM_BANK0_REG(19) | ||
575 | MOV_FROM_BANK0_REG(20) | ||
576 | MOV_FROM_BANK0_REG(21) | ||
577 | MOV_FROM_BANK0_REG(22) | ||
578 | MOV_FROM_BANK0_REG(23) | ||
579 | MOV_FROM_BANK0_REG(24) | ||
580 | MOV_FROM_BANK0_REG(25) | ||
581 | MOV_FROM_BANK0_REG(26) | ||
582 | MOV_FROM_BANK0_REG(27) | ||
583 | MOV_FROM_BANK0_REG(28) | ||
584 | MOV_FROM_BANK0_REG(29) | ||
585 | MOV_FROM_BANK0_REG(30) | ||
586 | MOV_FROM_BANK0_REG(31) | ||
587 | |||
588 | |||
589 | // mov from reg table | ||
590 | ENTRY(asm_mov_from_reg) | ||
591 | MOV_FROM_REG(0) | ||
592 | MOV_FROM_REG(1) | ||
593 | MOV_FROM_REG(2) | ||
594 | MOV_FROM_REG(3) | ||
595 | MOV_FROM_REG(4) | ||
596 | MOV_FROM_REG(5) | ||
597 | MOV_FROM_REG(6) | ||
598 | MOV_FROM_REG(7) | ||
599 | MOV_FROM_REG(8) | ||
600 | MOV_FROM_REG(9) | ||
601 | MOV_FROM_REG(10) | ||
602 | MOV_FROM_REG(11) | ||
603 | MOV_FROM_REG(12) | ||
604 | MOV_FROM_REG(13) | ||
605 | MOV_FROM_REG(14) | ||
606 | MOV_FROM_REG(15) | ||
607 | JMP_TO_MOV_FROM_BANK0_REG(16) | ||
608 | JMP_TO_MOV_FROM_BANK0_REG(17) | ||
609 | JMP_TO_MOV_FROM_BANK0_REG(18) | ||
610 | JMP_TO_MOV_FROM_BANK0_REG(19) | ||
611 | JMP_TO_MOV_FROM_BANK0_REG(20) | ||
612 | JMP_TO_MOV_FROM_BANK0_REG(21) | ||
613 | JMP_TO_MOV_FROM_BANK0_REG(22) | ||
614 | JMP_TO_MOV_FROM_BANK0_REG(23) | ||
615 | JMP_TO_MOV_FROM_BANK0_REG(24) | ||
616 | JMP_TO_MOV_FROM_BANK0_REG(25) | ||
617 | JMP_TO_MOV_FROM_BANK0_REG(26) | ||
618 | JMP_TO_MOV_FROM_BANK0_REG(27) | ||
619 | JMP_TO_MOV_FROM_BANK0_REG(28) | ||
620 | JMP_TO_MOV_FROM_BANK0_REG(29) | ||
621 | JMP_TO_MOV_FROM_BANK0_REG(30) | ||
622 | JMP_TO_MOV_FROM_BANK0_REG(31) | ||
623 | MOV_FROM_REG(32) | ||
624 | MOV_FROM_REG(33) | ||
625 | MOV_FROM_REG(34) | ||
626 | MOV_FROM_REG(35) | ||
627 | MOV_FROM_REG(36) | ||
628 | MOV_FROM_REG(37) | ||
629 | MOV_FROM_REG(38) | ||
630 | MOV_FROM_REG(39) | ||
631 | MOV_FROM_REG(40) | ||
632 | MOV_FROM_REG(41) | ||
633 | MOV_FROM_REG(42) | ||
634 | MOV_FROM_REG(43) | ||
635 | MOV_FROM_REG(44) | ||
636 | MOV_FROM_REG(45) | ||
637 | MOV_FROM_REG(46) | ||
638 | MOV_FROM_REG(47) | ||
639 | MOV_FROM_REG(48) | ||
640 | MOV_FROM_REG(49) | ||
641 | MOV_FROM_REG(50) | ||
642 | MOV_FROM_REG(51) | ||
643 | MOV_FROM_REG(52) | ||
644 | MOV_FROM_REG(53) | ||
645 | MOV_FROM_REG(54) | ||
646 | MOV_FROM_REG(55) | ||
647 | MOV_FROM_REG(56) | ||
648 | MOV_FROM_REG(57) | ||
649 | MOV_FROM_REG(58) | ||
650 | MOV_FROM_REG(59) | ||
651 | MOV_FROM_REG(60) | ||
652 | MOV_FROM_REG(61) | ||
653 | MOV_FROM_REG(62) | ||
654 | MOV_FROM_REG(63) | ||
655 | MOV_FROM_REG(64) | ||
656 | MOV_FROM_REG(65) | ||
657 | MOV_FROM_REG(66) | ||
658 | MOV_FROM_REG(67) | ||
659 | MOV_FROM_REG(68) | ||
660 | MOV_FROM_REG(69) | ||
661 | MOV_FROM_REG(70) | ||
662 | MOV_FROM_REG(71) | ||
663 | MOV_FROM_REG(72) | ||
664 | MOV_FROM_REG(73) | ||
665 | MOV_FROM_REG(74) | ||
666 | MOV_FROM_REG(75) | ||
667 | MOV_FROM_REG(76) | ||
668 | MOV_FROM_REG(77) | ||
669 | MOV_FROM_REG(78) | ||
670 | MOV_FROM_REG(79) | ||
671 | MOV_FROM_REG(80) | ||
672 | MOV_FROM_REG(81) | ||
673 | MOV_FROM_REG(82) | ||
674 | MOV_FROM_REG(83) | ||
675 | MOV_FROM_REG(84) | ||
676 | MOV_FROM_REG(85) | ||
677 | MOV_FROM_REG(86) | ||
678 | MOV_FROM_REG(87) | ||
679 | MOV_FROM_REG(88) | ||
680 | MOV_FROM_REG(89) | ||
681 | MOV_FROM_REG(90) | ||
682 | MOV_FROM_REG(91) | ||
683 | MOV_FROM_REG(92) | ||
684 | MOV_FROM_REG(93) | ||
685 | MOV_FROM_REG(94) | ||
686 | MOV_FROM_REG(95) | ||
687 | MOV_FROM_REG(96) | ||
688 | MOV_FROM_REG(97) | ||
689 | MOV_FROM_REG(98) | ||
690 | MOV_FROM_REG(99) | ||
691 | MOV_FROM_REG(100) | ||
692 | MOV_FROM_REG(101) | ||
693 | MOV_FROM_REG(102) | ||
694 | MOV_FROM_REG(103) | ||
695 | MOV_FROM_REG(104) | ||
696 | MOV_FROM_REG(105) | ||
697 | MOV_FROM_REG(106) | ||
698 | MOV_FROM_REG(107) | ||
699 | MOV_FROM_REG(108) | ||
700 | MOV_FROM_REG(109) | ||
701 | MOV_FROM_REG(110) | ||
702 | MOV_FROM_REG(111) | ||
703 | MOV_FROM_REG(112) | ||
704 | MOV_FROM_REG(113) | ||
705 | MOV_FROM_REG(114) | ||
706 | MOV_FROM_REG(115) | ||
707 | MOV_FROM_REG(116) | ||
708 | MOV_FROM_REG(117) | ||
709 | MOV_FROM_REG(118) | ||
710 | MOV_FROM_REG(119) | ||
711 | MOV_FROM_REG(120) | ||
712 | MOV_FROM_REG(121) | ||
713 | MOV_FROM_REG(122) | ||
714 | MOV_FROM_REG(123) | ||
715 | MOV_FROM_REG(124) | ||
716 | MOV_FROM_REG(125) | ||
717 | MOV_FROM_REG(126) | ||
718 | MOV_FROM_REG(127) | ||
719 | END(asm_mov_from_reg) | ||
720 | |||
721 | |||
722 | /* must be in bank 0 | ||
723 | * parameter: | ||
724 | * r31: pr | ||
725 | * r24: b0 | ||
726 | */ | ||
727 | ENTRY(kvm_resume_to_guest) | ||
728 | adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21 | ||
729 | ;; | ||
730 | ld8 r1 =[r16] | ||
731 | adds r20 = VMM_VCPU_VSA_BASE_OFFSET,r21 | ||
732 | ;; | ||
733 | mov r16=cr.ipsr | ||
734 | ;; | ||
735 | ld8 r20 = [r20] | ||
736 | adds r19=VMM_VPD_BASE_OFFSET,r21 | ||
737 | ;; | ||
738 | ld8 r25=[r19] | ||
739 | extr.u r17=r16,IA64_PSR_RI_BIT,2 | ||
740 | tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1 | ||
741 | ;; | ||
742 | (p6) mov r18=cr.iip | ||
743 | (p6) mov r17=r0 | ||
744 | ;; | ||
745 | (p6) add r18=0x10,r18 | ||
746 | (p7) add r17=1,r17 | ||
747 | ;; | ||
748 | (p6) mov cr.iip=r18 | ||
749 | dep r16=r17,r16,IA64_PSR_RI_BIT,2 | ||
750 | ;; | ||
751 | mov cr.ipsr=r16 | ||
752 | adds r19= VPD_VPSR_START_OFFSET,r25 | ||
753 | add r28=PAL_VPS_RESUME_NORMAL,r20 | ||
754 | add r29=PAL_VPS_RESUME_HANDLER,r20 | ||
755 | ;; | ||
756 | ld8 r19=[r19] | ||
757 | mov b0=r29 | ||
758 | cmp.ne p6,p7 = r0,r0 | ||
759 | ;; | ||
760 | tbit.z p6,p7 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic | ||
761 | ;; | ||
762 | (p6) ld8 r26=[r25] | ||
763 | (p7) mov b0=r28 | ||
764 | mov pr=r31,-2 | ||
765 | br.sptk.many b0 // call pal service | ||
766 | ;; | ||
767 | END(kvm_resume_to_guest) | ||
768 | |||
769 | |||
770 | MOV_TO_BANK0_REG(16) | ||
771 | MOV_TO_BANK0_REG(17) | ||
772 | MOV_TO_BANK0_REG(18) | ||
773 | MOV_TO_BANK0_REG(19) | ||
774 | MOV_TO_BANK0_REG(20) | ||
775 | MOV_TO_BANK0_REG(21) | ||
776 | MOV_TO_BANK0_REG(22) | ||
777 | MOV_TO_BANK0_REG(23) | ||
778 | MOV_TO_BANK0_REG(24) | ||
779 | MOV_TO_BANK0_REG(25) | ||
780 | MOV_TO_BANK0_REG(26) | ||
781 | MOV_TO_BANK0_REG(27) | ||
782 | MOV_TO_BANK0_REG(28) | ||
783 | MOV_TO_BANK0_REG(29) | ||
784 | MOV_TO_BANK0_REG(30) | ||
785 | MOV_TO_BANK0_REG(31) | ||
786 | |||
787 | |||
788 | // mov to reg table | ||
789 | ENTRY(asm_mov_to_reg) | ||
790 | MOV_TO_REG0 | ||
791 | MOV_TO_REG(1) | ||
792 | MOV_TO_REG(2) | ||
793 | MOV_TO_REG(3) | ||
794 | MOV_TO_REG(4) | ||
795 | MOV_TO_REG(5) | ||
796 | MOV_TO_REG(6) | ||
797 | MOV_TO_REG(7) | ||
798 | MOV_TO_REG(8) | ||
799 | MOV_TO_REG(9) | ||
800 | MOV_TO_REG(10) | ||
801 | MOV_TO_REG(11) | ||
802 | MOV_TO_REG(12) | ||
803 | MOV_TO_REG(13) | ||
804 | MOV_TO_REG(14) | ||
805 | MOV_TO_REG(15) | ||
806 | JMP_TO_MOV_TO_BANK0_REG(16) | ||
807 | JMP_TO_MOV_TO_BANK0_REG(17) | ||
808 | JMP_TO_MOV_TO_BANK0_REG(18) | ||
809 | JMP_TO_MOV_TO_BANK0_REG(19) | ||
810 | JMP_TO_MOV_TO_BANK0_REG(20) | ||
811 | JMP_TO_MOV_TO_BANK0_REG(21) | ||
812 | JMP_TO_MOV_TO_BANK0_REG(22) | ||
813 | JMP_TO_MOV_TO_BANK0_REG(23) | ||
814 | JMP_TO_MOV_TO_BANK0_REG(24) | ||
815 | JMP_TO_MOV_TO_BANK0_REG(25) | ||
816 | JMP_TO_MOV_TO_BANK0_REG(26) | ||
817 | JMP_TO_MOV_TO_BANK0_REG(27) | ||
818 | JMP_TO_MOV_TO_BANK0_REG(28) | ||
819 | JMP_TO_MOV_TO_BANK0_REG(29) | ||
820 | JMP_TO_MOV_TO_BANK0_REG(30) | ||
821 | JMP_TO_MOV_TO_BANK0_REG(31) | ||
822 | MOV_TO_REG(32) | ||
823 | MOV_TO_REG(33) | ||
824 | MOV_TO_REG(34) | ||
825 | MOV_TO_REG(35) | ||
826 | MOV_TO_REG(36) | ||
827 | MOV_TO_REG(37) | ||
828 | MOV_TO_REG(38) | ||
829 | MOV_TO_REG(39) | ||
830 | MOV_TO_REG(40) | ||
831 | MOV_TO_REG(41) | ||
832 | MOV_TO_REG(42) | ||
833 | MOV_TO_REG(43) | ||
834 | MOV_TO_REG(44) | ||
835 | MOV_TO_REG(45) | ||
836 | MOV_TO_REG(46) | ||
837 | MOV_TO_REG(47) | ||
838 | MOV_TO_REG(48) | ||
839 | MOV_TO_REG(49) | ||
840 | MOV_TO_REG(50) | ||
841 | MOV_TO_REG(51) | ||
842 | MOV_TO_REG(52) | ||
843 | MOV_TO_REG(53) | ||
844 | MOV_TO_REG(54) | ||
845 | MOV_TO_REG(55) | ||
846 | MOV_TO_REG(56) | ||
847 | MOV_TO_REG(57) | ||
848 | MOV_TO_REG(58) | ||
849 | MOV_TO_REG(59) | ||
850 | MOV_TO_REG(60) | ||
851 | MOV_TO_REG(61) | ||
852 | MOV_TO_REG(62) | ||
853 | MOV_TO_REG(63) | ||
854 | MOV_TO_REG(64) | ||
855 | MOV_TO_REG(65) | ||
856 | MOV_TO_REG(66) | ||
857 | MOV_TO_REG(67) | ||
858 | MOV_TO_REG(68) | ||
859 | MOV_TO_REG(69) | ||
860 | MOV_TO_REG(70) | ||
861 | MOV_TO_REG(71) | ||
862 | MOV_TO_REG(72) | ||
863 | MOV_TO_REG(73) | ||
864 | MOV_TO_REG(74) | ||
865 | MOV_TO_REG(75) | ||
866 | MOV_TO_REG(76) | ||
867 | MOV_TO_REG(77) | ||
868 | MOV_TO_REG(78) | ||
869 | MOV_TO_REG(79) | ||
870 | MOV_TO_REG(80) | ||
871 | MOV_TO_REG(81) | ||
872 | MOV_TO_REG(82) | ||
873 | MOV_TO_REG(83) | ||
874 | MOV_TO_REG(84) | ||
875 | MOV_TO_REG(85) | ||
876 | MOV_TO_REG(86) | ||
877 | MOV_TO_REG(87) | ||
878 | MOV_TO_REG(88) | ||
879 | MOV_TO_REG(89) | ||
880 | MOV_TO_REG(90) | ||
881 | MOV_TO_REG(91) | ||
882 | MOV_TO_REG(92) | ||
883 | MOV_TO_REG(93) | ||
884 | MOV_TO_REG(94) | ||
885 | MOV_TO_REG(95) | ||
886 | MOV_TO_REG(96) | ||
887 | MOV_TO_REG(97) | ||
888 | MOV_TO_REG(98) | ||
889 | MOV_TO_REG(99) | ||
890 | MOV_TO_REG(100) | ||
891 | MOV_TO_REG(101) | ||
892 | MOV_TO_REG(102) | ||
893 | MOV_TO_REG(103) | ||
894 | MOV_TO_REG(104) | ||
895 | MOV_TO_REG(105) | ||
896 | MOV_TO_REG(106) | ||
897 | MOV_TO_REG(107) | ||
898 | MOV_TO_REG(108) | ||
899 | MOV_TO_REG(109) | ||
900 | MOV_TO_REG(110) | ||
901 | MOV_TO_REG(111) | ||
902 | MOV_TO_REG(112) | ||
903 | MOV_TO_REG(113) | ||
904 | MOV_TO_REG(114) | ||
905 | MOV_TO_REG(115) | ||
906 | MOV_TO_REG(116) | ||
907 | MOV_TO_REG(117) | ||
908 | MOV_TO_REG(118) | ||
909 | MOV_TO_REG(119) | ||
910 | MOV_TO_REG(120) | ||
911 | MOV_TO_REG(121) | ||
912 | MOV_TO_REG(122) | ||
913 | MOV_TO_REG(123) | ||
914 | MOV_TO_REG(124) | ||
915 | MOV_TO_REG(125) | ||
916 | MOV_TO_REG(126) | ||
917 | MOV_TO_REG(127) | ||
918 | END(asm_mov_to_reg) | ||
diff --git a/arch/ia64/kvm/process.c b/arch/ia64/kvm/process.c new file mode 100644 index 000000000000..5a33f7ed29a0 --- /dev/null +++ b/arch/ia64/kvm/process.c | |||
@@ -0,0 +1,970 @@ | |||
1 | /* | ||
2 | * process.c: handle interruption inject for guests. | ||
3 | * Copyright (c) 2005, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Shaofan Li (Susue Li) <susie.li@intel.com> | ||
19 | * Xiaoyan Feng (Fleming Feng) <fleming.feng@intel.com> | ||
20 | * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) | ||
21 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
22 | */ | ||
23 | #include "vcpu.h" | ||
24 | |||
25 | #include <asm/pal.h> | ||
26 | #include <asm/sal.h> | ||
27 | #include <asm/fpswa.h> | ||
28 | #include <asm/kregs.h> | ||
29 | #include <asm/tlb.h> | ||
30 | |||
31 | fpswa_interface_t *vmm_fpswa_interface; | ||
32 | |||
33 | #define IA64_VHPT_TRANS_VECTOR 0x0000 | ||
34 | #define IA64_INST_TLB_VECTOR 0x0400 | ||
35 | #define IA64_DATA_TLB_VECTOR 0x0800 | ||
36 | #define IA64_ALT_INST_TLB_VECTOR 0x0c00 | ||
37 | #define IA64_ALT_DATA_TLB_VECTOR 0x1000 | ||
38 | #define IA64_DATA_NESTED_TLB_VECTOR 0x1400 | ||
39 | #define IA64_INST_KEY_MISS_VECTOR 0x1800 | ||
40 | #define IA64_DATA_KEY_MISS_VECTOR 0x1c00 | ||
41 | #define IA64_DIRTY_BIT_VECTOR 0x2000 | ||
42 | #define IA64_INST_ACCESS_BIT_VECTOR 0x2400 | ||
43 | #define IA64_DATA_ACCESS_BIT_VECTOR 0x2800 | ||
44 | #define IA64_BREAK_VECTOR 0x2c00 | ||
45 | #define IA64_EXTINT_VECTOR 0x3000 | ||
46 | #define IA64_PAGE_NOT_PRESENT_VECTOR 0x5000 | ||
47 | #define IA64_KEY_PERMISSION_VECTOR 0x5100 | ||
48 | #define IA64_INST_ACCESS_RIGHTS_VECTOR 0x5200 | ||
49 | #define IA64_DATA_ACCESS_RIGHTS_VECTOR 0x5300 | ||
50 | #define IA64_GENEX_VECTOR 0x5400 | ||
51 | #define IA64_DISABLED_FPREG_VECTOR 0x5500 | ||
52 | #define IA64_NAT_CONSUMPTION_VECTOR 0x5600 | ||
53 | #define IA64_SPECULATION_VECTOR 0x5700 /* UNUSED */ | ||
54 | #define IA64_DEBUG_VECTOR 0x5900 | ||
55 | #define IA64_UNALIGNED_REF_VECTOR 0x5a00 | ||
56 | #define IA64_UNSUPPORTED_DATA_REF_VECTOR 0x5b00 | ||
57 | #define IA64_FP_FAULT_VECTOR 0x5c00 | ||
58 | #define IA64_FP_TRAP_VECTOR 0x5d00 | ||
59 | #define IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR 0x5e00 | ||
60 | #define IA64_TAKEN_BRANCH_TRAP_VECTOR 0x5f00 | ||
61 | #define IA64_SINGLE_STEP_TRAP_VECTOR 0x6000 | ||
62 | |||
63 | /* SDM vol2 5.5 - IVA based interruption handling */ | ||
64 | #define INITIAL_PSR_VALUE_AT_INTERRUPTION (IA64_PSR_UP | IA64_PSR_MFL |\ | ||
65 | IA64_PSR_MFH | IA64_PSR_PK | IA64_PSR_DT | \ | ||
66 | IA64_PSR_RT | IA64_PSR_MC|IA64_PSR_IT) | ||
67 | |||
68 | #define DOMN_PAL_REQUEST 0x110000 | ||
69 | #define DOMN_SAL_REQUEST 0x110001 | ||
70 | |||
71 | static u64 vec2off[68] = {0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, | ||
72 | 0x1c00, 0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, | ||
73 | 0x4000, 0x4400, 0x4800, 0x4c00, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, | ||
74 | 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5a00, 0x5b00, 0x5c00, 0x5d00, | ||
75 | 0x5e00, 0x5f00, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, | ||
76 | 0x6700, 0x6800, 0x6900, 0x6a00, 0x6b00, 0x6c00, 0x6d00, 0x6e00, 0x6f00, | ||
77 | 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 0x7800, | ||
78 | 0x7900, 0x7a00, 0x7b00, 0x7c00, 0x7d00, 0x7e00, 0x7f00 | ||
79 | }; | ||
80 | |||
81 | static void collect_interruption(struct kvm_vcpu *vcpu) | ||
82 | { | ||
83 | u64 ipsr; | ||
84 | u64 vdcr; | ||
85 | u64 vifs; | ||
86 | unsigned long vpsr; | ||
87 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
88 | |||
89 | vpsr = vcpu_get_psr(vcpu); | ||
90 | vcpu_bsw0(vcpu); | ||
91 | if (vpsr & IA64_PSR_IC) { | ||
92 | |||
93 | /* Sync mpsr id/da/dd/ss/ed bits to vipsr | ||
94 | * since after guest do rfi, we still want these bits on in | ||
95 | * mpsr | ||
96 | */ | ||
97 | |||
98 | ipsr = regs->cr_ipsr; | ||
99 | vpsr = vpsr | (ipsr & (IA64_PSR_ID | IA64_PSR_DA | ||
100 | | IA64_PSR_DD | IA64_PSR_SS | ||
101 | | IA64_PSR_ED)); | ||
102 | vcpu_set_ipsr(vcpu, vpsr); | ||
103 | |||
104 | /* Currently, for trap, we do not advance IIP to next | ||
105 | * instruction. That's because we assume caller already | ||
106 | * set up IIP correctly | ||
107 | */ | ||
108 | |||
109 | vcpu_set_iip(vcpu , regs->cr_iip); | ||
110 | |||
111 | /* set vifs.v to zero */ | ||
112 | vifs = VCPU(vcpu, ifs); | ||
113 | vifs &= ~IA64_IFS_V; | ||
114 | vcpu_set_ifs(vcpu, vifs); | ||
115 | |||
116 | vcpu_set_iipa(vcpu, VMX(vcpu, cr_iipa)); | ||
117 | } | ||
118 | |||
119 | vdcr = VCPU(vcpu, dcr); | ||
120 | |||
121 | /* Set guest psr | ||
122 | * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged | ||
123 | * be: set to the value of dcr.be | ||
124 | * pp: set to the value of dcr.pp | ||
125 | */ | ||
126 | vpsr &= INITIAL_PSR_VALUE_AT_INTERRUPTION; | ||
127 | vpsr |= (vdcr & IA64_DCR_BE); | ||
128 | |||
129 | /* VDCR pp bit position is different from VPSR pp bit */ | ||
130 | if (vdcr & IA64_DCR_PP) { | ||
131 | vpsr |= IA64_PSR_PP; | ||
132 | } else { | ||
133 | vpsr &= ~IA64_PSR_PP;; | ||
134 | } | ||
135 | |||
136 | vcpu_set_psr(vcpu, vpsr); | ||
137 | |||
138 | } | ||
139 | |||
140 | void inject_guest_interruption(struct kvm_vcpu *vcpu, u64 vec) | ||
141 | { | ||
142 | u64 viva; | ||
143 | struct kvm_pt_regs *regs; | ||
144 | union ia64_isr pt_isr; | ||
145 | |||
146 | regs = vcpu_regs(vcpu); | ||
147 | |||
148 | /* clear cr.isr.ir (incomplete register frame)*/ | ||
149 | pt_isr.val = VMX(vcpu, cr_isr); | ||
150 | pt_isr.ir = 0; | ||
151 | VMX(vcpu, cr_isr) = pt_isr.val; | ||
152 | |||
153 | collect_interruption(vcpu); | ||
154 | |||
155 | viva = vcpu_get_iva(vcpu); | ||
156 | regs->cr_iip = viva + vec; | ||
157 | } | ||
158 | |||
159 | static u64 vcpu_get_itir_on_fault(struct kvm_vcpu *vcpu, u64 ifa) | ||
160 | { | ||
161 | union ia64_rr rr, rr1; | ||
162 | |||
163 | rr.val = vcpu_get_rr(vcpu, ifa); | ||
164 | rr1.val = 0; | ||
165 | rr1.ps = rr.ps; | ||
166 | rr1.rid = rr.rid; | ||
167 | return (rr1.val); | ||
168 | } | ||
169 | |||
170 | |||
171 | /* | ||
172 | * Set vIFA & vITIR & vIHA, when vPSR.ic =1 | ||
173 | * Parameter: | ||
174 | * set_ifa: if true, set vIFA | ||
175 | * set_itir: if true, set vITIR | ||
176 | * set_iha: if true, set vIHA | ||
177 | */ | ||
178 | void set_ifa_itir_iha(struct kvm_vcpu *vcpu, u64 vadr, | ||
179 | int set_ifa, int set_itir, int set_iha) | ||
180 | { | ||
181 | long vpsr; | ||
182 | u64 value; | ||
183 | |||
184 | vpsr = VCPU(vcpu, vpsr); | ||
185 | /* Vol2, Table 8-1 */ | ||
186 | if (vpsr & IA64_PSR_IC) { | ||
187 | if (set_ifa) | ||
188 | vcpu_set_ifa(vcpu, vadr); | ||
189 | if (set_itir) { | ||
190 | value = vcpu_get_itir_on_fault(vcpu, vadr); | ||
191 | vcpu_set_itir(vcpu, value); | ||
192 | } | ||
193 | |||
194 | if (set_iha) { | ||
195 | value = vcpu_thash(vcpu, vadr); | ||
196 | vcpu_set_iha(vcpu, value); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Data TLB Fault | ||
203 | * @ Data TLB vector | ||
204 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
205 | */ | ||
206 | void dtlb_fault(struct kvm_vcpu *vcpu, u64 vadr) | ||
207 | { | ||
208 | /* If vPSR.ic, IFA, ITIR, IHA */ | ||
209 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); | ||
210 | inject_guest_interruption(vcpu, IA64_DATA_TLB_VECTOR); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Instruction TLB Fault | ||
215 | * @ Instruction TLB vector | ||
216 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
217 | */ | ||
218 | void itlb_fault(struct kvm_vcpu *vcpu, u64 vadr) | ||
219 | { | ||
220 | /* If vPSR.ic, IFA, ITIR, IHA */ | ||
221 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); | ||
222 | inject_guest_interruption(vcpu, IA64_INST_TLB_VECTOR); | ||
223 | } | ||
224 | |||
225 | |||
226 | |||
227 | /* | ||
228 | * Data Nested TLB Fault | ||
229 | * @ Data Nested TLB Vector | ||
230 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
231 | */ | ||
232 | void nested_dtlb(struct kvm_vcpu *vcpu) | ||
233 | { | ||
234 | inject_guest_interruption(vcpu, IA64_DATA_NESTED_TLB_VECTOR); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Alternate Data TLB Fault | ||
239 | * @ Alternate Data TLB vector | ||
240 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
241 | */ | ||
242 | void alt_dtlb(struct kvm_vcpu *vcpu, u64 vadr) | ||
243 | { | ||
244 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); | ||
245 | inject_guest_interruption(vcpu, IA64_ALT_DATA_TLB_VECTOR); | ||
246 | } | ||
247 | |||
248 | |||
249 | /* | ||
250 | * Data TLB Fault | ||
251 | * @ Data TLB vector | ||
252 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
253 | */ | ||
254 | void alt_itlb(struct kvm_vcpu *vcpu, u64 vadr) | ||
255 | { | ||
256 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); | ||
257 | inject_guest_interruption(vcpu, IA64_ALT_INST_TLB_VECTOR); | ||
258 | } | ||
259 | |||
260 | /* Deal with: | ||
261 | * VHPT Translation Vector | ||
262 | */ | ||
263 | static void _vhpt_fault(struct kvm_vcpu *vcpu, u64 vadr) | ||
264 | { | ||
265 | /* If vPSR.ic, IFA, ITIR, IHA*/ | ||
266 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); | ||
267 | inject_guest_interruption(vcpu, IA64_VHPT_TRANS_VECTOR); | ||
268 | |||
269 | |||
270 | } | ||
271 | |||
272 | /* | ||
273 | * VHPT Instruction Fault | ||
274 | * @ VHPT Translation vector | ||
275 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
276 | */ | ||
277 | void ivhpt_fault(struct kvm_vcpu *vcpu, u64 vadr) | ||
278 | { | ||
279 | _vhpt_fault(vcpu, vadr); | ||
280 | } | ||
281 | |||
282 | |||
283 | /* | ||
284 | * VHPT Data Fault | ||
285 | * @ VHPT Translation vector | ||
286 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
287 | */ | ||
288 | void dvhpt_fault(struct kvm_vcpu *vcpu, u64 vadr) | ||
289 | { | ||
290 | _vhpt_fault(vcpu, vadr); | ||
291 | } | ||
292 | |||
293 | |||
294 | |||
295 | /* | ||
296 | * Deal with: | ||
297 | * General Exception vector | ||
298 | */ | ||
299 | void _general_exception(struct kvm_vcpu *vcpu) | ||
300 | { | ||
301 | inject_guest_interruption(vcpu, IA64_GENEX_VECTOR); | ||
302 | } | ||
303 | |||
304 | |||
305 | /* | ||
306 | * Illegal Operation Fault | ||
307 | * @ General Exception Vector | ||
308 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
309 | */ | ||
310 | void illegal_op(struct kvm_vcpu *vcpu) | ||
311 | { | ||
312 | _general_exception(vcpu); | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Illegal Dependency Fault | ||
317 | * @ General Exception Vector | ||
318 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
319 | */ | ||
320 | void illegal_dep(struct kvm_vcpu *vcpu) | ||
321 | { | ||
322 | _general_exception(vcpu); | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Reserved Register/Field Fault | ||
327 | * @ General Exception Vector | ||
328 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
329 | */ | ||
330 | void rsv_reg_field(struct kvm_vcpu *vcpu) | ||
331 | { | ||
332 | _general_exception(vcpu); | ||
333 | } | ||
334 | /* | ||
335 | * Privileged Operation Fault | ||
336 | * @ General Exception Vector | ||
337 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
338 | */ | ||
339 | |||
340 | void privilege_op(struct kvm_vcpu *vcpu) | ||
341 | { | ||
342 | _general_exception(vcpu); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Unimplement Data Address Fault | ||
347 | * @ General Exception Vector | ||
348 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
349 | */ | ||
350 | void unimpl_daddr(struct kvm_vcpu *vcpu) | ||
351 | { | ||
352 | _general_exception(vcpu); | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Privileged Register Fault | ||
357 | * @ General Exception Vector | ||
358 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
359 | */ | ||
360 | void privilege_reg(struct kvm_vcpu *vcpu) | ||
361 | { | ||
362 | _general_exception(vcpu); | ||
363 | } | ||
364 | |||
365 | /* Deal with | ||
366 | * Nat consumption vector | ||
367 | * Parameter: | ||
368 | * vaddr: Optional, if t == REGISTER | ||
369 | */ | ||
370 | static void _nat_consumption_fault(struct kvm_vcpu *vcpu, u64 vadr, | ||
371 | enum tlb_miss_type t) | ||
372 | { | ||
373 | /* If vPSR.ic && t == DATA/INST, IFA */ | ||
374 | if (t == DATA || t == INSTRUCTION) { | ||
375 | /* IFA */ | ||
376 | set_ifa_itir_iha(vcpu, vadr, 1, 0, 0); | ||
377 | } | ||
378 | |||
379 | inject_guest_interruption(vcpu, IA64_NAT_CONSUMPTION_VECTOR); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Instruction Nat Page Consumption Fault | ||
384 | * @ Nat Consumption Vector | ||
385 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
386 | */ | ||
387 | void inat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr) | ||
388 | { | ||
389 | _nat_consumption_fault(vcpu, vadr, INSTRUCTION); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Register Nat Consumption Fault | ||
394 | * @ Nat Consumption Vector | ||
395 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
396 | */ | ||
397 | void rnat_consumption(struct kvm_vcpu *vcpu) | ||
398 | { | ||
399 | _nat_consumption_fault(vcpu, 0, REGISTER); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Data Nat Page Consumption Fault | ||
404 | * @ Nat Consumption Vector | ||
405 | * Refer to SDM Vol2 Table 5-6 & 8-1 | ||
406 | */ | ||
407 | void dnat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr) | ||
408 | { | ||
409 | _nat_consumption_fault(vcpu, vadr, DATA); | ||
410 | } | ||
411 | |||
412 | /* Deal with | ||
413 | * Page not present vector | ||
414 | */ | ||
415 | static void __page_not_present(struct kvm_vcpu *vcpu, u64 vadr) | ||
416 | { | ||
417 | /* If vPSR.ic, IFA, ITIR */ | ||
418 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); | ||
419 | inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR); | ||
420 | } | ||
421 | |||
422 | |||
423 | void data_page_not_present(struct kvm_vcpu *vcpu, u64 vadr) | ||
424 | { | ||
425 | __page_not_present(vcpu, vadr); | ||
426 | } | ||
427 | |||
428 | |||
429 | void inst_page_not_present(struct kvm_vcpu *vcpu, u64 vadr) | ||
430 | { | ||
431 | __page_not_present(vcpu, vadr); | ||
432 | } | ||
433 | |||
434 | |||
435 | /* Deal with | ||
436 | * Data access rights vector | ||
437 | */ | ||
438 | void data_access_rights(struct kvm_vcpu *vcpu, u64 vadr) | ||
439 | { | ||
440 | /* If vPSR.ic, IFA, ITIR */ | ||
441 | set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); | ||
442 | inject_guest_interruption(vcpu, IA64_DATA_ACCESS_RIGHTS_VECTOR); | ||
443 | } | ||
444 | |||
445 | fpswa_ret_t vmm_fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr, | ||
446 | unsigned long *fpsr, unsigned long *isr, unsigned long *pr, | ||
447 | unsigned long *ifs, struct kvm_pt_regs *regs) | ||
448 | { | ||
449 | fp_state_t fp_state; | ||
450 | fpswa_ret_t ret; | ||
451 | struct kvm_vcpu *vcpu = current_vcpu; | ||
452 | |||
453 | uint64_t old_rr7 = ia64_get_rr(7UL<<61); | ||
454 | |||
455 | if (!vmm_fpswa_interface) | ||
456 | return (fpswa_ret_t) {-1, 0, 0, 0}; | ||
457 | |||
458 | /* | ||
459 | * Just let fpswa driver to use hardware fp registers. | ||
460 | * No fp register is valid in memory. | ||
461 | */ | ||
462 | memset(&fp_state, 0, sizeof(fp_state_t)); | ||
463 | |||
464 | /* | ||
465 | * unsigned long (*EFI_FPSWA) ( | ||
466 | * unsigned long trap_type, | ||
467 | * void *Bundle, | ||
468 | * unsigned long *pipsr, | ||
469 | * unsigned long *pfsr, | ||
470 | * unsigned long *pisr, | ||
471 | * unsigned long *ppreds, | ||
472 | * unsigned long *pifs, | ||
473 | * void *fp_state); | ||
474 | */ | ||
475 | /*Call host fpswa interface directly to virtualize | ||
476 | *guest fpswa request! | ||
477 | */ | ||
478 | ia64_set_rr(7UL << 61, vcpu->arch.host.rr[7]); | ||
479 | ia64_srlz_d(); | ||
480 | |||
481 | ret = (*vmm_fpswa_interface->fpswa) (fp_fault, bundle, | ||
482 | ipsr, fpsr, isr, pr, ifs, &fp_state); | ||
483 | ia64_set_rr(7UL << 61, old_rr7); | ||
484 | ia64_srlz_d(); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * Handle floating-point assist faults and traps for domain. | ||
490 | */ | ||
491 | unsigned long vmm_handle_fpu_swa(int fp_fault, struct kvm_pt_regs *regs, | ||
492 | unsigned long isr) | ||
493 | { | ||
494 | struct kvm_vcpu *v = current_vcpu; | ||
495 | IA64_BUNDLE bundle; | ||
496 | unsigned long fault_ip; | ||
497 | fpswa_ret_t ret; | ||
498 | |||
499 | fault_ip = regs->cr_iip; | ||
500 | /* | ||
501 | * When the FP trap occurs, the trapping instruction is completed. | ||
502 | * If ipsr.ri == 0, there is the trapping instruction in previous | ||
503 | * bundle. | ||
504 | */ | ||
505 | if (!fp_fault && (ia64_psr(regs)->ri == 0)) | ||
506 | fault_ip -= 16; | ||
507 | |||
508 | if (fetch_code(v, fault_ip, &bundle)) | ||
509 | return -EAGAIN; | ||
510 | |||
511 | if (!bundle.i64[0] && !bundle.i64[1]) | ||
512 | return -EACCES; | ||
513 | |||
514 | ret = vmm_fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, | ||
515 | &isr, ®s->pr, ®s->cr_ifs, regs); | ||
516 | return ret.status; | ||
517 | } | ||
518 | |||
519 | void reflect_interruption(u64 ifa, u64 isr, u64 iim, | ||
520 | u64 vec, struct kvm_pt_regs *regs) | ||
521 | { | ||
522 | u64 vector; | ||
523 | int status ; | ||
524 | struct kvm_vcpu *vcpu = current_vcpu; | ||
525 | u64 vpsr = VCPU(vcpu, vpsr); | ||
526 | |||
527 | vector = vec2off[vec]; | ||
528 | |||
529 | if (!(vpsr & IA64_PSR_IC) && (vector != IA64_DATA_NESTED_TLB_VECTOR)) { | ||
530 | panic_vm(vcpu); | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | switch (vec) { | ||
535 | case 32: /*IA64_FP_FAULT_VECTOR*/ | ||
536 | status = vmm_handle_fpu_swa(1, regs, isr); | ||
537 | if (!status) { | ||
538 | vcpu_increment_iip(vcpu); | ||
539 | return; | ||
540 | } else if (-EAGAIN == status) | ||
541 | return; | ||
542 | break; | ||
543 | case 33: /*IA64_FP_TRAP_VECTOR*/ | ||
544 | status = vmm_handle_fpu_swa(0, regs, isr); | ||
545 | if (!status) | ||
546 | return ; | ||
547 | else if (-EAGAIN == status) { | ||
548 | vcpu_decrement_iip(vcpu); | ||
549 | return ; | ||
550 | } | ||
551 | break; | ||
552 | } | ||
553 | |||
554 | VCPU(vcpu, isr) = isr; | ||
555 | VCPU(vcpu, iipa) = regs->cr_iip; | ||
556 | if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) | ||
557 | VCPU(vcpu, iim) = iim; | ||
558 | else | ||
559 | set_ifa_itir_iha(vcpu, ifa, 1, 1, 1); | ||
560 | |||
561 | inject_guest_interruption(vcpu, vector); | ||
562 | } | ||
563 | |||
564 | static void set_pal_call_data(struct kvm_vcpu *vcpu) | ||
565 | { | ||
566 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
567 | |||
568 | /*FIXME:For static and stacked convention, firmware | ||
569 | * has put the parameters in gr28-gr31 before | ||
570 | * break to vmm !!*/ | ||
571 | |||
572 | p->u.pal_data.gr28 = vcpu_get_gr(vcpu, 28); | ||
573 | p->u.pal_data.gr29 = vcpu_get_gr(vcpu, 29); | ||
574 | p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30); | ||
575 | p->u.pal_data.gr31 = vcpu_get_gr(vcpu, 31); | ||
576 | p->exit_reason = EXIT_REASON_PAL_CALL; | ||
577 | } | ||
578 | |||
579 | static void set_pal_call_result(struct kvm_vcpu *vcpu) | ||
580 | { | ||
581 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
582 | |||
583 | if (p->exit_reason == EXIT_REASON_PAL_CALL) { | ||
584 | vcpu_set_gr(vcpu, 8, p->u.pal_data.ret.status, 0); | ||
585 | vcpu_set_gr(vcpu, 9, p->u.pal_data.ret.v0, 0); | ||
586 | vcpu_set_gr(vcpu, 10, p->u.pal_data.ret.v1, 0); | ||
587 | vcpu_set_gr(vcpu, 11, p->u.pal_data.ret.v2, 0); | ||
588 | } else | ||
589 | panic_vm(vcpu); | ||
590 | } | ||
591 | |||
592 | static void set_sal_call_data(struct kvm_vcpu *vcpu) | ||
593 | { | ||
594 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
595 | |||
596 | p->u.sal_data.in0 = vcpu_get_gr(vcpu, 32); | ||
597 | p->u.sal_data.in1 = vcpu_get_gr(vcpu, 33); | ||
598 | p->u.sal_data.in2 = vcpu_get_gr(vcpu, 34); | ||
599 | p->u.sal_data.in3 = vcpu_get_gr(vcpu, 35); | ||
600 | p->u.sal_data.in4 = vcpu_get_gr(vcpu, 36); | ||
601 | p->u.sal_data.in5 = vcpu_get_gr(vcpu, 37); | ||
602 | p->u.sal_data.in6 = vcpu_get_gr(vcpu, 38); | ||
603 | p->u.sal_data.in7 = vcpu_get_gr(vcpu, 39); | ||
604 | p->exit_reason = EXIT_REASON_SAL_CALL; | ||
605 | } | ||
606 | |||
607 | static void set_sal_call_result(struct kvm_vcpu *vcpu) | ||
608 | { | ||
609 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
610 | |||
611 | if (p->exit_reason == EXIT_REASON_SAL_CALL) { | ||
612 | vcpu_set_gr(vcpu, 8, p->u.sal_data.ret.r8, 0); | ||
613 | vcpu_set_gr(vcpu, 9, p->u.sal_data.ret.r9, 0); | ||
614 | vcpu_set_gr(vcpu, 10, p->u.sal_data.ret.r10, 0); | ||
615 | vcpu_set_gr(vcpu, 11, p->u.sal_data.ret.r11, 0); | ||
616 | } else | ||
617 | panic_vm(vcpu); | ||
618 | } | ||
619 | |||
620 | void kvm_ia64_handle_break(unsigned long ifa, struct kvm_pt_regs *regs, | ||
621 | unsigned long isr, unsigned long iim) | ||
622 | { | ||
623 | struct kvm_vcpu *v = current_vcpu; | ||
624 | |||
625 | if (ia64_psr(regs)->cpl == 0) { | ||
626 | /* Allow hypercalls only when cpl = 0. */ | ||
627 | if (iim == DOMN_PAL_REQUEST) { | ||
628 | set_pal_call_data(v); | ||
629 | vmm_transition(v); | ||
630 | set_pal_call_result(v); | ||
631 | vcpu_increment_iip(v); | ||
632 | return; | ||
633 | } else if (iim == DOMN_SAL_REQUEST) { | ||
634 | set_sal_call_data(v); | ||
635 | vmm_transition(v); | ||
636 | set_sal_call_result(v); | ||
637 | vcpu_increment_iip(v); | ||
638 | return; | ||
639 | } | ||
640 | } | ||
641 | reflect_interruption(ifa, isr, iim, 11, regs); | ||
642 | } | ||
643 | |||
644 | void check_pending_irq(struct kvm_vcpu *vcpu) | ||
645 | { | ||
646 | int mask, h_pending, h_inservice; | ||
647 | u64 isr; | ||
648 | unsigned long vpsr; | ||
649 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
650 | |||
651 | h_pending = highest_pending_irq(vcpu); | ||
652 | if (h_pending == NULL_VECTOR) { | ||
653 | update_vhpi(vcpu, NULL_VECTOR); | ||
654 | return; | ||
655 | } | ||
656 | h_inservice = highest_inservice_irq(vcpu); | ||
657 | |||
658 | vpsr = VCPU(vcpu, vpsr); | ||
659 | mask = irq_masked(vcpu, h_pending, h_inservice); | ||
660 | if ((vpsr & IA64_PSR_I) && IRQ_NO_MASKED == mask) { | ||
661 | isr = vpsr & IA64_PSR_RI; | ||
662 | update_vhpi(vcpu, h_pending); | ||
663 | reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ | ||
664 | } else if (mask == IRQ_MASKED_BY_INSVC) { | ||
665 | if (VCPU(vcpu, vhpi)) | ||
666 | update_vhpi(vcpu, NULL_VECTOR); | ||
667 | } else { | ||
668 | /* masked by vpsr.i or vtpr.*/ | ||
669 | update_vhpi(vcpu, h_pending); | ||
670 | } | ||
671 | } | ||
672 | |||
673 | static void generate_exirq(struct kvm_vcpu *vcpu) | ||
674 | { | ||
675 | unsigned vpsr; | ||
676 | uint64_t isr; | ||
677 | |||
678 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
679 | |||
680 | vpsr = VCPU(vcpu, vpsr); | ||
681 | isr = vpsr & IA64_PSR_RI; | ||
682 | if (!(vpsr & IA64_PSR_IC)) | ||
683 | panic_vm(vcpu); | ||
684 | reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ | ||
685 | } | ||
686 | |||
687 | void vhpi_detection(struct kvm_vcpu *vcpu) | ||
688 | { | ||
689 | uint64_t threshold, vhpi; | ||
690 | union ia64_tpr vtpr; | ||
691 | struct ia64_psr vpsr; | ||
692 | |||
693 | vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
694 | vtpr.val = VCPU(vcpu, tpr); | ||
695 | |||
696 | threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; | ||
697 | vhpi = VCPU(vcpu, vhpi); | ||
698 | if (vhpi > threshold) { | ||
699 | /* interrupt actived*/ | ||
700 | generate_exirq(vcpu); | ||
701 | } | ||
702 | } | ||
703 | |||
704 | |||
705 | void leave_hypervisor_tail(void) | ||
706 | { | ||
707 | struct kvm_vcpu *v = current_vcpu; | ||
708 | |||
709 | if (VMX(v, timer_check)) { | ||
710 | VMX(v, timer_check) = 0; | ||
711 | if (VMX(v, itc_check)) { | ||
712 | if (vcpu_get_itc(v) > VCPU(v, itm)) { | ||
713 | if (!(VCPU(v, itv) & (1 << 16))) { | ||
714 | vcpu_pend_interrupt(v, VCPU(v, itv) | ||
715 | & 0xff); | ||
716 | VMX(v, itc_check) = 0; | ||
717 | } else { | ||
718 | v->arch.timer_pending = 1; | ||
719 | } | ||
720 | VMX(v, last_itc) = VCPU(v, itm) + 1; | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | |||
725 | rmb(); | ||
726 | if (v->arch.irq_new_pending) { | ||
727 | v->arch.irq_new_pending = 0; | ||
728 | VMX(v, irq_check) = 0; | ||
729 | check_pending_irq(v); | ||
730 | return; | ||
731 | } | ||
732 | if (VMX(v, irq_check)) { | ||
733 | VMX(v, irq_check) = 0; | ||
734 | vhpi_detection(v); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | |||
739 | static inline void handle_lds(struct kvm_pt_regs *regs) | ||
740 | { | ||
741 | regs->cr_ipsr |= IA64_PSR_ED; | ||
742 | } | ||
743 | |||
744 | void physical_tlb_miss(struct kvm_vcpu *vcpu, unsigned long vadr, int type) | ||
745 | { | ||
746 | unsigned long pte; | ||
747 | union ia64_rr rr; | ||
748 | |||
749 | rr.val = ia64_get_rr(vadr); | ||
750 | pte = vadr & _PAGE_PPN_MASK; | ||
751 | pte = pte | PHY_PAGE_WB; | ||
752 | thash_vhpt_insert(vcpu, pte, (u64)(rr.ps << 2), vadr, type); | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | void kvm_page_fault(u64 vadr , u64 vec, struct kvm_pt_regs *regs) | ||
757 | { | ||
758 | unsigned long vpsr; | ||
759 | int type; | ||
760 | |||
761 | u64 vhpt_adr, gppa, pteval, rr, itir; | ||
762 | union ia64_isr misr; | ||
763 | union ia64_pta vpta; | ||
764 | struct thash_data *data; | ||
765 | struct kvm_vcpu *v = current_vcpu; | ||
766 | |||
767 | vpsr = VCPU(v, vpsr); | ||
768 | misr.val = VMX(v, cr_isr); | ||
769 | |||
770 | type = vec; | ||
771 | |||
772 | if (is_physical_mode(v) && (!(vadr << 1 >> 62))) { | ||
773 | if (vec == 2) { | ||
774 | if (__gpfn_is_io((vadr << 1) >> (PAGE_SHIFT + 1))) { | ||
775 | emulate_io_inst(v, ((vadr << 1) >> 1), 4); | ||
776 | return; | ||
777 | } | ||
778 | } | ||
779 | physical_tlb_miss(v, vadr, type); | ||
780 | return; | ||
781 | } | ||
782 | data = vtlb_lookup(v, vadr, type); | ||
783 | if (data != 0) { | ||
784 | if (type == D_TLB) { | ||
785 | gppa = (vadr & ((1UL << data->ps) - 1)) | ||
786 | + (data->ppn >> (data->ps - 12) << data->ps); | ||
787 | if (__gpfn_is_io(gppa >> PAGE_SHIFT)) { | ||
788 | if (data->pl >= ((regs->cr_ipsr >> | ||
789 | IA64_PSR_CPL0_BIT) & 3)) | ||
790 | emulate_io_inst(v, gppa, data->ma); | ||
791 | else { | ||
792 | vcpu_set_isr(v, misr.val); | ||
793 | data_access_rights(v, vadr); | ||
794 | } | ||
795 | return ; | ||
796 | } | ||
797 | } | ||
798 | thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type); | ||
799 | |||
800 | } else if (type == D_TLB) { | ||
801 | if (misr.sp) { | ||
802 | handle_lds(regs); | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | rr = vcpu_get_rr(v, vadr); | ||
807 | itir = rr & (RR_RID_MASK | RR_PS_MASK); | ||
808 | |||
809 | if (!vhpt_enabled(v, vadr, misr.rs ? RSE_REF : DATA_REF)) { | ||
810 | if (vpsr & IA64_PSR_IC) { | ||
811 | vcpu_set_isr(v, misr.val); | ||
812 | alt_dtlb(v, vadr); | ||
813 | } else { | ||
814 | nested_dtlb(v); | ||
815 | } | ||
816 | return ; | ||
817 | } | ||
818 | |||
819 | vpta.val = vcpu_get_pta(v); | ||
820 | /* avoid recursively walking (short format) VHPT */ | ||
821 | |||
822 | vhpt_adr = vcpu_thash(v, vadr); | ||
823 | if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { | ||
824 | /* VHPT successfully read. */ | ||
825 | if (!(pteval & _PAGE_P)) { | ||
826 | if (vpsr & IA64_PSR_IC) { | ||
827 | vcpu_set_isr(v, misr.val); | ||
828 | dtlb_fault(v, vadr); | ||
829 | } else { | ||
830 | nested_dtlb(v); | ||
831 | } | ||
832 | } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { | ||
833 | thash_purge_and_insert(v, pteval, itir, | ||
834 | vadr, D_TLB); | ||
835 | } else if (vpsr & IA64_PSR_IC) { | ||
836 | vcpu_set_isr(v, misr.val); | ||
837 | dtlb_fault(v, vadr); | ||
838 | } else { | ||
839 | nested_dtlb(v); | ||
840 | } | ||
841 | } else { | ||
842 | /* Can't read VHPT. */ | ||
843 | if (vpsr & IA64_PSR_IC) { | ||
844 | vcpu_set_isr(v, misr.val); | ||
845 | dvhpt_fault(v, vadr); | ||
846 | } else { | ||
847 | nested_dtlb(v); | ||
848 | } | ||
849 | } | ||
850 | } else if (type == I_TLB) { | ||
851 | if (!(vpsr & IA64_PSR_IC)) | ||
852 | misr.ni = 1; | ||
853 | if (!vhpt_enabled(v, vadr, INST_REF)) { | ||
854 | vcpu_set_isr(v, misr.val); | ||
855 | alt_itlb(v, vadr); | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | vpta.val = vcpu_get_pta(v); | ||
860 | |||
861 | vhpt_adr = vcpu_thash(v, vadr); | ||
862 | if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { | ||
863 | /* VHPT successfully read. */ | ||
864 | if (pteval & _PAGE_P) { | ||
865 | if ((pteval & _PAGE_MA_MASK) == _PAGE_MA_ST) { | ||
866 | vcpu_set_isr(v, misr.val); | ||
867 | itlb_fault(v, vadr); | ||
868 | return ; | ||
869 | } | ||
870 | rr = vcpu_get_rr(v, vadr); | ||
871 | itir = rr & (RR_RID_MASK | RR_PS_MASK); | ||
872 | thash_purge_and_insert(v, pteval, itir, | ||
873 | vadr, I_TLB); | ||
874 | } else { | ||
875 | vcpu_set_isr(v, misr.val); | ||
876 | inst_page_not_present(v, vadr); | ||
877 | } | ||
878 | } else { | ||
879 | vcpu_set_isr(v, misr.val); | ||
880 | ivhpt_fault(v, vadr); | ||
881 | } | ||
882 | } | ||
883 | } | ||
884 | |||
885 | void kvm_vexirq(struct kvm_vcpu *vcpu) | ||
886 | { | ||
887 | u64 vpsr, isr; | ||
888 | struct kvm_pt_regs *regs; | ||
889 | |||
890 | regs = vcpu_regs(vcpu); | ||
891 | vpsr = VCPU(vcpu, vpsr); | ||
892 | isr = vpsr & IA64_PSR_RI; | ||
893 | reflect_interruption(0, isr, 0, 12, regs); /*EXT IRQ*/ | ||
894 | } | ||
895 | |||
896 | void kvm_ia64_handle_irq(struct kvm_vcpu *v) | ||
897 | { | ||
898 | struct exit_ctl_data *p = &v->arch.exit_data; | ||
899 | long psr; | ||
900 | |||
901 | local_irq_save(psr); | ||
902 | p->exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT; | ||
903 | vmm_transition(v); | ||
904 | local_irq_restore(psr); | ||
905 | |||
906 | VMX(v, timer_check) = 1; | ||
907 | |||
908 | } | ||
909 | |||
910 | static void ptc_ga_remote_func(struct kvm_vcpu *v, int pos) | ||
911 | { | ||
912 | u64 oldrid, moldrid, oldpsbits, vaddr; | ||
913 | struct kvm_ptc_g *p = &v->arch.ptc_g_data[pos]; | ||
914 | vaddr = p->vaddr; | ||
915 | |||
916 | oldrid = VMX(v, vrr[0]); | ||
917 | VMX(v, vrr[0]) = p->rr; | ||
918 | oldpsbits = VMX(v, psbits[0]); | ||
919 | VMX(v, psbits[0]) = VMX(v, psbits[REGION_NUMBER(vaddr)]); | ||
920 | moldrid = ia64_get_rr(0x0); | ||
921 | ia64_set_rr(0x0, vrrtomrr(p->rr)); | ||
922 | ia64_srlz_d(); | ||
923 | |||
924 | vaddr = PAGEALIGN(vaddr, p->ps); | ||
925 | thash_purge_entries_remote(v, vaddr, p->ps); | ||
926 | |||
927 | VMX(v, vrr[0]) = oldrid; | ||
928 | VMX(v, psbits[0]) = oldpsbits; | ||
929 | ia64_set_rr(0x0, moldrid); | ||
930 | ia64_dv_serialize_data(); | ||
931 | } | ||
932 | |||
933 | static void vcpu_do_resume(struct kvm_vcpu *vcpu) | ||
934 | { | ||
935 | /*Re-init VHPT and VTLB once from resume*/ | ||
936 | vcpu->arch.vhpt.num = VHPT_NUM_ENTRIES; | ||
937 | thash_init(&vcpu->arch.vhpt, VHPT_SHIFT); | ||
938 | vcpu->arch.vtlb.num = VTLB_NUM_ENTRIES; | ||
939 | thash_init(&vcpu->arch.vtlb, VTLB_SHIFT); | ||
940 | |||
941 | ia64_set_pta(vcpu->arch.vhpt.pta.val); | ||
942 | } | ||
943 | |||
944 | static void kvm_do_resume_op(struct kvm_vcpu *vcpu) | ||
945 | { | ||
946 | if (test_and_clear_bit(KVM_REQ_RESUME, &vcpu->requests)) { | ||
947 | vcpu_do_resume(vcpu); | ||
948 | return; | ||
949 | } | ||
950 | |||
951 | if (unlikely(test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))) { | ||
952 | thash_purge_all(vcpu); | ||
953 | return; | ||
954 | } | ||
955 | |||
956 | if (test_and_clear_bit(KVM_REQ_PTC_G, &vcpu->requests)) { | ||
957 | while (vcpu->arch.ptc_g_count > 0) | ||
958 | ptc_ga_remote_func(vcpu, --vcpu->arch.ptc_g_count); | ||
959 | } | ||
960 | } | ||
961 | |||
962 | void vmm_transition(struct kvm_vcpu *vcpu) | ||
963 | { | ||
964 | ia64_call_vsa(PAL_VPS_SAVE, (unsigned long)vcpu->arch.vpd, | ||
965 | 0, 0, 0, 0, 0, 0); | ||
966 | vmm_trampoline(&vcpu->arch.guest, &vcpu->arch.host); | ||
967 | ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)vcpu->arch.vpd, | ||
968 | 0, 0, 0, 0, 0, 0); | ||
969 | kvm_do_resume_op(vcpu); | ||
970 | } | ||
diff --git a/arch/ia64/kvm/trampoline.S b/arch/ia64/kvm/trampoline.S new file mode 100644 index 000000000000..30897d44d61e --- /dev/null +++ b/arch/ia64/kvm/trampoline.S | |||
@@ -0,0 +1,1038 @@ | |||
1 | /* Save all processor states | ||
2 | * | ||
3 | * Copyright (c) 2007 Fleming Feng <fleming.feng@intel.com> | ||
4 | * Copyright (c) 2007 Anthony Xu <anthony.xu@intel.com> | ||
5 | */ | ||
6 | |||
7 | #include <asm/asmmacro.h> | ||
8 | #include "asm-offsets.h" | ||
9 | |||
10 | |||
11 | #define CTX(name) VMM_CTX_##name##_OFFSET | ||
12 | |||
13 | /* | ||
14 | * r32: context_t base address | ||
15 | */ | ||
16 | #define SAVE_BRANCH_REGS \ | ||
17 | add r2 = CTX(B0),r32; \ | ||
18 | add r3 = CTX(B1),r32; \ | ||
19 | mov r16 = b0; \ | ||
20 | mov r17 = b1; \ | ||
21 | ;; \ | ||
22 | st8 [r2]=r16,16; \ | ||
23 | st8 [r3]=r17,16; \ | ||
24 | ;; \ | ||
25 | mov r16 = b2; \ | ||
26 | mov r17 = b3; \ | ||
27 | ;; \ | ||
28 | st8 [r2]=r16,16; \ | ||
29 | st8 [r3]=r17,16; \ | ||
30 | ;; \ | ||
31 | mov r16 = b4; \ | ||
32 | mov r17 = b5; \ | ||
33 | ;; \ | ||
34 | st8 [r2]=r16; \ | ||
35 | st8 [r3]=r17; \ | ||
36 | ;; | ||
37 | |||
38 | /* | ||
39 | * r33: context_t base address | ||
40 | */ | ||
41 | #define RESTORE_BRANCH_REGS \ | ||
42 | add r2 = CTX(B0),r33; \ | ||
43 | add r3 = CTX(B1),r33; \ | ||
44 | ;; \ | ||
45 | ld8 r16=[r2],16; \ | ||
46 | ld8 r17=[r3],16; \ | ||
47 | ;; \ | ||
48 | mov b0 = r16; \ | ||
49 | mov b1 = r17; \ | ||
50 | ;; \ | ||
51 | ld8 r16=[r2],16; \ | ||
52 | ld8 r17=[r3],16; \ | ||
53 | ;; \ | ||
54 | mov b2 = r16; \ | ||
55 | mov b3 = r17; \ | ||
56 | ;; \ | ||
57 | ld8 r16=[r2]; \ | ||
58 | ld8 r17=[r3]; \ | ||
59 | ;; \ | ||
60 | mov b4=r16; \ | ||
61 | mov b5=r17; \ | ||
62 | ;; | ||
63 | |||
64 | |||
65 | /* | ||
66 | * r32: context_t base address | ||
67 | * bsw == 1 | ||
68 | * Save all bank1 general registers, r4 ~ r7 | ||
69 | */ | ||
70 | #define SAVE_GENERAL_REGS \ | ||
71 | add r2=CTX(R4),r32; \ | ||
72 | add r3=CTX(R5),r32; \ | ||
73 | ;; \ | ||
74 | .mem.offset 0,0; \ | ||
75 | st8.spill [r2]=r4,16; \ | ||
76 | .mem.offset 8,0; \ | ||
77 | st8.spill [r3]=r5,16; \ | ||
78 | ;; \ | ||
79 | .mem.offset 0,0; \ | ||
80 | st8.spill [r2]=r6,48; \ | ||
81 | .mem.offset 8,0; \ | ||
82 | st8.spill [r3]=r7,48; \ | ||
83 | ;; \ | ||
84 | .mem.offset 0,0; \ | ||
85 | st8.spill [r2]=r12; \ | ||
86 | .mem.offset 8,0; \ | ||
87 | st8.spill [r3]=r13; \ | ||
88 | ;; | ||
89 | |||
90 | /* | ||
91 | * r33: context_t base address | ||
92 | * bsw == 1 | ||
93 | */ | ||
94 | #define RESTORE_GENERAL_REGS \ | ||
95 | add r2=CTX(R4),r33; \ | ||
96 | add r3=CTX(R5),r33; \ | ||
97 | ;; \ | ||
98 | ld8.fill r4=[r2],16; \ | ||
99 | ld8.fill r5=[r3],16; \ | ||
100 | ;; \ | ||
101 | ld8.fill r6=[r2],48; \ | ||
102 | ld8.fill r7=[r3],48; \ | ||
103 | ;; \ | ||
104 | ld8.fill r12=[r2]; \ | ||
105 | ld8.fill r13 =[r3]; \ | ||
106 | ;; | ||
107 | |||
108 | |||
109 | |||
110 | |||
111 | /* | ||
112 | * r32: context_t base address | ||
113 | */ | ||
114 | #define SAVE_KERNEL_REGS \ | ||
115 | add r2 = CTX(KR0),r32; \ | ||
116 | add r3 = CTX(KR1),r32; \ | ||
117 | mov r16 = ar.k0; \ | ||
118 | mov r17 = ar.k1; \ | ||
119 | ;; \ | ||
120 | st8 [r2] = r16,16; \ | ||
121 | st8 [r3] = r17,16; \ | ||
122 | ;; \ | ||
123 | mov r16 = ar.k2; \ | ||
124 | mov r17 = ar.k3; \ | ||
125 | ;; \ | ||
126 | st8 [r2] = r16,16; \ | ||
127 | st8 [r3] = r17,16; \ | ||
128 | ;; \ | ||
129 | mov r16 = ar.k4; \ | ||
130 | mov r17 = ar.k5; \ | ||
131 | ;; \ | ||
132 | st8 [r2] = r16,16; \ | ||
133 | st8 [r3] = r17,16; \ | ||
134 | ;; \ | ||
135 | mov r16 = ar.k6; \ | ||
136 | mov r17 = ar.k7; \ | ||
137 | ;; \ | ||
138 | st8 [r2] = r16; \ | ||
139 | st8 [r3] = r17; \ | ||
140 | ;; | ||
141 | |||
142 | |||
143 | |||
144 | /* | ||
145 | * r33: context_t base address | ||
146 | */ | ||
147 | #define RESTORE_KERNEL_REGS \ | ||
148 | add r2 = CTX(KR0),r33; \ | ||
149 | add r3 = CTX(KR1),r33; \ | ||
150 | ;; \ | ||
151 | ld8 r16=[r2],16; \ | ||
152 | ld8 r17=[r3],16; \ | ||
153 | ;; \ | ||
154 | mov ar.k0=r16; \ | ||
155 | mov ar.k1=r17; \ | ||
156 | ;; \ | ||
157 | ld8 r16=[r2],16; \ | ||
158 | ld8 r17=[r3],16; \ | ||
159 | ;; \ | ||
160 | mov ar.k2=r16; \ | ||
161 | mov ar.k3=r17; \ | ||
162 | ;; \ | ||
163 | ld8 r16=[r2],16; \ | ||
164 | ld8 r17=[r3],16; \ | ||
165 | ;; \ | ||
166 | mov ar.k4=r16; \ | ||
167 | mov ar.k5=r17; \ | ||
168 | ;; \ | ||
169 | ld8 r16=[r2],16; \ | ||
170 | ld8 r17=[r3],16; \ | ||
171 | ;; \ | ||
172 | mov ar.k6=r16; \ | ||
173 | mov ar.k7=r17; \ | ||
174 | ;; | ||
175 | |||
176 | |||
177 | |||
178 | /* | ||
179 | * r32: context_t base address | ||
180 | */ | ||
181 | #define SAVE_APP_REGS \ | ||
182 | add r2 = CTX(BSPSTORE),r32; \ | ||
183 | mov r16 = ar.bspstore; \ | ||
184 | ;; \ | ||
185 | st8 [r2] = r16,CTX(RNAT)-CTX(BSPSTORE);\ | ||
186 | mov r16 = ar.rnat; \ | ||
187 | ;; \ | ||
188 | st8 [r2] = r16,CTX(FCR)-CTX(RNAT); \ | ||
189 | mov r16 = ar.fcr; \ | ||
190 | ;; \ | ||
191 | st8 [r2] = r16,CTX(EFLAG)-CTX(FCR); \ | ||
192 | mov r16 = ar.eflag; \ | ||
193 | ;; \ | ||
194 | st8 [r2] = r16,CTX(CFLG)-CTX(EFLAG); \ | ||
195 | mov r16 = ar.cflg; \ | ||
196 | ;; \ | ||
197 | st8 [r2] = r16,CTX(FSR)-CTX(CFLG); \ | ||
198 | mov r16 = ar.fsr; \ | ||
199 | ;; \ | ||
200 | st8 [r2] = r16,CTX(FIR)-CTX(FSR); \ | ||
201 | mov r16 = ar.fir; \ | ||
202 | ;; \ | ||
203 | st8 [r2] = r16,CTX(FDR)-CTX(FIR); \ | ||
204 | mov r16 = ar.fdr; \ | ||
205 | ;; \ | ||
206 | st8 [r2] = r16,CTX(UNAT)-CTX(FDR); \ | ||
207 | mov r16 = ar.unat; \ | ||
208 | ;; \ | ||
209 | st8 [r2] = r16,CTX(FPSR)-CTX(UNAT); \ | ||
210 | mov r16 = ar.fpsr; \ | ||
211 | ;; \ | ||
212 | st8 [r2] = r16,CTX(PFS)-CTX(FPSR); \ | ||
213 | mov r16 = ar.pfs; \ | ||
214 | ;; \ | ||
215 | st8 [r2] = r16,CTX(LC)-CTX(PFS); \ | ||
216 | mov r16 = ar.lc; \ | ||
217 | ;; \ | ||
218 | st8 [r2] = r16; \ | ||
219 | ;; | ||
220 | |||
221 | /* | ||
222 | * r33: context_t base address | ||
223 | */ | ||
224 | #define RESTORE_APP_REGS \ | ||
225 | add r2=CTX(BSPSTORE),r33; \ | ||
226 | ;; \ | ||
227 | ld8 r16=[r2],CTX(RNAT)-CTX(BSPSTORE); \ | ||
228 | ;; \ | ||
229 | mov ar.bspstore=r16; \ | ||
230 | ld8 r16=[r2],CTX(FCR)-CTX(RNAT); \ | ||
231 | ;; \ | ||
232 | mov ar.rnat=r16; \ | ||
233 | ld8 r16=[r2],CTX(EFLAG)-CTX(FCR); \ | ||
234 | ;; \ | ||
235 | mov ar.fcr=r16; \ | ||
236 | ld8 r16=[r2],CTX(CFLG)-CTX(EFLAG); \ | ||
237 | ;; \ | ||
238 | mov ar.eflag=r16; \ | ||
239 | ld8 r16=[r2],CTX(FSR)-CTX(CFLG); \ | ||
240 | ;; \ | ||
241 | mov ar.cflg=r16; \ | ||
242 | ld8 r16=[r2],CTX(FIR)-CTX(FSR); \ | ||
243 | ;; \ | ||
244 | mov ar.fsr=r16; \ | ||
245 | ld8 r16=[r2],CTX(FDR)-CTX(FIR); \ | ||
246 | ;; \ | ||
247 | mov ar.fir=r16; \ | ||
248 | ld8 r16=[r2],CTX(UNAT)-CTX(FDR); \ | ||
249 | ;; \ | ||
250 | mov ar.fdr=r16; \ | ||
251 | ld8 r16=[r2],CTX(FPSR)-CTX(UNAT); \ | ||
252 | ;; \ | ||
253 | mov ar.unat=r16; \ | ||
254 | ld8 r16=[r2],CTX(PFS)-CTX(FPSR); \ | ||
255 | ;; \ | ||
256 | mov ar.fpsr=r16; \ | ||
257 | ld8 r16=[r2],CTX(LC)-CTX(PFS); \ | ||
258 | ;; \ | ||
259 | mov ar.pfs=r16; \ | ||
260 | ld8 r16=[r2]; \ | ||
261 | ;; \ | ||
262 | mov ar.lc=r16; \ | ||
263 | ;; | ||
264 | |||
265 | /* | ||
266 | * r32: context_t base address | ||
267 | */ | ||
268 | #define SAVE_CTL_REGS \ | ||
269 | add r2 = CTX(DCR),r32; \ | ||
270 | mov r16 = cr.dcr; \ | ||
271 | ;; \ | ||
272 | st8 [r2] = r16,CTX(IVA)-CTX(DCR); \ | ||
273 | ;; \ | ||
274 | mov r16 = cr.iva; \ | ||
275 | ;; \ | ||
276 | st8 [r2] = r16,CTX(PTA)-CTX(IVA); \ | ||
277 | ;; \ | ||
278 | mov r16 = cr.pta; \ | ||
279 | ;; \ | ||
280 | st8 [r2] = r16 ; \ | ||
281 | ;; | ||
282 | |||
283 | /* | ||
284 | * r33: context_t base address | ||
285 | */ | ||
286 | #define RESTORE_CTL_REGS \ | ||
287 | add r2 = CTX(DCR),r33; \ | ||
288 | ;; \ | ||
289 | ld8 r16 = [r2],CTX(IVA)-CTX(DCR); \ | ||
290 | ;; \ | ||
291 | mov cr.dcr = r16; \ | ||
292 | dv_serialize_data; \ | ||
293 | ;; \ | ||
294 | ld8 r16 = [r2],CTX(PTA)-CTX(IVA); \ | ||
295 | ;; \ | ||
296 | mov cr.iva = r16; \ | ||
297 | dv_serialize_data; \ | ||
298 | ;; \ | ||
299 | ld8 r16 = [r2]; \ | ||
300 | ;; \ | ||
301 | mov cr.pta = r16; \ | ||
302 | dv_serialize_data; \ | ||
303 | ;; | ||
304 | |||
305 | |||
306 | /* | ||
307 | * r32: context_t base address | ||
308 | */ | ||
309 | #define SAVE_REGION_REGS \ | ||
310 | add r2=CTX(RR0),r32; \ | ||
311 | mov r16=rr[r0]; \ | ||
312 | dep.z r18=1,61,3; \ | ||
313 | ;; \ | ||
314 | st8 [r2]=r16,8; \ | ||
315 | mov r17=rr[r18]; \ | ||
316 | dep.z r18=2,61,3; \ | ||
317 | ;; \ | ||
318 | st8 [r2]=r17,8; \ | ||
319 | mov r16=rr[r18]; \ | ||
320 | dep.z r18=3,61,3; \ | ||
321 | ;; \ | ||
322 | st8 [r2]=r16,8; \ | ||
323 | mov r17=rr[r18]; \ | ||
324 | dep.z r18=4,61,3; \ | ||
325 | ;; \ | ||
326 | st8 [r2]=r17,8; \ | ||
327 | mov r16=rr[r18]; \ | ||
328 | dep.z r18=5,61,3; \ | ||
329 | ;; \ | ||
330 | st8 [r2]=r16,8; \ | ||
331 | mov r17=rr[r18]; \ | ||
332 | dep.z r18=7,61,3; \ | ||
333 | ;; \ | ||
334 | st8 [r2]=r17,16; \ | ||
335 | mov r16=rr[r18]; \ | ||
336 | ;; \ | ||
337 | st8 [r2]=r16,8; \ | ||
338 | ;; | ||
339 | |||
340 | /* | ||
341 | * r33:context_t base address | ||
342 | */ | ||
343 | #define RESTORE_REGION_REGS \ | ||
344 | add r2=CTX(RR0),r33;\ | ||
345 | mov r18=r0; \ | ||
346 | ;; \ | ||
347 | ld8 r20=[r2],8; \ | ||
348 | ;; /* rr0 */ \ | ||
349 | ld8 r21=[r2],8; \ | ||
350 | ;; /* rr1 */ \ | ||
351 | ld8 r22=[r2],8; \ | ||
352 | ;; /* rr2 */ \ | ||
353 | ld8 r23=[r2],8; \ | ||
354 | ;; /* rr3 */ \ | ||
355 | ld8 r24=[r2],8; \ | ||
356 | ;; /* rr4 */ \ | ||
357 | ld8 r25=[r2],16; \ | ||
358 | ;; /* rr5 */ \ | ||
359 | ld8 r27=[r2]; \ | ||
360 | ;; /* rr7 */ \ | ||
361 | mov rr[r18]=r20; \ | ||
362 | dep.z r18=1,61,3; \ | ||
363 | ;; /* rr1 */ \ | ||
364 | mov rr[r18]=r21; \ | ||
365 | dep.z r18=2,61,3; \ | ||
366 | ;; /* rr2 */ \ | ||
367 | mov rr[r18]=r22; \ | ||
368 | dep.z r18=3,61,3; \ | ||
369 | ;; /* rr3 */ \ | ||
370 | mov rr[r18]=r23; \ | ||
371 | dep.z r18=4,61,3; \ | ||
372 | ;; /* rr4 */ \ | ||
373 | mov rr[r18]=r24; \ | ||
374 | dep.z r18=5,61,3; \ | ||
375 | ;; /* rr5 */ \ | ||
376 | mov rr[r18]=r25; \ | ||
377 | dep.z r18=7,61,3; \ | ||
378 | ;; /* rr7 */ \ | ||
379 | mov rr[r18]=r27; \ | ||
380 | ;; \ | ||
381 | srlz.i; \ | ||
382 | ;; | ||
383 | |||
384 | |||
385 | |||
386 | /* | ||
387 | * r32: context_t base address | ||
388 | * r36~r39:scratch registers | ||
389 | */ | ||
390 | #define SAVE_DEBUG_REGS \ | ||
391 | add r2=CTX(IBR0),r32; \ | ||
392 | add r3=CTX(DBR0),r32; \ | ||
393 | mov r16=ibr[r0]; \ | ||
394 | mov r17=dbr[r0]; \ | ||
395 | ;; \ | ||
396 | st8 [r2]=r16,8; \ | ||
397 | st8 [r3]=r17,8; \ | ||
398 | add r18=1,r0; \ | ||
399 | ;; \ | ||
400 | mov r16=ibr[r18]; \ | ||
401 | mov r17=dbr[r18]; \ | ||
402 | ;; \ | ||
403 | st8 [r2]=r16,8; \ | ||
404 | st8 [r3]=r17,8; \ | ||
405 | add r18=2,r0; \ | ||
406 | ;; \ | ||
407 | mov r16=ibr[r18]; \ | ||
408 | mov r17=dbr[r18]; \ | ||
409 | ;; \ | ||
410 | st8 [r2]=r16,8; \ | ||
411 | st8 [r3]=r17,8; \ | ||
412 | add r18=2,r0; \ | ||
413 | ;; \ | ||
414 | mov r16=ibr[r18]; \ | ||
415 | mov r17=dbr[r18]; \ | ||
416 | ;; \ | ||
417 | st8 [r2]=r16,8; \ | ||
418 | st8 [r3]=r17,8; \ | ||
419 | add r18=3,r0; \ | ||
420 | ;; \ | ||
421 | mov r16=ibr[r18]; \ | ||
422 | mov r17=dbr[r18]; \ | ||
423 | ;; \ | ||
424 | st8 [r2]=r16,8; \ | ||
425 | st8 [r3]=r17,8; \ | ||
426 | add r18=4,r0; \ | ||
427 | ;; \ | ||
428 | mov r16=ibr[r18]; \ | ||
429 | mov r17=dbr[r18]; \ | ||
430 | ;; \ | ||
431 | st8 [r2]=r16,8; \ | ||
432 | st8 [r3]=r17,8; \ | ||
433 | add r18=5,r0; \ | ||
434 | ;; \ | ||
435 | mov r16=ibr[r18]; \ | ||
436 | mov r17=dbr[r18]; \ | ||
437 | ;; \ | ||
438 | st8 [r2]=r16,8; \ | ||
439 | st8 [r3]=r17,8; \ | ||
440 | add r18=6,r0; \ | ||
441 | ;; \ | ||
442 | mov r16=ibr[r18]; \ | ||
443 | mov r17=dbr[r18]; \ | ||
444 | ;; \ | ||
445 | st8 [r2]=r16,8; \ | ||
446 | st8 [r3]=r17,8; \ | ||
447 | add r18=7,r0; \ | ||
448 | ;; \ | ||
449 | mov r16=ibr[r18]; \ | ||
450 | mov r17=dbr[r18]; \ | ||
451 | ;; \ | ||
452 | st8 [r2]=r16,8; \ | ||
453 | st8 [r3]=r17,8; \ | ||
454 | ;; | ||
455 | |||
456 | |||
457 | /* | ||
458 | * r33: point to context_t structure | ||
459 | * ar.lc are corrupted. | ||
460 | */ | ||
461 | #define RESTORE_DEBUG_REGS \ | ||
462 | add r2=CTX(IBR0),r33; \ | ||
463 | add r3=CTX(DBR0),r33; \ | ||
464 | mov r16=7; \ | ||
465 | mov r17=r0; \ | ||
466 | ;; \ | ||
467 | mov ar.lc = r16; \ | ||
468 | ;; \ | ||
469 | 1: \ | ||
470 | ld8 r18=[r2],8; \ | ||
471 | ld8 r19=[r3],8; \ | ||
472 | ;; \ | ||
473 | mov ibr[r17]=r18; \ | ||
474 | mov dbr[r17]=r19; \ | ||
475 | ;; \ | ||
476 | srlz.i; \ | ||
477 | ;; \ | ||
478 | add r17=1,r17; \ | ||
479 | br.cloop.sptk 1b; \ | ||
480 | ;; | ||
481 | |||
482 | |||
483 | /* | ||
484 | * r32: context_t base address | ||
485 | */ | ||
486 | #define SAVE_FPU_LOW \ | ||
487 | add r2=CTX(F2),r32; \ | ||
488 | add r3=CTX(F3),r32; \ | ||
489 | ;; \ | ||
490 | stf.spill.nta [r2]=f2,32; \ | ||
491 | stf.spill.nta [r3]=f3,32; \ | ||
492 | ;; \ | ||
493 | stf.spill.nta [r2]=f4,32; \ | ||
494 | stf.spill.nta [r3]=f5,32; \ | ||
495 | ;; \ | ||
496 | stf.spill.nta [r2]=f6,32; \ | ||
497 | stf.spill.nta [r3]=f7,32; \ | ||
498 | ;; \ | ||
499 | stf.spill.nta [r2]=f8,32; \ | ||
500 | stf.spill.nta [r3]=f9,32; \ | ||
501 | ;; \ | ||
502 | stf.spill.nta [r2]=f10,32; \ | ||
503 | stf.spill.nta [r3]=f11,32; \ | ||
504 | ;; \ | ||
505 | stf.spill.nta [r2]=f12,32; \ | ||
506 | stf.spill.nta [r3]=f13,32; \ | ||
507 | ;; \ | ||
508 | stf.spill.nta [r2]=f14,32; \ | ||
509 | stf.spill.nta [r3]=f15,32; \ | ||
510 | ;; \ | ||
511 | stf.spill.nta [r2]=f16,32; \ | ||
512 | stf.spill.nta [r3]=f17,32; \ | ||
513 | ;; \ | ||
514 | stf.spill.nta [r2]=f18,32; \ | ||
515 | stf.spill.nta [r3]=f19,32; \ | ||
516 | ;; \ | ||
517 | stf.spill.nta [r2]=f20,32; \ | ||
518 | stf.spill.nta [r3]=f21,32; \ | ||
519 | ;; \ | ||
520 | stf.spill.nta [r2]=f22,32; \ | ||
521 | stf.spill.nta [r3]=f23,32; \ | ||
522 | ;; \ | ||
523 | stf.spill.nta [r2]=f24,32; \ | ||
524 | stf.spill.nta [r3]=f25,32; \ | ||
525 | ;; \ | ||
526 | stf.spill.nta [r2]=f26,32; \ | ||
527 | stf.spill.nta [r3]=f27,32; \ | ||
528 | ;; \ | ||
529 | stf.spill.nta [r2]=f28,32; \ | ||
530 | stf.spill.nta [r3]=f29,32; \ | ||
531 | ;; \ | ||
532 | stf.spill.nta [r2]=f30; \ | ||
533 | stf.spill.nta [r3]=f31; \ | ||
534 | ;; | ||
535 | |||
536 | /* | ||
537 | * r32: context_t base address | ||
538 | */ | ||
539 | #define SAVE_FPU_HIGH \ | ||
540 | add r2=CTX(F32),r32; \ | ||
541 | add r3=CTX(F33),r32; \ | ||
542 | ;; \ | ||
543 | stf.spill.nta [r2]=f32,32; \ | ||
544 | stf.spill.nta [r3]=f33,32; \ | ||
545 | ;; \ | ||
546 | stf.spill.nta [r2]=f34,32; \ | ||
547 | stf.spill.nta [r3]=f35,32; \ | ||
548 | ;; \ | ||
549 | stf.spill.nta [r2]=f36,32; \ | ||
550 | stf.spill.nta [r3]=f37,32; \ | ||
551 | ;; \ | ||
552 | stf.spill.nta [r2]=f38,32; \ | ||
553 | stf.spill.nta [r3]=f39,32; \ | ||
554 | ;; \ | ||
555 | stf.spill.nta [r2]=f40,32; \ | ||
556 | stf.spill.nta [r3]=f41,32; \ | ||
557 | ;; \ | ||
558 | stf.spill.nta [r2]=f42,32; \ | ||
559 | stf.spill.nta [r3]=f43,32; \ | ||
560 | ;; \ | ||
561 | stf.spill.nta [r2]=f44,32; \ | ||
562 | stf.spill.nta [r3]=f45,32; \ | ||
563 | ;; \ | ||
564 | stf.spill.nta [r2]=f46,32; \ | ||
565 | stf.spill.nta [r3]=f47,32; \ | ||
566 | ;; \ | ||
567 | stf.spill.nta [r2]=f48,32; \ | ||
568 | stf.spill.nta [r3]=f49,32; \ | ||
569 | ;; \ | ||
570 | stf.spill.nta [r2]=f50,32; \ | ||
571 | stf.spill.nta [r3]=f51,32; \ | ||
572 | ;; \ | ||
573 | stf.spill.nta [r2]=f52,32; \ | ||
574 | stf.spill.nta [r3]=f53,32; \ | ||
575 | ;; \ | ||
576 | stf.spill.nta [r2]=f54,32; \ | ||
577 | stf.spill.nta [r3]=f55,32; \ | ||
578 | ;; \ | ||
579 | stf.spill.nta [r2]=f56,32; \ | ||
580 | stf.spill.nta [r3]=f57,32; \ | ||
581 | ;; \ | ||
582 | stf.spill.nta [r2]=f58,32; \ | ||
583 | stf.spill.nta [r3]=f59,32; \ | ||
584 | ;; \ | ||
585 | stf.spill.nta [r2]=f60,32; \ | ||
586 | stf.spill.nta [r3]=f61,32; \ | ||
587 | ;; \ | ||
588 | stf.spill.nta [r2]=f62,32; \ | ||
589 | stf.spill.nta [r3]=f63,32; \ | ||
590 | ;; \ | ||
591 | stf.spill.nta [r2]=f64,32; \ | ||
592 | stf.spill.nta [r3]=f65,32; \ | ||
593 | ;; \ | ||
594 | stf.spill.nta [r2]=f66,32; \ | ||
595 | stf.spill.nta [r3]=f67,32; \ | ||
596 | ;; \ | ||
597 | stf.spill.nta [r2]=f68,32; \ | ||
598 | stf.spill.nta [r3]=f69,32; \ | ||
599 | ;; \ | ||
600 | stf.spill.nta [r2]=f70,32; \ | ||
601 | stf.spill.nta [r3]=f71,32; \ | ||
602 | ;; \ | ||
603 | stf.spill.nta [r2]=f72,32; \ | ||
604 | stf.spill.nta [r3]=f73,32; \ | ||
605 | ;; \ | ||
606 | stf.spill.nta [r2]=f74,32; \ | ||
607 | stf.spill.nta [r3]=f75,32; \ | ||
608 | ;; \ | ||
609 | stf.spill.nta [r2]=f76,32; \ | ||
610 | stf.spill.nta [r3]=f77,32; \ | ||
611 | ;; \ | ||
612 | stf.spill.nta [r2]=f78,32; \ | ||
613 | stf.spill.nta [r3]=f79,32; \ | ||
614 | ;; \ | ||
615 | stf.spill.nta [r2]=f80,32; \ | ||
616 | stf.spill.nta [r3]=f81,32; \ | ||
617 | ;; \ | ||
618 | stf.spill.nta [r2]=f82,32; \ | ||
619 | stf.spill.nta [r3]=f83,32; \ | ||
620 | ;; \ | ||
621 | stf.spill.nta [r2]=f84,32; \ | ||
622 | stf.spill.nta [r3]=f85,32; \ | ||
623 | ;; \ | ||
624 | stf.spill.nta [r2]=f86,32; \ | ||
625 | stf.spill.nta [r3]=f87,32; \ | ||
626 | ;; \ | ||
627 | stf.spill.nta [r2]=f88,32; \ | ||
628 | stf.spill.nta [r3]=f89,32; \ | ||
629 | ;; \ | ||
630 | stf.spill.nta [r2]=f90,32; \ | ||
631 | stf.spill.nta [r3]=f91,32; \ | ||
632 | ;; \ | ||
633 | stf.spill.nta [r2]=f92,32; \ | ||
634 | stf.spill.nta [r3]=f93,32; \ | ||
635 | ;; \ | ||
636 | stf.spill.nta [r2]=f94,32; \ | ||
637 | stf.spill.nta [r3]=f95,32; \ | ||
638 | ;; \ | ||
639 | stf.spill.nta [r2]=f96,32; \ | ||
640 | stf.spill.nta [r3]=f97,32; \ | ||
641 | ;; \ | ||
642 | stf.spill.nta [r2]=f98,32; \ | ||
643 | stf.spill.nta [r3]=f99,32; \ | ||
644 | ;; \ | ||
645 | stf.spill.nta [r2]=f100,32; \ | ||
646 | stf.spill.nta [r3]=f101,32; \ | ||
647 | ;; \ | ||
648 | stf.spill.nta [r2]=f102,32; \ | ||
649 | stf.spill.nta [r3]=f103,32; \ | ||
650 | ;; \ | ||
651 | stf.spill.nta [r2]=f104,32; \ | ||
652 | stf.spill.nta [r3]=f105,32; \ | ||
653 | ;; \ | ||
654 | stf.spill.nta [r2]=f106,32; \ | ||
655 | stf.spill.nta [r3]=f107,32; \ | ||
656 | ;; \ | ||
657 | stf.spill.nta [r2]=f108,32; \ | ||
658 | stf.spill.nta [r3]=f109,32; \ | ||
659 | ;; \ | ||
660 | stf.spill.nta [r2]=f110,32; \ | ||
661 | stf.spill.nta [r3]=f111,32; \ | ||
662 | ;; \ | ||
663 | stf.spill.nta [r2]=f112,32; \ | ||
664 | stf.spill.nta [r3]=f113,32; \ | ||
665 | ;; \ | ||
666 | stf.spill.nta [r2]=f114,32; \ | ||
667 | stf.spill.nta [r3]=f115,32; \ | ||
668 | ;; \ | ||
669 | stf.spill.nta [r2]=f116,32; \ | ||
670 | stf.spill.nta [r3]=f117,32; \ | ||
671 | ;; \ | ||
672 | stf.spill.nta [r2]=f118,32; \ | ||
673 | stf.spill.nta [r3]=f119,32; \ | ||
674 | ;; \ | ||
675 | stf.spill.nta [r2]=f120,32; \ | ||
676 | stf.spill.nta [r3]=f121,32; \ | ||
677 | ;; \ | ||
678 | stf.spill.nta [r2]=f122,32; \ | ||
679 | stf.spill.nta [r3]=f123,32; \ | ||
680 | ;; \ | ||
681 | stf.spill.nta [r2]=f124,32; \ | ||
682 | stf.spill.nta [r3]=f125,32; \ | ||
683 | ;; \ | ||
684 | stf.spill.nta [r2]=f126; \ | ||
685 | stf.spill.nta [r3]=f127; \ | ||
686 | ;; | ||
687 | |||
688 | /* | ||
689 | * r33: point to context_t structure | ||
690 | */ | ||
691 | #define RESTORE_FPU_LOW \ | ||
692 | add r2 = CTX(F2), r33; \ | ||
693 | add r3 = CTX(F3), r33; \ | ||
694 | ;; \ | ||
695 | ldf.fill.nta f2 = [r2], 32; \ | ||
696 | ldf.fill.nta f3 = [r3], 32; \ | ||
697 | ;; \ | ||
698 | ldf.fill.nta f4 = [r2], 32; \ | ||
699 | ldf.fill.nta f5 = [r3], 32; \ | ||
700 | ;; \ | ||
701 | ldf.fill.nta f6 = [r2], 32; \ | ||
702 | ldf.fill.nta f7 = [r3], 32; \ | ||
703 | ;; \ | ||
704 | ldf.fill.nta f8 = [r2], 32; \ | ||
705 | ldf.fill.nta f9 = [r3], 32; \ | ||
706 | ;; \ | ||
707 | ldf.fill.nta f10 = [r2], 32; \ | ||
708 | ldf.fill.nta f11 = [r3], 32; \ | ||
709 | ;; \ | ||
710 | ldf.fill.nta f12 = [r2], 32; \ | ||
711 | ldf.fill.nta f13 = [r3], 32; \ | ||
712 | ;; \ | ||
713 | ldf.fill.nta f14 = [r2], 32; \ | ||
714 | ldf.fill.nta f15 = [r3], 32; \ | ||
715 | ;; \ | ||
716 | ldf.fill.nta f16 = [r2], 32; \ | ||
717 | ldf.fill.nta f17 = [r3], 32; \ | ||
718 | ;; \ | ||
719 | ldf.fill.nta f18 = [r2], 32; \ | ||
720 | ldf.fill.nta f19 = [r3], 32; \ | ||
721 | ;; \ | ||
722 | ldf.fill.nta f20 = [r2], 32; \ | ||
723 | ldf.fill.nta f21 = [r3], 32; \ | ||
724 | ;; \ | ||
725 | ldf.fill.nta f22 = [r2], 32; \ | ||
726 | ldf.fill.nta f23 = [r3], 32; \ | ||
727 | ;; \ | ||
728 | ldf.fill.nta f24 = [r2], 32; \ | ||
729 | ldf.fill.nta f25 = [r3], 32; \ | ||
730 | ;; \ | ||
731 | ldf.fill.nta f26 = [r2], 32; \ | ||
732 | ldf.fill.nta f27 = [r3], 32; \ | ||
733 | ;; \ | ||
734 | ldf.fill.nta f28 = [r2], 32; \ | ||
735 | ldf.fill.nta f29 = [r3], 32; \ | ||
736 | ;; \ | ||
737 | ldf.fill.nta f30 = [r2], 32; \ | ||
738 | ldf.fill.nta f31 = [r3], 32; \ | ||
739 | ;; | ||
740 | |||
741 | |||
742 | |||
743 | /* | ||
744 | * r33: point to context_t structure | ||
745 | */ | ||
746 | #define RESTORE_FPU_HIGH \ | ||
747 | add r2 = CTX(F32), r33; \ | ||
748 | add r3 = CTX(F33), r33; \ | ||
749 | ;; \ | ||
750 | ldf.fill.nta f32 = [r2], 32; \ | ||
751 | ldf.fill.nta f33 = [r3], 32; \ | ||
752 | ;; \ | ||
753 | ldf.fill.nta f34 = [r2], 32; \ | ||
754 | ldf.fill.nta f35 = [r3], 32; \ | ||
755 | ;; \ | ||
756 | ldf.fill.nta f36 = [r2], 32; \ | ||
757 | ldf.fill.nta f37 = [r3], 32; \ | ||
758 | ;; \ | ||
759 | ldf.fill.nta f38 = [r2], 32; \ | ||
760 | ldf.fill.nta f39 = [r3], 32; \ | ||
761 | ;; \ | ||
762 | ldf.fill.nta f40 = [r2], 32; \ | ||
763 | ldf.fill.nta f41 = [r3], 32; \ | ||
764 | ;; \ | ||
765 | ldf.fill.nta f42 = [r2], 32; \ | ||
766 | ldf.fill.nta f43 = [r3], 32; \ | ||
767 | ;; \ | ||
768 | ldf.fill.nta f44 = [r2], 32; \ | ||
769 | ldf.fill.nta f45 = [r3], 32; \ | ||
770 | ;; \ | ||
771 | ldf.fill.nta f46 = [r2], 32; \ | ||
772 | ldf.fill.nta f47 = [r3], 32; \ | ||
773 | ;; \ | ||
774 | ldf.fill.nta f48 = [r2], 32; \ | ||
775 | ldf.fill.nta f49 = [r3], 32; \ | ||
776 | ;; \ | ||
777 | ldf.fill.nta f50 = [r2], 32; \ | ||
778 | ldf.fill.nta f51 = [r3], 32; \ | ||
779 | ;; \ | ||
780 | ldf.fill.nta f52 = [r2], 32; \ | ||
781 | ldf.fill.nta f53 = [r3], 32; \ | ||
782 | ;; \ | ||
783 | ldf.fill.nta f54 = [r2], 32; \ | ||
784 | ldf.fill.nta f55 = [r3], 32; \ | ||
785 | ;; \ | ||
786 | ldf.fill.nta f56 = [r2], 32; \ | ||
787 | ldf.fill.nta f57 = [r3], 32; \ | ||
788 | ;; \ | ||
789 | ldf.fill.nta f58 = [r2], 32; \ | ||
790 | ldf.fill.nta f59 = [r3], 32; \ | ||
791 | ;; \ | ||
792 | ldf.fill.nta f60 = [r2], 32; \ | ||
793 | ldf.fill.nta f61 = [r3], 32; \ | ||
794 | ;; \ | ||
795 | ldf.fill.nta f62 = [r2], 32; \ | ||
796 | ldf.fill.nta f63 = [r3], 32; \ | ||
797 | ;; \ | ||
798 | ldf.fill.nta f64 = [r2], 32; \ | ||
799 | ldf.fill.nta f65 = [r3], 32; \ | ||
800 | ;; \ | ||
801 | ldf.fill.nta f66 = [r2], 32; \ | ||
802 | ldf.fill.nta f67 = [r3], 32; \ | ||
803 | ;; \ | ||
804 | ldf.fill.nta f68 = [r2], 32; \ | ||
805 | ldf.fill.nta f69 = [r3], 32; \ | ||
806 | ;; \ | ||
807 | ldf.fill.nta f70 = [r2], 32; \ | ||
808 | ldf.fill.nta f71 = [r3], 32; \ | ||
809 | ;; \ | ||
810 | ldf.fill.nta f72 = [r2], 32; \ | ||
811 | ldf.fill.nta f73 = [r3], 32; \ | ||
812 | ;; \ | ||
813 | ldf.fill.nta f74 = [r2], 32; \ | ||
814 | ldf.fill.nta f75 = [r3], 32; \ | ||
815 | ;; \ | ||
816 | ldf.fill.nta f76 = [r2], 32; \ | ||
817 | ldf.fill.nta f77 = [r3], 32; \ | ||
818 | ;; \ | ||
819 | ldf.fill.nta f78 = [r2], 32; \ | ||
820 | ldf.fill.nta f79 = [r3], 32; \ | ||
821 | ;; \ | ||
822 | ldf.fill.nta f80 = [r2], 32; \ | ||
823 | ldf.fill.nta f81 = [r3], 32; \ | ||
824 | ;; \ | ||
825 | ldf.fill.nta f82 = [r2], 32; \ | ||
826 | ldf.fill.nta f83 = [r3], 32; \ | ||
827 | ;; \ | ||
828 | ldf.fill.nta f84 = [r2], 32; \ | ||
829 | ldf.fill.nta f85 = [r3], 32; \ | ||
830 | ;; \ | ||
831 | ldf.fill.nta f86 = [r2], 32; \ | ||
832 | ldf.fill.nta f87 = [r3], 32; \ | ||
833 | ;; \ | ||
834 | ldf.fill.nta f88 = [r2], 32; \ | ||
835 | ldf.fill.nta f89 = [r3], 32; \ | ||
836 | ;; \ | ||
837 | ldf.fill.nta f90 = [r2], 32; \ | ||
838 | ldf.fill.nta f91 = [r3], 32; \ | ||
839 | ;; \ | ||
840 | ldf.fill.nta f92 = [r2], 32; \ | ||
841 | ldf.fill.nta f93 = [r3], 32; \ | ||
842 | ;; \ | ||
843 | ldf.fill.nta f94 = [r2], 32; \ | ||
844 | ldf.fill.nta f95 = [r3], 32; \ | ||
845 | ;; \ | ||
846 | ldf.fill.nta f96 = [r2], 32; \ | ||
847 | ldf.fill.nta f97 = [r3], 32; \ | ||
848 | ;; \ | ||
849 | ldf.fill.nta f98 = [r2], 32; \ | ||
850 | ldf.fill.nta f99 = [r3], 32; \ | ||
851 | ;; \ | ||
852 | ldf.fill.nta f100 = [r2], 32; \ | ||
853 | ldf.fill.nta f101 = [r3], 32; \ | ||
854 | ;; \ | ||
855 | ldf.fill.nta f102 = [r2], 32; \ | ||
856 | ldf.fill.nta f103 = [r3], 32; \ | ||
857 | ;; \ | ||
858 | ldf.fill.nta f104 = [r2], 32; \ | ||
859 | ldf.fill.nta f105 = [r3], 32; \ | ||
860 | ;; \ | ||
861 | ldf.fill.nta f106 = [r2], 32; \ | ||
862 | ldf.fill.nta f107 = [r3], 32; \ | ||
863 | ;; \ | ||
864 | ldf.fill.nta f108 = [r2], 32; \ | ||
865 | ldf.fill.nta f109 = [r3], 32; \ | ||
866 | ;; \ | ||
867 | ldf.fill.nta f110 = [r2], 32; \ | ||
868 | ldf.fill.nta f111 = [r3], 32; \ | ||
869 | ;; \ | ||
870 | ldf.fill.nta f112 = [r2], 32; \ | ||
871 | ldf.fill.nta f113 = [r3], 32; \ | ||
872 | ;; \ | ||
873 | ldf.fill.nta f114 = [r2], 32; \ | ||
874 | ldf.fill.nta f115 = [r3], 32; \ | ||
875 | ;; \ | ||
876 | ldf.fill.nta f116 = [r2], 32; \ | ||
877 | ldf.fill.nta f117 = [r3], 32; \ | ||
878 | ;; \ | ||
879 | ldf.fill.nta f118 = [r2], 32; \ | ||
880 | ldf.fill.nta f119 = [r3], 32; \ | ||
881 | ;; \ | ||
882 | ldf.fill.nta f120 = [r2], 32; \ | ||
883 | ldf.fill.nta f121 = [r3], 32; \ | ||
884 | ;; \ | ||
885 | ldf.fill.nta f122 = [r2], 32; \ | ||
886 | ldf.fill.nta f123 = [r3], 32; \ | ||
887 | ;; \ | ||
888 | ldf.fill.nta f124 = [r2], 32; \ | ||
889 | ldf.fill.nta f125 = [r3], 32; \ | ||
890 | ;; \ | ||
891 | ldf.fill.nta f126 = [r2], 32; \ | ||
892 | ldf.fill.nta f127 = [r3], 32; \ | ||
893 | ;; | ||
894 | |||
895 | /* | ||
896 | * r32: context_t base address | ||
897 | */ | ||
898 | #define SAVE_PTK_REGS \ | ||
899 | add r2=CTX(PKR0), r32; \ | ||
900 | mov r16=7; \ | ||
901 | ;; \ | ||
902 | mov ar.lc=r16; \ | ||
903 | mov r17=r0; \ | ||
904 | ;; \ | ||
905 | 1: \ | ||
906 | mov r18=pkr[r17]; \ | ||
907 | ;; \ | ||
908 | srlz.i; \ | ||
909 | ;; \ | ||
910 | st8 [r2]=r18, 8; \ | ||
911 | ;; \ | ||
912 | add r17 =1,r17; \ | ||
913 | ;; \ | ||
914 | br.cloop.sptk 1b; \ | ||
915 | ;; | ||
916 | |||
917 | /* | ||
918 | * r33: point to context_t structure | ||
919 | * ar.lc are corrupted. | ||
920 | */ | ||
921 | #define RESTORE_PTK_REGS \ | ||
922 | add r2=CTX(PKR0), r33; \ | ||
923 | mov r16=7; \ | ||
924 | ;; \ | ||
925 | mov ar.lc=r16; \ | ||
926 | mov r17=r0; \ | ||
927 | ;; \ | ||
928 | 1: \ | ||
929 | ld8 r18=[r2], 8; \ | ||
930 | ;; \ | ||
931 | mov pkr[r17]=r18; \ | ||
932 | ;; \ | ||
933 | srlz.i; \ | ||
934 | ;; \ | ||
935 | add r17 =1,r17; \ | ||
936 | ;; \ | ||
937 | br.cloop.sptk 1b; \ | ||
938 | ;; | ||
939 | |||
940 | |||
941 | /* | ||
942 | * void vmm_trampoline( context_t * from, | ||
943 | * context_t * to) | ||
944 | * | ||
945 | * from: r32 | ||
946 | * to: r33 | ||
947 | * note: interrupt disabled before call this function. | ||
948 | */ | ||
949 | GLOBAL_ENTRY(vmm_trampoline) | ||
950 | mov r16 = psr | ||
951 | adds r2 = CTX(PSR), r32 | ||
952 | ;; | ||
953 | st8 [r2] = r16, 8 // psr | ||
954 | mov r17 = pr | ||
955 | ;; | ||
956 | st8 [r2] = r17, 8 // pr | ||
957 | mov r18 = ar.unat | ||
958 | ;; | ||
959 | st8 [r2] = r18 | ||
960 | mov r17 = ar.rsc | ||
961 | ;; | ||
962 | adds r2 = CTX(RSC),r32 | ||
963 | ;; | ||
964 | st8 [r2]= r17 | ||
965 | mov ar.rsc =0 | ||
966 | flushrs | ||
967 | ;; | ||
968 | SAVE_GENERAL_REGS | ||
969 | ;; | ||
970 | SAVE_KERNEL_REGS | ||
971 | ;; | ||
972 | SAVE_APP_REGS | ||
973 | ;; | ||
974 | SAVE_BRANCH_REGS | ||
975 | ;; | ||
976 | SAVE_CTL_REGS | ||
977 | ;; | ||
978 | SAVE_REGION_REGS | ||
979 | ;; | ||
980 | //SAVE_DEBUG_REGS | ||
981 | ;; | ||
982 | rsm psr.dfl | ||
983 | ;; | ||
984 | srlz.d | ||
985 | ;; | ||
986 | SAVE_FPU_LOW | ||
987 | ;; | ||
988 | rsm psr.dfh | ||
989 | ;; | ||
990 | srlz.d | ||
991 | ;; | ||
992 | SAVE_FPU_HIGH | ||
993 | ;; | ||
994 | SAVE_PTK_REGS | ||
995 | ;; | ||
996 | RESTORE_PTK_REGS | ||
997 | ;; | ||
998 | RESTORE_FPU_HIGH | ||
999 | ;; | ||
1000 | RESTORE_FPU_LOW | ||
1001 | ;; | ||
1002 | //RESTORE_DEBUG_REGS | ||
1003 | ;; | ||
1004 | RESTORE_REGION_REGS | ||
1005 | ;; | ||
1006 | RESTORE_CTL_REGS | ||
1007 | ;; | ||
1008 | RESTORE_BRANCH_REGS | ||
1009 | ;; | ||
1010 | RESTORE_APP_REGS | ||
1011 | ;; | ||
1012 | RESTORE_KERNEL_REGS | ||
1013 | ;; | ||
1014 | RESTORE_GENERAL_REGS | ||
1015 | ;; | ||
1016 | adds r2=CTX(PSR), r33 | ||
1017 | ;; | ||
1018 | ld8 r16=[r2], 8 // psr | ||
1019 | ;; | ||
1020 | mov psr.l=r16 | ||
1021 | ;; | ||
1022 | srlz.d | ||
1023 | ;; | ||
1024 | ld8 r16=[r2], 8 // pr | ||
1025 | ;; | ||
1026 | mov pr =r16,-1 | ||
1027 | ld8 r16=[r2] // unat | ||
1028 | ;; | ||
1029 | mov ar.unat=r16 | ||
1030 | ;; | ||
1031 | adds r2=CTX(RSC),r33 | ||
1032 | ;; | ||
1033 | ld8 r16 =[r2] | ||
1034 | ;; | ||
1035 | mov ar.rsc = r16 | ||
1036 | ;; | ||
1037 | br.ret.sptk.few b0 | ||
1038 | END(vmm_trampoline) | ||
diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c new file mode 100644 index 000000000000..e44027ce5667 --- /dev/null +++ b/arch/ia64/kvm/vcpu.c | |||
@@ -0,0 +1,2163 @@ | |||
1 | /* | ||
2 | * kvm_vcpu.c: handling all virtual cpu related thing. | ||
3 | * Copyright (c) 2005, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Shaofan Li (Susue Li) <susie.li@intel.com> | ||
19 | * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com) | ||
20 | * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) | ||
21 | * Xiantao Zhang <xiantao.zhang@intel.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/kvm_host.h> | ||
25 | #include <linux/types.h> | ||
26 | |||
27 | #include <asm/processor.h> | ||
28 | #include <asm/ia64regs.h> | ||
29 | #include <asm/gcc_intrin.h> | ||
30 | #include <asm/kregs.h> | ||
31 | #include <asm/pgtable.h> | ||
32 | #include <asm/tlb.h> | ||
33 | |||
34 | #include "asm-offsets.h" | ||
35 | #include "vcpu.h" | ||
36 | |||
37 | /* | ||
38 | * Special notes: | ||
39 | * - Index by it/dt/rt sequence | ||
40 | * - Only existing mode transitions are allowed in this table | ||
41 | * - RSE is placed at lazy mode when emulating guest partial mode | ||
42 | * - If gva happens to be rr0 and rr4, only allowed case is identity | ||
43 | * mapping (gva=gpa), or panic! (How?) | ||
44 | */ | ||
45 | int mm_switch_table[8][8] = { | ||
46 | /* 2004/09/12(Kevin): Allow switch to self */ | ||
47 | /* | ||
48 | * (it,dt,rt): (0,0,0) -> (1,1,1) | ||
49 | * This kind of transition usually occurs in the very early | ||
50 | * stage of Linux boot up procedure. Another case is in efi | ||
51 | * and pal calls. (see "arch/ia64/kernel/head.S") | ||
52 | * | ||
53 | * (it,dt,rt): (0,0,0) -> (0,1,1) | ||
54 | * This kind of transition is found when OSYa exits efi boot | ||
55 | * service. Due to gva = gpa in this case (Same region), | ||
56 | * data access can be satisfied though itlb entry for physical | ||
57 | * emulation is hit. | ||
58 | */ | ||
59 | {SW_SELF, 0, 0, SW_NOP, 0, 0, 0, SW_P2V}, | ||
60 | {0, 0, 0, 0, 0, 0, 0, 0}, | ||
61 | {0, 0, 0, 0, 0, 0, 0, 0}, | ||
62 | /* | ||
63 | * (it,dt,rt): (0,1,1) -> (1,1,1) | ||
64 | * This kind of transition is found in OSYa. | ||
65 | * | ||
66 | * (it,dt,rt): (0,1,1) -> (0,0,0) | ||
67 | * This kind of transition is found in OSYa | ||
68 | */ | ||
69 | {SW_NOP, 0, 0, SW_SELF, 0, 0, 0, SW_P2V}, | ||
70 | /* (1,0,0)->(1,1,1) */ | ||
71 | {0, 0, 0, 0, 0, 0, 0, SW_P2V}, | ||
72 | /* | ||
73 | * (it,dt,rt): (1,0,1) -> (1,1,1) | ||
74 | * This kind of transition usually occurs when Linux returns | ||
75 | * from the low level TLB miss handlers. | ||
76 | * (see "arch/ia64/kernel/ivt.S") | ||
77 | */ | ||
78 | {0, 0, 0, 0, 0, SW_SELF, 0, SW_P2V}, | ||
79 | {0, 0, 0, 0, 0, 0, 0, 0}, | ||
80 | /* | ||
81 | * (it,dt,rt): (1,1,1) -> (1,0,1) | ||
82 | * This kind of transition usually occurs in Linux low level | ||
83 | * TLB miss handler. (see "arch/ia64/kernel/ivt.S") | ||
84 | * | ||
85 | * (it,dt,rt): (1,1,1) -> (0,0,0) | ||
86 | * This kind of transition usually occurs in pal and efi calls, | ||
87 | * which requires running in physical mode. | ||
88 | * (see "arch/ia64/kernel/head.S") | ||
89 | * (1,1,1)->(1,0,0) | ||
90 | */ | ||
91 | |||
92 | {SW_V2P, 0, 0, 0, SW_V2P, SW_V2P, 0, SW_SELF}, | ||
93 | }; | ||
94 | |||
95 | void physical_mode_init(struct kvm_vcpu *vcpu) | ||
96 | { | ||
97 | vcpu->arch.mode_flags = GUEST_IN_PHY; | ||
98 | } | ||
99 | |||
100 | void switch_to_physical_rid(struct kvm_vcpu *vcpu) | ||
101 | { | ||
102 | unsigned long psr; | ||
103 | |||
104 | /* Save original virtual mode rr[0] and rr[4] */ | ||
105 | psr = ia64_clear_ic(); | ||
106 | ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_rr0); | ||
107 | ia64_srlz_d(); | ||
108 | ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_rr4); | ||
109 | ia64_srlz_d(); | ||
110 | |||
111 | ia64_set_psr(psr); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | |||
116 | void switch_to_virtual_rid(struct kvm_vcpu *vcpu) | ||
117 | { | ||
118 | unsigned long psr; | ||
119 | |||
120 | psr = ia64_clear_ic(); | ||
121 | ia64_set_rr(VRN0 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0); | ||
122 | ia64_srlz_d(); | ||
123 | ia64_set_rr(VRN4 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4); | ||
124 | ia64_srlz_d(); | ||
125 | ia64_set_psr(psr); | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | static int mm_switch_action(struct ia64_psr opsr, struct ia64_psr npsr) | ||
130 | { | ||
131 | return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)]; | ||
132 | } | ||
133 | |||
134 | void switch_mm_mode(struct kvm_vcpu *vcpu, struct ia64_psr old_psr, | ||
135 | struct ia64_psr new_psr) | ||
136 | { | ||
137 | int act; | ||
138 | act = mm_switch_action(old_psr, new_psr); | ||
139 | switch (act) { | ||
140 | case SW_V2P: | ||
141 | /*printk("V -> P mode transition: (0x%lx -> 0x%lx)\n", | ||
142 | old_psr.val, new_psr.val);*/ | ||
143 | switch_to_physical_rid(vcpu); | ||
144 | /* | ||
145 | * Set rse to enforced lazy, to prevent active rse | ||
146 | *save/restor when guest physical mode. | ||
147 | */ | ||
148 | vcpu->arch.mode_flags |= GUEST_IN_PHY; | ||
149 | break; | ||
150 | case SW_P2V: | ||
151 | switch_to_virtual_rid(vcpu); | ||
152 | /* | ||
153 | * recover old mode which is saved when entering | ||
154 | * guest physical mode | ||
155 | */ | ||
156 | vcpu->arch.mode_flags &= ~GUEST_IN_PHY; | ||
157 | break; | ||
158 | case SW_SELF: | ||
159 | break; | ||
160 | case SW_NOP: | ||
161 | break; | ||
162 | default: | ||
163 | /* Sanity check */ | ||
164 | break; | ||
165 | } | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | |||
170 | |||
171 | /* | ||
172 | * In physical mode, insert tc/tr for region 0 and 4 uses | ||
173 | * RID[0] and RID[4] which is for physical mode emulation. | ||
174 | * However what those inserted tc/tr wants is rid for | ||
175 | * virtual mode. So original virtual rid needs to be restored | ||
176 | * before insert. | ||
177 | * | ||
178 | * Operations which required such switch include: | ||
179 | * - insertions (itc.*, itr.*) | ||
180 | * - purges (ptc.* and ptr.*) | ||
181 | * - tpa | ||
182 | * - tak | ||
183 | * - thash?, ttag? | ||
184 | * All above needs actual virtual rid for destination entry. | ||
185 | */ | ||
186 | |||
187 | void check_mm_mode_switch(struct kvm_vcpu *vcpu, struct ia64_psr old_psr, | ||
188 | struct ia64_psr new_psr) | ||
189 | { | ||
190 | |||
191 | if ((old_psr.dt != new_psr.dt) | ||
192 | || (old_psr.it != new_psr.it) | ||
193 | || (old_psr.rt != new_psr.rt)) | ||
194 | switch_mm_mode(vcpu, old_psr, new_psr); | ||
195 | |||
196 | return; | ||
197 | } | ||
198 | |||
199 | |||
200 | /* | ||
201 | * In physical mode, insert tc/tr for region 0 and 4 uses | ||
202 | * RID[0] and RID[4] which is for physical mode emulation. | ||
203 | * However what those inserted tc/tr wants is rid for | ||
204 | * virtual mode. So original virtual rid needs to be restored | ||
205 | * before insert. | ||
206 | * | ||
207 | * Operations which required such switch include: | ||
208 | * - insertions (itc.*, itr.*) | ||
209 | * - purges (ptc.* and ptr.*) | ||
210 | * - tpa | ||
211 | * - tak | ||
212 | * - thash?, ttag? | ||
213 | * All above needs actual virtual rid for destination entry. | ||
214 | */ | ||
215 | |||
216 | void prepare_if_physical_mode(struct kvm_vcpu *vcpu) | ||
217 | { | ||
218 | if (is_physical_mode(vcpu)) { | ||
219 | vcpu->arch.mode_flags |= GUEST_PHY_EMUL; | ||
220 | switch_to_virtual_rid(vcpu); | ||
221 | } | ||
222 | return; | ||
223 | } | ||
224 | |||
225 | /* Recover always follows prepare */ | ||
226 | void recover_if_physical_mode(struct kvm_vcpu *vcpu) | ||
227 | { | ||
228 | if (is_physical_mode(vcpu)) | ||
229 | switch_to_physical_rid(vcpu); | ||
230 | vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | #define RPT(x) ((u16) &((struct kvm_pt_regs *)0)->x) | ||
235 | |||
236 | static u16 gr_info[32] = { | ||
237 | 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ | ||
238 | RPT(r1), RPT(r2), RPT(r3), | ||
239 | RPT(r4), RPT(r5), RPT(r6), RPT(r7), | ||
240 | RPT(r8), RPT(r9), RPT(r10), RPT(r11), | ||
241 | RPT(r12), RPT(r13), RPT(r14), RPT(r15), | ||
242 | RPT(r16), RPT(r17), RPT(r18), RPT(r19), | ||
243 | RPT(r20), RPT(r21), RPT(r22), RPT(r23), | ||
244 | RPT(r24), RPT(r25), RPT(r26), RPT(r27), | ||
245 | RPT(r28), RPT(r29), RPT(r30), RPT(r31) | ||
246 | }; | ||
247 | |||
248 | #define IA64_FIRST_STACKED_GR 32 | ||
249 | #define IA64_FIRST_ROTATING_FR 32 | ||
250 | |||
251 | static inline unsigned long | ||
252 | rotate_reg(unsigned long sor, unsigned long rrb, unsigned long reg) | ||
253 | { | ||
254 | reg += rrb; | ||
255 | if (reg >= sor) | ||
256 | reg -= sor; | ||
257 | return reg; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Return the (rotated) index for floating point register | ||
262 | * be in the REGNUM (REGNUM must range from 32-127, | ||
263 | * result is in the range from 0-95. | ||
264 | */ | ||
265 | static inline unsigned long fph_index(struct kvm_pt_regs *regs, | ||
266 | long regnum) | ||
267 | { | ||
268 | unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f; | ||
269 | return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR)); | ||
270 | } | ||
271 | |||
272 | |||
273 | /* | ||
274 | * The inverse of the above: given bspstore and the number of | ||
275 | * registers, calculate ar.bsp. | ||
276 | */ | ||
277 | static inline unsigned long *kvm_rse_skip_regs(unsigned long *addr, | ||
278 | long num_regs) | ||
279 | { | ||
280 | long delta = ia64_rse_slot_num(addr) + num_regs; | ||
281 | int i = 0; | ||
282 | |||
283 | if (num_regs < 0) | ||
284 | delta -= 0x3e; | ||
285 | if (delta < 0) { | ||
286 | while (delta <= -0x3f) { | ||
287 | i--; | ||
288 | delta += 0x3f; | ||
289 | } | ||
290 | } else { | ||
291 | while (delta >= 0x3f) { | ||
292 | i++; | ||
293 | delta -= 0x3f; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | return addr + num_regs + i; | ||
298 | } | ||
299 | |||
300 | static void get_rse_reg(struct kvm_pt_regs *regs, unsigned long r1, | ||
301 | unsigned long *val, int *nat) | ||
302 | { | ||
303 | unsigned long *bsp, *addr, *rnat_addr, *bspstore; | ||
304 | unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET; | ||
305 | unsigned long nat_mask; | ||
306 | unsigned long old_rsc, new_rsc; | ||
307 | long sof = (regs->cr_ifs) & 0x7f; | ||
308 | long sor = (((regs->cr_ifs >> 14) & 0xf) << 3); | ||
309 | long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; | ||
310 | long ridx = r1 - 32; | ||
311 | |||
312 | if (ridx < sor) | ||
313 | ridx = rotate_reg(sor, rrb_gr, ridx); | ||
314 | |||
315 | old_rsc = ia64_getreg(_IA64_REG_AR_RSC); | ||
316 | new_rsc = old_rsc&(~(0x3)); | ||
317 | ia64_setreg(_IA64_REG_AR_RSC, new_rsc); | ||
318 | |||
319 | bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE); | ||
320 | bsp = kbs + (regs->loadrs >> 19); | ||
321 | |||
322 | addr = kvm_rse_skip_regs(bsp, -sof + ridx); | ||
323 | nat_mask = 1UL << ia64_rse_slot_num(addr); | ||
324 | rnat_addr = ia64_rse_rnat_addr(addr); | ||
325 | |||
326 | if (addr >= bspstore) { | ||
327 | ia64_flushrs(); | ||
328 | ia64_mf(); | ||
329 | bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE); | ||
330 | } | ||
331 | *val = *addr; | ||
332 | if (nat) { | ||
333 | if (bspstore < rnat_addr) | ||
334 | *nat = (int)!!(ia64_getreg(_IA64_REG_AR_RNAT) | ||
335 | & nat_mask); | ||
336 | else | ||
337 | *nat = (int)!!((*rnat_addr) & nat_mask); | ||
338 | ia64_setreg(_IA64_REG_AR_RSC, old_rsc); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | void set_rse_reg(struct kvm_pt_regs *regs, unsigned long r1, | ||
343 | unsigned long val, unsigned long nat) | ||
344 | { | ||
345 | unsigned long *bsp, *bspstore, *addr, *rnat_addr; | ||
346 | unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET; | ||
347 | unsigned long nat_mask; | ||
348 | unsigned long old_rsc, new_rsc, psr; | ||
349 | unsigned long rnat; | ||
350 | long sof = (regs->cr_ifs) & 0x7f; | ||
351 | long sor = (((regs->cr_ifs >> 14) & 0xf) << 3); | ||
352 | long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; | ||
353 | long ridx = r1 - 32; | ||
354 | |||
355 | if (ridx < sor) | ||
356 | ridx = rotate_reg(sor, rrb_gr, ridx); | ||
357 | |||
358 | old_rsc = ia64_getreg(_IA64_REG_AR_RSC); | ||
359 | /* put RSC to lazy mode, and set loadrs 0 */ | ||
360 | new_rsc = old_rsc & (~0x3fff0003); | ||
361 | ia64_setreg(_IA64_REG_AR_RSC, new_rsc); | ||
362 | bsp = kbs + (regs->loadrs >> 19); /* 16 + 3 */ | ||
363 | |||
364 | addr = kvm_rse_skip_regs(bsp, -sof + ridx); | ||
365 | nat_mask = 1UL << ia64_rse_slot_num(addr); | ||
366 | rnat_addr = ia64_rse_rnat_addr(addr); | ||
367 | |||
368 | local_irq_save(psr); | ||
369 | bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE); | ||
370 | if (addr >= bspstore) { | ||
371 | |||
372 | ia64_flushrs(); | ||
373 | ia64_mf(); | ||
374 | *addr = val; | ||
375 | bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE); | ||
376 | rnat = ia64_getreg(_IA64_REG_AR_RNAT); | ||
377 | if (bspstore < rnat_addr) | ||
378 | rnat = rnat & (~nat_mask); | ||
379 | else | ||
380 | *rnat_addr = (*rnat_addr)&(~nat_mask); | ||
381 | |||
382 | ia64_mf(); | ||
383 | ia64_loadrs(); | ||
384 | ia64_setreg(_IA64_REG_AR_RNAT, rnat); | ||
385 | } else { | ||
386 | rnat = ia64_getreg(_IA64_REG_AR_RNAT); | ||
387 | *addr = val; | ||
388 | if (bspstore < rnat_addr) | ||
389 | rnat = rnat&(~nat_mask); | ||
390 | else | ||
391 | *rnat_addr = (*rnat_addr) & (~nat_mask); | ||
392 | |||
393 | ia64_setreg(_IA64_REG_AR_BSPSTORE, bspstore); | ||
394 | ia64_setreg(_IA64_REG_AR_RNAT, rnat); | ||
395 | } | ||
396 | local_irq_restore(psr); | ||
397 | ia64_setreg(_IA64_REG_AR_RSC, old_rsc); | ||
398 | } | ||
399 | |||
400 | void getreg(unsigned long regnum, unsigned long *val, | ||
401 | int *nat, struct kvm_pt_regs *regs) | ||
402 | { | ||
403 | unsigned long addr, *unat; | ||
404 | if (regnum >= IA64_FIRST_STACKED_GR) { | ||
405 | get_rse_reg(regs, regnum, val, nat); | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Now look at registers in [0-31] range and init correct UNAT | ||
411 | */ | ||
412 | addr = (unsigned long)regs; | ||
413 | unat = ®s->eml_unat;; | ||
414 | |||
415 | addr += gr_info[regnum]; | ||
416 | |||
417 | *val = *(unsigned long *)addr; | ||
418 | /* | ||
419 | * do it only when requested | ||
420 | */ | ||
421 | if (nat) | ||
422 | *nat = (*unat >> ((addr >> 3) & 0x3f)) & 0x1UL; | ||
423 | } | ||
424 | |||
425 | void setreg(unsigned long regnum, unsigned long val, | ||
426 | int nat, struct kvm_pt_regs *regs) | ||
427 | { | ||
428 | unsigned long addr; | ||
429 | unsigned long bitmask; | ||
430 | unsigned long *unat; | ||
431 | |||
432 | /* | ||
433 | * First takes care of stacked registers | ||
434 | */ | ||
435 | if (regnum >= IA64_FIRST_STACKED_GR) { | ||
436 | set_rse_reg(regs, regnum, val, nat); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Now look at registers in [0-31] range and init correct UNAT | ||
442 | */ | ||
443 | addr = (unsigned long)regs; | ||
444 | unat = ®s->eml_unat; | ||
445 | /* | ||
446 | * add offset from base of struct | ||
447 | * and do it ! | ||
448 | */ | ||
449 | addr += gr_info[regnum]; | ||
450 | |||
451 | *(unsigned long *)addr = val; | ||
452 | |||
453 | /* | ||
454 | * We need to clear the corresponding UNAT bit to fully emulate the load | ||
455 | * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 | ||
456 | */ | ||
457 | bitmask = 1UL << ((addr >> 3) & 0x3f); | ||
458 | if (nat) | ||
459 | *unat |= bitmask; | ||
460 | else | ||
461 | *unat &= ~bitmask; | ||
462 | |||
463 | } | ||
464 | |||
465 | u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg) | ||
466 | { | ||
467 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
468 | u64 val; | ||
469 | |||
470 | if (!reg) | ||
471 | return 0; | ||
472 | getreg(reg, &val, 0, regs); | ||
473 | return val; | ||
474 | } | ||
475 | |||
476 | void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 value, int nat) | ||
477 | { | ||
478 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
479 | long sof = (regs->cr_ifs) & 0x7f; | ||
480 | |||
481 | if (!reg) | ||
482 | return; | ||
483 | if (reg >= sof + 32) | ||
484 | return; | ||
485 | setreg(reg, value, nat, regs); /* FIXME: handle NATs later*/ | ||
486 | } | ||
487 | |||
488 | void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, | ||
489 | struct kvm_pt_regs *regs) | ||
490 | { | ||
491 | /* Take floating register rotation into consideration*/ | ||
492 | if (regnum >= IA64_FIRST_ROTATING_FR) | ||
493 | regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum); | ||
494 | #define CASE_FIXED_FP(reg) \ | ||
495 | case (reg) : \ | ||
496 | ia64_stf_spill(fpval, reg); \ | ||
497 | break | ||
498 | |||
499 | switch (regnum) { | ||
500 | CASE_FIXED_FP(0); | ||
501 | CASE_FIXED_FP(1); | ||
502 | CASE_FIXED_FP(2); | ||
503 | CASE_FIXED_FP(3); | ||
504 | CASE_FIXED_FP(4); | ||
505 | CASE_FIXED_FP(5); | ||
506 | |||
507 | CASE_FIXED_FP(6); | ||
508 | CASE_FIXED_FP(7); | ||
509 | CASE_FIXED_FP(8); | ||
510 | CASE_FIXED_FP(9); | ||
511 | CASE_FIXED_FP(10); | ||
512 | CASE_FIXED_FP(11); | ||
513 | |||
514 | CASE_FIXED_FP(12); | ||
515 | CASE_FIXED_FP(13); | ||
516 | CASE_FIXED_FP(14); | ||
517 | CASE_FIXED_FP(15); | ||
518 | CASE_FIXED_FP(16); | ||
519 | CASE_FIXED_FP(17); | ||
520 | CASE_FIXED_FP(18); | ||
521 | CASE_FIXED_FP(19); | ||
522 | CASE_FIXED_FP(20); | ||
523 | CASE_FIXED_FP(21); | ||
524 | CASE_FIXED_FP(22); | ||
525 | CASE_FIXED_FP(23); | ||
526 | CASE_FIXED_FP(24); | ||
527 | CASE_FIXED_FP(25); | ||
528 | CASE_FIXED_FP(26); | ||
529 | CASE_FIXED_FP(27); | ||
530 | CASE_FIXED_FP(28); | ||
531 | CASE_FIXED_FP(29); | ||
532 | CASE_FIXED_FP(30); | ||
533 | CASE_FIXED_FP(31); | ||
534 | CASE_FIXED_FP(32); | ||
535 | CASE_FIXED_FP(33); | ||
536 | CASE_FIXED_FP(34); | ||
537 | CASE_FIXED_FP(35); | ||
538 | CASE_FIXED_FP(36); | ||
539 | CASE_FIXED_FP(37); | ||
540 | CASE_FIXED_FP(38); | ||
541 | CASE_FIXED_FP(39); | ||
542 | CASE_FIXED_FP(40); | ||
543 | CASE_FIXED_FP(41); | ||
544 | CASE_FIXED_FP(42); | ||
545 | CASE_FIXED_FP(43); | ||
546 | CASE_FIXED_FP(44); | ||
547 | CASE_FIXED_FP(45); | ||
548 | CASE_FIXED_FP(46); | ||
549 | CASE_FIXED_FP(47); | ||
550 | CASE_FIXED_FP(48); | ||
551 | CASE_FIXED_FP(49); | ||
552 | CASE_FIXED_FP(50); | ||
553 | CASE_FIXED_FP(51); | ||
554 | CASE_FIXED_FP(52); | ||
555 | CASE_FIXED_FP(53); | ||
556 | CASE_FIXED_FP(54); | ||
557 | CASE_FIXED_FP(55); | ||
558 | CASE_FIXED_FP(56); | ||
559 | CASE_FIXED_FP(57); | ||
560 | CASE_FIXED_FP(58); | ||
561 | CASE_FIXED_FP(59); | ||
562 | CASE_FIXED_FP(60); | ||
563 | CASE_FIXED_FP(61); | ||
564 | CASE_FIXED_FP(62); | ||
565 | CASE_FIXED_FP(63); | ||
566 | CASE_FIXED_FP(64); | ||
567 | CASE_FIXED_FP(65); | ||
568 | CASE_FIXED_FP(66); | ||
569 | CASE_FIXED_FP(67); | ||
570 | CASE_FIXED_FP(68); | ||
571 | CASE_FIXED_FP(69); | ||
572 | CASE_FIXED_FP(70); | ||
573 | CASE_FIXED_FP(71); | ||
574 | CASE_FIXED_FP(72); | ||
575 | CASE_FIXED_FP(73); | ||
576 | CASE_FIXED_FP(74); | ||
577 | CASE_FIXED_FP(75); | ||
578 | CASE_FIXED_FP(76); | ||
579 | CASE_FIXED_FP(77); | ||
580 | CASE_FIXED_FP(78); | ||
581 | CASE_FIXED_FP(79); | ||
582 | CASE_FIXED_FP(80); | ||
583 | CASE_FIXED_FP(81); | ||
584 | CASE_FIXED_FP(82); | ||
585 | CASE_FIXED_FP(83); | ||
586 | CASE_FIXED_FP(84); | ||
587 | CASE_FIXED_FP(85); | ||
588 | CASE_FIXED_FP(86); | ||
589 | CASE_FIXED_FP(87); | ||
590 | CASE_FIXED_FP(88); | ||
591 | CASE_FIXED_FP(89); | ||
592 | CASE_FIXED_FP(90); | ||
593 | CASE_FIXED_FP(91); | ||
594 | CASE_FIXED_FP(92); | ||
595 | CASE_FIXED_FP(93); | ||
596 | CASE_FIXED_FP(94); | ||
597 | CASE_FIXED_FP(95); | ||
598 | CASE_FIXED_FP(96); | ||
599 | CASE_FIXED_FP(97); | ||
600 | CASE_FIXED_FP(98); | ||
601 | CASE_FIXED_FP(99); | ||
602 | CASE_FIXED_FP(100); | ||
603 | CASE_FIXED_FP(101); | ||
604 | CASE_FIXED_FP(102); | ||
605 | CASE_FIXED_FP(103); | ||
606 | CASE_FIXED_FP(104); | ||
607 | CASE_FIXED_FP(105); | ||
608 | CASE_FIXED_FP(106); | ||
609 | CASE_FIXED_FP(107); | ||
610 | CASE_FIXED_FP(108); | ||
611 | CASE_FIXED_FP(109); | ||
612 | CASE_FIXED_FP(110); | ||
613 | CASE_FIXED_FP(111); | ||
614 | CASE_FIXED_FP(112); | ||
615 | CASE_FIXED_FP(113); | ||
616 | CASE_FIXED_FP(114); | ||
617 | CASE_FIXED_FP(115); | ||
618 | CASE_FIXED_FP(116); | ||
619 | CASE_FIXED_FP(117); | ||
620 | CASE_FIXED_FP(118); | ||
621 | CASE_FIXED_FP(119); | ||
622 | CASE_FIXED_FP(120); | ||
623 | CASE_FIXED_FP(121); | ||
624 | CASE_FIXED_FP(122); | ||
625 | CASE_FIXED_FP(123); | ||
626 | CASE_FIXED_FP(124); | ||
627 | CASE_FIXED_FP(125); | ||
628 | CASE_FIXED_FP(126); | ||
629 | CASE_FIXED_FP(127); | ||
630 | } | ||
631 | #undef CASE_FIXED_FP | ||
632 | } | ||
633 | |||
634 | void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, | ||
635 | struct kvm_pt_regs *regs) | ||
636 | { | ||
637 | /* Take floating register rotation into consideration*/ | ||
638 | if (regnum >= IA64_FIRST_ROTATING_FR) | ||
639 | regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum); | ||
640 | |||
641 | #define CASE_FIXED_FP(reg) \ | ||
642 | case (reg) : \ | ||
643 | ia64_ldf_fill(reg, fpval); \ | ||
644 | break | ||
645 | |||
646 | switch (regnum) { | ||
647 | CASE_FIXED_FP(2); | ||
648 | CASE_FIXED_FP(3); | ||
649 | CASE_FIXED_FP(4); | ||
650 | CASE_FIXED_FP(5); | ||
651 | |||
652 | CASE_FIXED_FP(6); | ||
653 | CASE_FIXED_FP(7); | ||
654 | CASE_FIXED_FP(8); | ||
655 | CASE_FIXED_FP(9); | ||
656 | CASE_FIXED_FP(10); | ||
657 | CASE_FIXED_FP(11); | ||
658 | |||
659 | CASE_FIXED_FP(12); | ||
660 | CASE_FIXED_FP(13); | ||
661 | CASE_FIXED_FP(14); | ||
662 | CASE_FIXED_FP(15); | ||
663 | CASE_FIXED_FP(16); | ||
664 | CASE_FIXED_FP(17); | ||
665 | CASE_FIXED_FP(18); | ||
666 | CASE_FIXED_FP(19); | ||
667 | CASE_FIXED_FP(20); | ||
668 | CASE_FIXED_FP(21); | ||
669 | CASE_FIXED_FP(22); | ||
670 | CASE_FIXED_FP(23); | ||
671 | CASE_FIXED_FP(24); | ||
672 | CASE_FIXED_FP(25); | ||
673 | CASE_FIXED_FP(26); | ||
674 | CASE_FIXED_FP(27); | ||
675 | CASE_FIXED_FP(28); | ||
676 | CASE_FIXED_FP(29); | ||
677 | CASE_FIXED_FP(30); | ||
678 | CASE_FIXED_FP(31); | ||
679 | CASE_FIXED_FP(32); | ||
680 | CASE_FIXED_FP(33); | ||
681 | CASE_FIXED_FP(34); | ||
682 | CASE_FIXED_FP(35); | ||
683 | CASE_FIXED_FP(36); | ||
684 | CASE_FIXED_FP(37); | ||
685 | CASE_FIXED_FP(38); | ||
686 | CASE_FIXED_FP(39); | ||
687 | CASE_FIXED_FP(40); | ||
688 | CASE_FIXED_FP(41); | ||
689 | CASE_FIXED_FP(42); | ||
690 | CASE_FIXED_FP(43); | ||
691 | CASE_FIXED_FP(44); | ||
692 | CASE_FIXED_FP(45); | ||
693 | CASE_FIXED_FP(46); | ||
694 | CASE_FIXED_FP(47); | ||
695 | CASE_FIXED_FP(48); | ||
696 | CASE_FIXED_FP(49); | ||
697 | CASE_FIXED_FP(50); | ||
698 | CASE_FIXED_FP(51); | ||
699 | CASE_FIXED_FP(52); | ||
700 | CASE_FIXED_FP(53); | ||
701 | CASE_FIXED_FP(54); | ||
702 | CASE_FIXED_FP(55); | ||
703 | CASE_FIXED_FP(56); | ||
704 | CASE_FIXED_FP(57); | ||
705 | CASE_FIXED_FP(58); | ||
706 | CASE_FIXED_FP(59); | ||
707 | CASE_FIXED_FP(60); | ||
708 | CASE_FIXED_FP(61); | ||
709 | CASE_FIXED_FP(62); | ||
710 | CASE_FIXED_FP(63); | ||
711 | CASE_FIXED_FP(64); | ||
712 | CASE_FIXED_FP(65); | ||
713 | CASE_FIXED_FP(66); | ||
714 | CASE_FIXED_FP(67); | ||
715 | CASE_FIXED_FP(68); | ||
716 | CASE_FIXED_FP(69); | ||
717 | CASE_FIXED_FP(70); | ||
718 | CASE_FIXED_FP(71); | ||
719 | CASE_FIXED_FP(72); | ||
720 | CASE_FIXED_FP(73); | ||
721 | CASE_FIXED_FP(74); | ||
722 | CASE_FIXED_FP(75); | ||
723 | CASE_FIXED_FP(76); | ||
724 | CASE_FIXED_FP(77); | ||
725 | CASE_FIXED_FP(78); | ||
726 | CASE_FIXED_FP(79); | ||
727 | CASE_FIXED_FP(80); | ||
728 | CASE_FIXED_FP(81); | ||
729 | CASE_FIXED_FP(82); | ||
730 | CASE_FIXED_FP(83); | ||
731 | CASE_FIXED_FP(84); | ||
732 | CASE_FIXED_FP(85); | ||
733 | CASE_FIXED_FP(86); | ||
734 | CASE_FIXED_FP(87); | ||
735 | CASE_FIXED_FP(88); | ||
736 | CASE_FIXED_FP(89); | ||
737 | CASE_FIXED_FP(90); | ||
738 | CASE_FIXED_FP(91); | ||
739 | CASE_FIXED_FP(92); | ||
740 | CASE_FIXED_FP(93); | ||
741 | CASE_FIXED_FP(94); | ||
742 | CASE_FIXED_FP(95); | ||
743 | CASE_FIXED_FP(96); | ||
744 | CASE_FIXED_FP(97); | ||
745 | CASE_FIXED_FP(98); | ||
746 | CASE_FIXED_FP(99); | ||
747 | CASE_FIXED_FP(100); | ||
748 | CASE_FIXED_FP(101); | ||
749 | CASE_FIXED_FP(102); | ||
750 | CASE_FIXED_FP(103); | ||
751 | CASE_FIXED_FP(104); | ||
752 | CASE_FIXED_FP(105); | ||
753 | CASE_FIXED_FP(106); | ||
754 | CASE_FIXED_FP(107); | ||
755 | CASE_FIXED_FP(108); | ||
756 | CASE_FIXED_FP(109); | ||
757 | CASE_FIXED_FP(110); | ||
758 | CASE_FIXED_FP(111); | ||
759 | CASE_FIXED_FP(112); | ||
760 | CASE_FIXED_FP(113); | ||
761 | CASE_FIXED_FP(114); | ||
762 | CASE_FIXED_FP(115); | ||
763 | CASE_FIXED_FP(116); | ||
764 | CASE_FIXED_FP(117); | ||
765 | CASE_FIXED_FP(118); | ||
766 | CASE_FIXED_FP(119); | ||
767 | CASE_FIXED_FP(120); | ||
768 | CASE_FIXED_FP(121); | ||
769 | CASE_FIXED_FP(122); | ||
770 | CASE_FIXED_FP(123); | ||
771 | CASE_FIXED_FP(124); | ||
772 | CASE_FIXED_FP(125); | ||
773 | CASE_FIXED_FP(126); | ||
774 | CASE_FIXED_FP(127); | ||
775 | } | ||
776 | } | ||
777 | |||
778 | void vcpu_get_fpreg(struct kvm_vcpu *vcpu, unsigned long reg, | ||
779 | struct ia64_fpreg *val) | ||
780 | { | ||
781 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
782 | |||
783 | getfpreg(reg, val, regs); /* FIXME: handle NATs later*/ | ||
784 | } | ||
785 | |||
786 | void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg, | ||
787 | struct ia64_fpreg *val) | ||
788 | { | ||
789 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
790 | |||
791 | if (reg > 1) | ||
792 | setfpreg(reg, val, regs); /* FIXME: handle NATs later*/ | ||
793 | } | ||
794 | |||
795 | /************************************************************************ | ||
796 | * lsapic timer | ||
797 | ***********************************************************************/ | ||
798 | u64 vcpu_get_itc(struct kvm_vcpu *vcpu) | ||
799 | { | ||
800 | unsigned long guest_itc; | ||
801 | guest_itc = VMX(vcpu, itc_offset) + ia64_getreg(_IA64_REG_AR_ITC); | ||
802 | |||
803 | if (guest_itc >= VMX(vcpu, last_itc)) { | ||
804 | VMX(vcpu, last_itc) = guest_itc; | ||
805 | return guest_itc; | ||
806 | } else | ||
807 | return VMX(vcpu, last_itc); | ||
808 | } | ||
809 | |||
810 | static inline void vcpu_set_itm(struct kvm_vcpu *vcpu, u64 val); | ||
811 | static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val) | ||
812 | { | ||
813 | struct kvm_vcpu *v; | ||
814 | int i; | ||
815 | long itc_offset = val - ia64_getreg(_IA64_REG_AR_ITC); | ||
816 | unsigned long vitv = VCPU(vcpu, itv); | ||
817 | |||
818 | if (vcpu->vcpu_id == 0) { | ||
819 | for (i = 0; i < MAX_VCPU_NUM; i++) { | ||
820 | v = (struct kvm_vcpu *)((char *)vcpu + VCPU_SIZE * i); | ||
821 | VMX(v, itc_offset) = itc_offset; | ||
822 | VMX(v, last_itc) = 0; | ||
823 | } | ||
824 | } | ||
825 | VMX(vcpu, last_itc) = 0; | ||
826 | if (VCPU(vcpu, itm) <= val) { | ||
827 | VMX(vcpu, itc_check) = 0; | ||
828 | vcpu_unpend_interrupt(vcpu, vitv); | ||
829 | } else { | ||
830 | VMX(vcpu, itc_check) = 1; | ||
831 | vcpu_set_itm(vcpu, VCPU(vcpu, itm)); | ||
832 | } | ||
833 | |||
834 | } | ||
835 | |||
836 | static inline u64 vcpu_get_itm(struct kvm_vcpu *vcpu) | ||
837 | { | ||
838 | return ((u64)VCPU(vcpu, itm)); | ||
839 | } | ||
840 | |||
841 | static inline void vcpu_set_itm(struct kvm_vcpu *vcpu, u64 val) | ||
842 | { | ||
843 | unsigned long vitv = VCPU(vcpu, itv); | ||
844 | VCPU(vcpu, itm) = val; | ||
845 | |||
846 | if (val > vcpu_get_itc(vcpu)) { | ||
847 | VMX(vcpu, itc_check) = 1; | ||
848 | vcpu_unpend_interrupt(vcpu, vitv); | ||
849 | VMX(vcpu, timer_pending) = 0; | ||
850 | } else | ||
851 | VMX(vcpu, itc_check) = 0; | ||
852 | } | ||
853 | |||
854 | #define ITV_VECTOR(itv) (itv&0xff) | ||
855 | #define ITV_IRQ_MASK(itv) (itv&(1<<16)) | ||
856 | |||
857 | static inline void vcpu_set_itv(struct kvm_vcpu *vcpu, u64 val) | ||
858 | { | ||
859 | VCPU(vcpu, itv) = val; | ||
860 | if (!ITV_IRQ_MASK(val) && vcpu->arch.timer_pending) { | ||
861 | vcpu_pend_interrupt(vcpu, ITV_VECTOR(val)); | ||
862 | vcpu->arch.timer_pending = 0; | ||
863 | } | ||
864 | } | ||
865 | |||
866 | static inline void vcpu_set_eoi(struct kvm_vcpu *vcpu, u64 val) | ||
867 | { | ||
868 | int vec; | ||
869 | |||
870 | vec = highest_inservice_irq(vcpu); | ||
871 | if (vec == NULL_VECTOR) | ||
872 | return; | ||
873 | VMX(vcpu, insvc[vec >> 6]) &= ~(1UL << (vec & 63)); | ||
874 | VCPU(vcpu, eoi) = 0; | ||
875 | vcpu->arch.irq_new_pending = 1; | ||
876 | |||
877 | } | ||
878 | |||
879 | /* See Table 5-8 in SDM vol2 for the definition */ | ||
880 | int irq_masked(struct kvm_vcpu *vcpu, int h_pending, int h_inservice) | ||
881 | { | ||
882 | union ia64_tpr vtpr; | ||
883 | |||
884 | vtpr.val = VCPU(vcpu, tpr); | ||
885 | |||
886 | if (h_inservice == NMI_VECTOR) | ||
887 | return IRQ_MASKED_BY_INSVC; | ||
888 | |||
889 | if (h_pending == NMI_VECTOR) { | ||
890 | /* Non Maskable Interrupt */ | ||
891 | return IRQ_NO_MASKED; | ||
892 | } | ||
893 | |||
894 | if (h_inservice == ExtINT_VECTOR) | ||
895 | return IRQ_MASKED_BY_INSVC; | ||
896 | |||
897 | if (h_pending == ExtINT_VECTOR) { | ||
898 | if (vtpr.mmi) { | ||
899 | /* mask all external IRQ */ | ||
900 | return IRQ_MASKED_BY_VTPR; | ||
901 | } else | ||
902 | return IRQ_NO_MASKED; | ||
903 | } | ||
904 | |||
905 | if (is_higher_irq(h_pending, h_inservice)) { | ||
906 | if (is_higher_class(h_pending, vtpr.mic + (vtpr.mmi << 4))) | ||
907 | return IRQ_NO_MASKED; | ||
908 | else | ||
909 | return IRQ_MASKED_BY_VTPR; | ||
910 | } else { | ||
911 | return IRQ_MASKED_BY_INSVC; | ||
912 | } | ||
913 | } | ||
914 | |||
915 | void vcpu_pend_interrupt(struct kvm_vcpu *vcpu, u8 vec) | ||
916 | { | ||
917 | long spsr; | ||
918 | int ret; | ||
919 | |||
920 | local_irq_save(spsr); | ||
921 | ret = test_and_set_bit(vec, &VCPU(vcpu, irr[0])); | ||
922 | local_irq_restore(spsr); | ||
923 | |||
924 | vcpu->arch.irq_new_pending = 1; | ||
925 | } | ||
926 | |||
927 | void vcpu_unpend_interrupt(struct kvm_vcpu *vcpu, u8 vec) | ||
928 | { | ||
929 | long spsr; | ||
930 | int ret; | ||
931 | |||
932 | local_irq_save(spsr); | ||
933 | ret = test_and_clear_bit(vec, &VCPU(vcpu, irr[0])); | ||
934 | local_irq_restore(spsr); | ||
935 | if (ret) { | ||
936 | vcpu->arch.irq_new_pending = 1; | ||
937 | wmb(); | ||
938 | } | ||
939 | } | ||
940 | |||
941 | void update_vhpi(struct kvm_vcpu *vcpu, int vec) | ||
942 | { | ||
943 | u64 vhpi; | ||
944 | |||
945 | if (vec == NULL_VECTOR) | ||
946 | vhpi = 0; | ||
947 | else if (vec == NMI_VECTOR) | ||
948 | vhpi = 32; | ||
949 | else if (vec == ExtINT_VECTOR) | ||
950 | vhpi = 16; | ||
951 | else | ||
952 | vhpi = vec >> 4; | ||
953 | |||
954 | VCPU(vcpu, vhpi) = vhpi; | ||
955 | if (VCPU(vcpu, vac).a_int) | ||
956 | ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT, | ||
957 | (u64)vcpu->arch.vpd, 0, 0, 0, 0, 0, 0); | ||
958 | } | ||
959 | |||
960 | u64 vcpu_get_ivr(struct kvm_vcpu *vcpu) | ||
961 | { | ||
962 | int vec, h_inservice, mask; | ||
963 | |||
964 | vec = highest_pending_irq(vcpu); | ||
965 | h_inservice = highest_inservice_irq(vcpu); | ||
966 | mask = irq_masked(vcpu, vec, h_inservice); | ||
967 | if (vec == NULL_VECTOR || mask == IRQ_MASKED_BY_INSVC) { | ||
968 | if (VCPU(vcpu, vhpi)) | ||
969 | update_vhpi(vcpu, NULL_VECTOR); | ||
970 | return IA64_SPURIOUS_INT_VECTOR; | ||
971 | } | ||
972 | if (mask == IRQ_MASKED_BY_VTPR) { | ||
973 | update_vhpi(vcpu, vec); | ||
974 | return IA64_SPURIOUS_INT_VECTOR; | ||
975 | } | ||
976 | VMX(vcpu, insvc[vec >> 6]) |= (1UL << (vec & 63)); | ||
977 | vcpu_unpend_interrupt(vcpu, vec); | ||
978 | return (u64)vec; | ||
979 | } | ||
980 | |||
981 | /************************************************************************** | ||
982 | Privileged operation emulation routines | ||
983 | **************************************************************************/ | ||
984 | u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr) | ||
985 | { | ||
986 | union ia64_pta vpta; | ||
987 | union ia64_rr vrr; | ||
988 | u64 pval; | ||
989 | u64 vhpt_offset; | ||
990 | |||
991 | vpta.val = vcpu_get_pta(vcpu); | ||
992 | vrr.val = vcpu_get_rr(vcpu, vadr); | ||
993 | vhpt_offset = ((vadr >> vrr.ps) << 3) & ((1UL << (vpta.size)) - 1); | ||
994 | if (vpta.vf) { | ||
995 | pval = ia64_call_vsa(PAL_VPS_THASH, vadr, vrr.val, | ||
996 | vpta.val, 0, 0, 0, 0); | ||
997 | } else { | ||
998 | pval = (vadr & VRN_MASK) | vhpt_offset | | ||
999 | (vpta.val << 3 >> (vpta.size + 3) << (vpta.size)); | ||
1000 | } | ||
1001 | return pval; | ||
1002 | } | ||
1003 | |||
1004 | u64 vcpu_ttag(struct kvm_vcpu *vcpu, u64 vadr) | ||
1005 | { | ||
1006 | union ia64_rr vrr; | ||
1007 | union ia64_pta vpta; | ||
1008 | u64 pval; | ||
1009 | |||
1010 | vpta.val = vcpu_get_pta(vcpu); | ||
1011 | vrr.val = vcpu_get_rr(vcpu, vadr); | ||
1012 | if (vpta.vf) { | ||
1013 | pval = ia64_call_vsa(PAL_VPS_TTAG, vadr, vrr.val, | ||
1014 | 0, 0, 0, 0, 0); | ||
1015 | } else | ||
1016 | pval = 1; | ||
1017 | |||
1018 | return pval; | ||
1019 | } | ||
1020 | |||
1021 | u64 vcpu_tak(struct kvm_vcpu *vcpu, u64 vadr) | ||
1022 | { | ||
1023 | struct thash_data *data; | ||
1024 | union ia64_pta vpta; | ||
1025 | u64 key; | ||
1026 | |||
1027 | vpta.val = vcpu_get_pta(vcpu); | ||
1028 | if (vpta.vf == 0) { | ||
1029 | key = 1; | ||
1030 | return key; | ||
1031 | } | ||
1032 | data = vtlb_lookup(vcpu, vadr, D_TLB); | ||
1033 | if (!data || !data->p) | ||
1034 | key = 1; | ||
1035 | else | ||
1036 | key = data->key; | ||
1037 | |||
1038 | return key; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | |||
1043 | void kvm_thash(struct kvm_vcpu *vcpu, INST64 inst) | ||
1044 | { | ||
1045 | unsigned long thash, vadr; | ||
1046 | |||
1047 | vadr = vcpu_get_gr(vcpu, inst.M46.r3); | ||
1048 | thash = vcpu_thash(vcpu, vadr); | ||
1049 | vcpu_set_gr(vcpu, inst.M46.r1, thash, 0); | ||
1050 | } | ||
1051 | |||
1052 | |||
1053 | void kvm_ttag(struct kvm_vcpu *vcpu, INST64 inst) | ||
1054 | { | ||
1055 | unsigned long tag, vadr; | ||
1056 | |||
1057 | vadr = vcpu_get_gr(vcpu, inst.M46.r3); | ||
1058 | tag = vcpu_ttag(vcpu, vadr); | ||
1059 | vcpu_set_gr(vcpu, inst.M46.r1, tag, 0); | ||
1060 | } | ||
1061 | |||
1062 | int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, u64 *padr) | ||
1063 | { | ||
1064 | struct thash_data *data; | ||
1065 | union ia64_isr visr, pt_isr; | ||
1066 | struct kvm_pt_regs *regs; | ||
1067 | struct ia64_psr vpsr; | ||
1068 | |||
1069 | regs = vcpu_regs(vcpu); | ||
1070 | pt_isr.val = VMX(vcpu, cr_isr); | ||
1071 | visr.val = 0; | ||
1072 | visr.ei = pt_isr.ei; | ||
1073 | visr.ir = pt_isr.ir; | ||
1074 | vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
1075 | visr.na = 1; | ||
1076 | |||
1077 | data = vhpt_lookup(vadr); | ||
1078 | if (data) { | ||
1079 | if (data->p == 0) { | ||
1080 | vcpu_set_isr(vcpu, visr.val); | ||
1081 | data_page_not_present(vcpu, vadr); | ||
1082 | return IA64_FAULT; | ||
1083 | } else if (data->ma == VA_MATTR_NATPAGE) { | ||
1084 | vcpu_set_isr(vcpu, visr.val); | ||
1085 | dnat_page_consumption(vcpu, vadr); | ||
1086 | return IA64_FAULT; | ||
1087 | } else { | ||
1088 | *padr = (data->gpaddr >> data->ps << data->ps) | | ||
1089 | (vadr & (PSIZE(data->ps) - 1)); | ||
1090 | return IA64_NO_FAULT; | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | data = vtlb_lookup(vcpu, vadr, D_TLB); | ||
1095 | if (data) { | ||
1096 | if (data->p == 0) { | ||
1097 | vcpu_set_isr(vcpu, visr.val); | ||
1098 | data_page_not_present(vcpu, vadr); | ||
1099 | return IA64_FAULT; | ||
1100 | } else if (data->ma == VA_MATTR_NATPAGE) { | ||
1101 | vcpu_set_isr(vcpu, visr.val); | ||
1102 | dnat_page_consumption(vcpu, vadr); | ||
1103 | return IA64_FAULT; | ||
1104 | } else{ | ||
1105 | *padr = ((data->ppn >> (data->ps - 12)) << data->ps) | ||
1106 | | (vadr & (PSIZE(data->ps) - 1)); | ||
1107 | return IA64_NO_FAULT; | ||
1108 | } | ||
1109 | } | ||
1110 | if (!vhpt_enabled(vcpu, vadr, NA_REF)) { | ||
1111 | if (vpsr.ic) { | ||
1112 | vcpu_set_isr(vcpu, visr.val); | ||
1113 | alt_dtlb(vcpu, vadr); | ||
1114 | return IA64_FAULT; | ||
1115 | } else { | ||
1116 | nested_dtlb(vcpu); | ||
1117 | return IA64_FAULT; | ||
1118 | } | ||
1119 | } else { | ||
1120 | if (vpsr.ic) { | ||
1121 | vcpu_set_isr(vcpu, visr.val); | ||
1122 | dvhpt_fault(vcpu, vadr); | ||
1123 | return IA64_FAULT; | ||
1124 | } else{ | ||
1125 | nested_dtlb(vcpu); | ||
1126 | return IA64_FAULT; | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | return IA64_NO_FAULT; | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | int kvm_tpa(struct kvm_vcpu *vcpu, INST64 inst) | ||
1135 | { | ||
1136 | unsigned long r1, r3; | ||
1137 | |||
1138 | r3 = vcpu_get_gr(vcpu, inst.M46.r3); | ||
1139 | |||
1140 | if (vcpu_tpa(vcpu, r3, &r1)) | ||
1141 | return IA64_FAULT; | ||
1142 | |||
1143 | vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); | ||
1144 | return(IA64_NO_FAULT); | ||
1145 | } | ||
1146 | |||
1147 | void kvm_tak(struct kvm_vcpu *vcpu, INST64 inst) | ||
1148 | { | ||
1149 | unsigned long r1, r3; | ||
1150 | |||
1151 | r3 = vcpu_get_gr(vcpu, inst.M46.r3); | ||
1152 | r1 = vcpu_tak(vcpu, r3); | ||
1153 | vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | /************************************ | ||
1158 | * Insert/Purge translation register/cache | ||
1159 | ************************************/ | ||
1160 | void vcpu_itc_i(struct kvm_vcpu *vcpu, u64 pte, u64 itir, u64 ifa) | ||
1161 | { | ||
1162 | thash_purge_and_insert(vcpu, pte, itir, ifa, I_TLB); | ||
1163 | } | ||
1164 | |||
1165 | void vcpu_itc_d(struct kvm_vcpu *vcpu, u64 pte, u64 itir, u64 ifa) | ||
1166 | { | ||
1167 | thash_purge_and_insert(vcpu, pte, itir, ifa, D_TLB); | ||
1168 | } | ||
1169 | |||
1170 | void vcpu_itr_i(struct kvm_vcpu *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) | ||
1171 | { | ||
1172 | u64 ps, va, rid; | ||
1173 | struct thash_data *p_itr; | ||
1174 | |||
1175 | ps = itir_ps(itir); | ||
1176 | va = PAGEALIGN(ifa, ps); | ||
1177 | pte &= ~PAGE_FLAGS_RV_MASK; | ||
1178 | rid = vcpu_get_rr(vcpu, ifa); | ||
1179 | rid = rid & RR_RID_MASK; | ||
1180 | p_itr = (struct thash_data *)&vcpu->arch.itrs[slot]; | ||
1181 | vcpu_set_tr(p_itr, pte, itir, va, rid); | ||
1182 | vcpu_quick_region_set(VMX(vcpu, itr_regions), va); | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | void vcpu_itr_d(struct kvm_vcpu *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) | ||
1187 | { | ||
1188 | u64 gpfn; | ||
1189 | u64 ps, va, rid; | ||
1190 | struct thash_data *p_dtr; | ||
1191 | |||
1192 | ps = itir_ps(itir); | ||
1193 | va = PAGEALIGN(ifa, ps); | ||
1194 | pte &= ~PAGE_FLAGS_RV_MASK; | ||
1195 | |||
1196 | if (ps != _PAGE_SIZE_16M) | ||
1197 | thash_purge_entries(vcpu, va, ps); | ||
1198 | gpfn = (pte & _PAGE_PPN_MASK) >> PAGE_SHIFT; | ||
1199 | if (__gpfn_is_io(gpfn)) | ||
1200 | pte |= VTLB_PTE_IO; | ||
1201 | rid = vcpu_get_rr(vcpu, va); | ||
1202 | rid = rid & RR_RID_MASK; | ||
1203 | p_dtr = (struct thash_data *)&vcpu->arch.dtrs[slot]; | ||
1204 | vcpu_set_tr((struct thash_data *)&vcpu->arch.dtrs[slot], | ||
1205 | pte, itir, va, rid); | ||
1206 | vcpu_quick_region_set(VMX(vcpu, dtr_regions), va); | ||
1207 | } | ||
1208 | |||
1209 | void vcpu_ptr_d(struct kvm_vcpu *vcpu, u64 ifa, u64 ps) | ||
1210 | { | ||
1211 | int index; | ||
1212 | u64 va; | ||
1213 | |||
1214 | va = PAGEALIGN(ifa, ps); | ||
1215 | while ((index = vtr_find_overlap(vcpu, va, ps, D_TLB)) >= 0) | ||
1216 | vcpu->arch.dtrs[index].page_flags = 0; | ||
1217 | |||
1218 | thash_purge_entries(vcpu, va, ps); | ||
1219 | } | ||
1220 | |||
1221 | void vcpu_ptr_i(struct kvm_vcpu *vcpu, u64 ifa, u64 ps) | ||
1222 | { | ||
1223 | int index; | ||
1224 | u64 va; | ||
1225 | |||
1226 | va = PAGEALIGN(ifa, ps); | ||
1227 | while ((index = vtr_find_overlap(vcpu, va, ps, I_TLB)) >= 0) | ||
1228 | vcpu->arch.itrs[index].page_flags = 0; | ||
1229 | |||
1230 | thash_purge_entries(vcpu, va, ps); | ||
1231 | } | ||
1232 | |||
1233 | void vcpu_ptc_l(struct kvm_vcpu *vcpu, u64 va, u64 ps) | ||
1234 | { | ||
1235 | va = PAGEALIGN(va, ps); | ||
1236 | thash_purge_entries(vcpu, va, ps); | ||
1237 | } | ||
1238 | |||
1239 | void vcpu_ptc_e(struct kvm_vcpu *vcpu, u64 va) | ||
1240 | { | ||
1241 | thash_purge_all(vcpu); | ||
1242 | } | ||
1243 | |||
1244 | void vcpu_ptc_ga(struct kvm_vcpu *vcpu, u64 va, u64 ps) | ||
1245 | { | ||
1246 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
1247 | long psr; | ||
1248 | local_irq_save(psr); | ||
1249 | p->exit_reason = EXIT_REASON_PTC_G; | ||
1250 | |||
1251 | p->u.ptc_g_data.rr = vcpu_get_rr(vcpu, va); | ||
1252 | p->u.ptc_g_data.vaddr = va; | ||
1253 | p->u.ptc_g_data.ps = ps; | ||
1254 | vmm_transition(vcpu); | ||
1255 | /* Do Local Purge Here*/ | ||
1256 | vcpu_ptc_l(vcpu, va, ps); | ||
1257 | local_irq_restore(psr); | ||
1258 | } | ||
1259 | |||
1260 | |||
1261 | void vcpu_ptc_g(struct kvm_vcpu *vcpu, u64 va, u64 ps) | ||
1262 | { | ||
1263 | vcpu_ptc_ga(vcpu, va, ps); | ||
1264 | } | ||
1265 | |||
1266 | void kvm_ptc_e(struct kvm_vcpu *vcpu, INST64 inst) | ||
1267 | { | ||
1268 | unsigned long ifa; | ||
1269 | |||
1270 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1271 | vcpu_ptc_e(vcpu, ifa); | ||
1272 | } | ||
1273 | |||
1274 | void kvm_ptc_g(struct kvm_vcpu *vcpu, INST64 inst) | ||
1275 | { | ||
1276 | unsigned long ifa, itir; | ||
1277 | |||
1278 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1279 | itir = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1280 | vcpu_ptc_g(vcpu, ifa, itir_ps(itir)); | ||
1281 | } | ||
1282 | |||
1283 | void kvm_ptc_ga(struct kvm_vcpu *vcpu, INST64 inst) | ||
1284 | { | ||
1285 | unsigned long ifa, itir; | ||
1286 | |||
1287 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1288 | itir = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1289 | vcpu_ptc_ga(vcpu, ifa, itir_ps(itir)); | ||
1290 | } | ||
1291 | |||
1292 | void kvm_ptc_l(struct kvm_vcpu *vcpu, INST64 inst) | ||
1293 | { | ||
1294 | unsigned long ifa, itir; | ||
1295 | |||
1296 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1297 | itir = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1298 | vcpu_ptc_l(vcpu, ifa, itir_ps(itir)); | ||
1299 | } | ||
1300 | |||
1301 | void kvm_ptr_d(struct kvm_vcpu *vcpu, INST64 inst) | ||
1302 | { | ||
1303 | unsigned long ifa, itir; | ||
1304 | |||
1305 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1306 | itir = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1307 | vcpu_ptr_d(vcpu, ifa, itir_ps(itir)); | ||
1308 | } | ||
1309 | |||
1310 | void kvm_ptr_i(struct kvm_vcpu *vcpu, INST64 inst) | ||
1311 | { | ||
1312 | unsigned long ifa, itir; | ||
1313 | |||
1314 | ifa = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1315 | itir = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1316 | vcpu_ptr_i(vcpu, ifa, itir_ps(itir)); | ||
1317 | } | ||
1318 | |||
1319 | void kvm_itr_d(struct kvm_vcpu *vcpu, INST64 inst) | ||
1320 | { | ||
1321 | unsigned long itir, ifa, pte, slot; | ||
1322 | |||
1323 | slot = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1324 | pte = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1325 | itir = vcpu_get_itir(vcpu); | ||
1326 | ifa = vcpu_get_ifa(vcpu); | ||
1327 | vcpu_itr_d(vcpu, slot, pte, itir, ifa); | ||
1328 | } | ||
1329 | |||
1330 | |||
1331 | |||
1332 | void kvm_itr_i(struct kvm_vcpu *vcpu, INST64 inst) | ||
1333 | { | ||
1334 | unsigned long itir, ifa, pte, slot; | ||
1335 | |||
1336 | slot = vcpu_get_gr(vcpu, inst.M45.r3); | ||
1337 | pte = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1338 | itir = vcpu_get_itir(vcpu); | ||
1339 | ifa = vcpu_get_ifa(vcpu); | ||
1340 | vcpu_itr_i(vcpu, slot, pte, itir, ifa); | ||
1341 | } | ||
1342 | |||
1343 | void kvm_itc_d(struct kvm_vcpu *vcpu, INST64 inst) | ||
1344 | { | ||
1345 | unsigned long itir, ifa, pte; | ||
1346 | |||
1347 | itir = vcpu_get_itir(vcpu); | ||
1348 | ifa = vcpu_get_ifa(vcpu); | ||
1349 | pte = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1350 | vcpu_itc_d(vcpu, pte, itir, ifa); | ||
1351 | } | ||
1352 | |||
1353 | void kvm_itc_i(struct kvm_vcpu *vcpu, INST64 inst) | ||
1354 | { | ||
1355 | unsigned long itir, ifa, pte; | ||
1356 | |||
1357 | itir = vcpu_get_itir(vcpu); | ||
1358 | ifa = vcpu_get_ifa(vcpu); | ||
1359 | pte = vcpu_get_gr(vcpu, inst.M45.r2); | ||
1360 | vcpu_itc_i(vcpu, pte, itir, ifa); | ||
1361 | } | ||
1362 | |||
1363 | /************************************* | ||
1364 | * Moves to semi-privileged registers | ||
1365 | *************************************/ | ||
1366 | |||
1367 | void kvm_mov_to_ar_imm(struct kvm_vcpu *vcpu, INST64 inst) | ||
1368 | { | ||
1369 | unsigned long imm; | ||
1370 | |||
1371 | if (inst.M30.s) | ||
1372 | imm = -inst.M30.imm; | ||
1373 | else | ||
1374 | imm = inst.M30.imm; | ||
1375 | |||
1376 | vcpu_set_itc(vcpu, imm); | ||
1377 | } | ||
1378 | |||
1379 | void kvm_mov_to_ar_reg(struct kvm_vcpu *vcpu, INST64 inst) | ||
1380 | { | ||
1381 | unsigned long r2; | ||
1382 | |||
1383 | r2 = vcpu_get_gr(vcpu, inst.M29.r2); | ||
1384 | vcpu_set_itc(vcpu, r2); | ||
1385 | } | ||
1386 | |||
1387 | |||
1388 | void kvm_mov_from_ar_reg(struct kvm_vcpu *vcpu, INST64 inst) | ||
1389 | { | ||
1390 | unsigned long r1; | ||
1391 | |||
1392 | r1 = vcpu_get_itc(vcpu); | ||
1393 | vcpu_set_gr(vcpu, inst.M31.r1, r1, 0); | ||
1394 | } | ||
1395 | /************************************************************************** | ||
1396 | struct kvm_vcpu*protection key register access routines | ||
1397 | **************************************************************************/ | ||
1398 | |||
1399 | unsigned long vcpu_get_pkr(struct kvm_vcpu *vcpu, unsigned long reg) | ||
1400 | { | ||
1401 | return ((unsigned long)ia64_get_pkr(reg)); | ||
1402 | } | ||
1403 | |||
1404 | void vcpu_set_pkr(struct kvm_vcpu *vcpu, unsigned long reg, unsigned long val) | ||
1405 | { | ||
1406 | ia64_set_pkr(reg, val); | ||
1407 | } | ||
1408 | |||
1409 | |||
1410 | unsigned long vcpu_get_itir_on_fault(struct kvm_vcpu *vcpu, unsigned long ifa) | ||
1411 | { | ||
1412 | union ia64_rr rr, rr1; | ||
1413 | |||
1414 | rr.val = vcpu_get_rr(vcpu, ifa); | ||
1415 | rr1.val = 0; | ||
1416 | rr1.ps = rr.ps; | ||
1417 | rr1.rid = rr.rid; | ||
1418 | return (rr1.val); | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | |||
1423 | /******************************** | ||
1424 | * Moves to privileged registers | ||
1425 | ********************************/ | ||
1426 | unsigned long vcpu_set_rr(struct kvm_vcpu *vcpu, unsigned long reg, | ||
1427 | unsigned long val) | ||
1428 | { | ||
1429 | union ia64_rr oldrr, newrr; | ||
1430 | unsigned long rrval; | ||
1431 | struct exit_ctl_data *p = &vcpu->arch.exit_data; | ||
1432 | unsigned long psr; | ||
1433 | |||
1434 | oldrr.val = vcpu_get_rr(vcpu, reg); | ||
1435 | newrr.val = val; | ||
1436 | vcpu->arch.vrr[reg >> VRN_SHIFT] = val; | ||
1437 | |||
1438 | switch ((unsigned long)(reg >> VRN_SHIFT)) { | ||
1439 | case VRN6: | ||
1440 | vcpu->arch.vmm_rr = vrrtomrr(val); | ||
1441 | local_irq_save(psr); | ||
1442 | p->exit_reason = EXIT_REASON_SWITCH_RR6; | ||
1443 | vmm_transition(vcpu); | ||
1444 | local_irq_restore(psr); | ||
1445 | break; | ||
1446 | case VRN4: | ||
1447 | rrval = vrrtomrr(val); | ||
1448 | vcpu->arch.metaphysical_saved_rr4 = rrval; | ||
1449 | if (!is_physical_mode(vcpu)) | ||
1450 | ia64_set_rr(reg, rrval); | ||
1451 | break; | ||
1452 | case VRN0: | ||
1453 | rrval = vrrtomrr(val); | ||
1454 | vcpu->arch.metaphysical_saved_rr0 = rrval; | ||
1455 | if (!is_physical_mode(vcpu)) | ||
1456 | ia64_set_rr(reg, rrval); | ||
1457 | break; | ||
1458 | default: | ||
1459 | ia64_set_rr(reg, vrrtomrr(val)); | ||
1460 | break; | ||
1461 | } | ||
1462 | |||
1463 | return (IA64_NO_FAULT); | ||
1464 | } | ||
1465 | |||
1466 | |||
1467 | |||
1468 | void kvm_mov_to_rr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1469 | { | ||
1470 | unsigned long r3, r2; | ||
1471 | |||
1472 | r3 = vcpu_get_gr(vcpu, inst.M42.r3); | ||
1473 | r2 = vcpu_get_gr(vcpu, inst.M42.r2); | ||
1474 | vcpu_set_rr(vcpu, r3, r2); | ||
1475 | } | ||
1476 | |||
1477 | void kvm_mov_to_dbr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1478 | { | ||
1479 | } | ||
1480 | |||
1481 | void kvm_mov_to_ibr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1482 | { | ||
1483 | } | ||
1484 | |||
1485 | void kvm_mov_to_pmc(struct kvm_vcpu *vcpu, INST64 inst) | ||
1486 | { | ||
1487 | unsigned long r3, r2; | ||
1488 | |||
1489 | r3 = vcpu_get_gr(vcpu, inst.M42.r3); | ||
1490 | r2 = vcpu_get_gr(vcpu, inst.M42.r2); | ||
1491 | vcpu_set_pmc(vcpu, r3, r2); | ||
1492 | } | ||
1493 | |||
1494 | void kvm_mov_to_pmd(struct kvm_vcpu *vcpu, INST64 inst) | ||
1495 | { | ||
1496 | unsigned long r3, r2; | ||
1497 | |||
1498 | r3 = vcpu_get_gr(vcpu, inst.M42.r3); | ||
1499 | r2 = vcpu_get_gr(vcpu, inst.M42.r2); | ||
1500 | vcpu_set_pmd(vcpu, r3, r2); | ||
1501 | } | ||
1502 | |||
1503 | void kvm_mov_to_pkr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1504 | { | ||
1505 | u64 r3, r2; | ||
1506 | |||
1507 | r3 = vcpu_get_gr(vcpu, inst.M42.r3); | ||
1508 | r2 = vcpu_get_gr(vcpu, inst.M42.r2); | ||
1509 | vcpu_set_pkr(vcpu, r3, r2); | ||
1510 | } | ||
1511 | |||
1512 | |||
1513 | |||
1514 | void kvm_mov_from_rr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1515 | { | ||
1516 | unsigned long r3, r1; | ||
1517 | |||
1518 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1519 | r1 = vcpu_get_rr(vcpu, r3); | ||
1520 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1521 | } | ||
1522 | |||
1523 | void kvm_mov_from_pkr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1524 | { | ||
1525 | unsigned long r3, r1; | ||
1526 | |||
1527 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1528 | r1 = vcpu_get_pkr(vcpu, r3); | ||
1529 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1530 | } | ||
1531 | |||
1532 | void kvm_mov_from_dbr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1533 | { | ||
1534 | unsigned long r3, r1; | ||
1535 | |||
1536 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1537 | r1 = vcpu_get_dbr(vcpu, r3); | ||
1538 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1539 | } | ||
1540 | |||
1541 | void kvm_mov_from_ibr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1542 | { | ||
1543 | unsigned long r3, r1; | ||
1544 | |||
1545 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1546 | r1 = vcpu_get_ibr(vcpu, r3); | ||
1547 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1548 | } | ||
1549 | |||
1550 | void kvm_mov_from_pmc(struct kvm_vcpu *vcpu, INST64 inst) | ||
1551 | { | ||
1552 | unsigned long r3, r1; | ||
1553 | |||
1554 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1555 | r1 = vcpu_get_pmc(vcpu, r3); | ||
1556 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1557 | } | ||
1558 | |||
1559 | |||
1560 | unsigned long vcpu_get_cpuid(struct kvm_vcpu *vcpu, unsigned long reg) | ||
1561 | { | ||
1562 | /* FIXME: This could get called as a result of a rsvd-reg fault */ | ||
1563 | if (reg > (ia64_get_cpuid(3) & 0xff)) | ||
1564 | return 0; | ||
1565 | else | ||
1566 | return ia64_get_cpuid(reg); | ||
1567 | } | ||
1568 | |||
1569 | void kvm_mov_from_cpuid(struct kvm_vcpu *vcpu, INST64 inst) | ||
1570 | { | ||
1571 | unsigned long r3, r1; | ||
1572 | |||
1573 | r3 = vcpu_get_gr(vcpu, inst.M43.r3); | ||
1574 | r1 = vcpu_get_cpuid(vcpu, r3); | ||
1575 | vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); | ||
1576 | } | ||
1577 | |||
1578 | void vcpu_set_tpr(struct kvm_vcpu *vcpu, unsigned long val) | ||
1579 | { | ||
1580 | VCPU(vcpu, tpr) = val; | ||
1581 | vcpu->arch.irq_check = 1; | ||
1582 | } | ||
1583 | |||
1584 | unsigned long kvm_mov_to_cr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1585 | { | ||
1586 | unsigned long r2; | ||
1587 | |||
1588 | r2 = vcpu_get_gr(vcpu, inst.M32.r2); | ||
1589 | VCPU(vcpu, vcr[inst.M32.cr3]) = r2; | ||
1590 | |||
1591 | switch (inst.M32.cr3) { | ||
1592 | case 0: | ||
1593 | vcpu_set_dcr(vcpu, r2); | ||
1594 | break; | ||
1595 | case 1: | ||
1596 | vcpu_set_itm(vcpu, r2); | ||
1597 | break; | ||
1598 | case 66: | ||
1599 | vcpu_set_tpr(vcpu, r2); | ||
1600 | break; | ||
1601 | case 67: | ||
1602 | vcpu_set_eoi(vcpu, r2); | ||
1603 | break; | ||
1604 | default: | ||
1605 | break; | ||
1606 | } | ||
1607 | |||
1608 | return 0; | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | unsigned long kvm_mov_from_cr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1613 | { | ||
1614 | unsigned long tgt = inst.M33.r1; | ||
1615 | unsigned long val; | ||
1616 | |||
1617 | switch (inst.M33.cr3) { | ||
1618 | case 65: | ||
1619 | val = vcpu_get_ivr(vcpu); | ||
1620 | vcpu_set_gr(vcpu, tgt, val, 0); | ||
1621 | break; | ||
1622 | |||
1623 | case 67: | ||
1624 | vcpu_set_gr(vcpu, tgt, 0L, 0); | ||
1625 | break; | ||
1626 | default: | ||
1627 | val = VCPU(vcpu, vcr[inst.M33.cr3]); | ||
1628 | vcpu_set_gr(vcpu, tgt, val, 0); | ||
1629 | break; | ||
1630 | } | ||
1631 | |||
1632 | return 0; | ||
1633 | } | ||
1634 | |||
1635 | |||
1636 | |||
1637 | void vcpu_set_psr(struct kvm_vcpu *vcpu, unsigned long val) | ||
1638 | { | ||
1639 | |||
1640 | unsigned long mask; | ||
1641 | struct kvm_pt_regs *regs; | ||
1642 | struct ia64_psr old_psr, new_psr; | ||
1643 | |||
1644 | old_psr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
1645 | |||
1646 | regs = vcpu_regs(vcpu); | ||
1647 | /* We only support guest as: | ||
1648 | * vpsr.pk = 0 | ||
1649 | * vpsr.is = 0 | ||
1650 | * Otherwise panic | ||
1651 | */ | ||
1652 | if (val & (IA64_PSR_PK | IA64_PSR_IS | IA64_PSR_VM)) | ||
1653 | panic_vm(vcpu); | ||
1654 | |||
1655 | /* | ||
1656 | * For those IA64_PSR bits: id/da/dd/ss/ed/ia | ||
1657 | * Since these bits will become 0, after success execution of each | ||
1658 | * instruction, we will change set them to mIA64_PSR | ||
1659 | */ | ||
1660 | VCPU(vcpu, vpsr) = val | ||
1661 | & (~(IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | | ||
1662 | IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA)); | ||
1663 | |||
1664 | if (!old_psr.i && (val & IA64_PSR_I)) { | ||
1665 | /* vpsr.i 0->1 */ | ||
1666 | vcpu->arch.irq_check = 1; | ||
1667 | } | ||
1668 | new_psr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
1669 | |||
1670 | /* | ||
1671 | * All vIA64_PSR bits shall go to mPSR (v->tf->tf_special.psr) | ||
1672 | * , except for the following bits: | ||
1673 | * ic/i/dt/si/rt/mc/it/bn/vm | ||
1674 | */ | ||
1675 | mask = IA64_PSR_IC + IA64_PSR_I + IA64_PSR_DT + IA64_PSR_SI + | ||
1676 | IA64_PSR_RT + IA64_PSR_MC + IA64_PSR_IT + IA64_PSR_BN + | ||
1677 | IA64_PSR_VM; | ||
1678 | |||
1679 | regs->cr_ipsr = (regs->cr_ipsr & mask) | (val & (~mask)); | ||
1680 | |||
1681 | check_mm_mode_switch(vcpu, old_psr, new_psr); | ||
1682 | |||
1683 | return ; | ||
1684 | } | ||
1685 | |||
1686 | unsigned long vcpu_cover(struct kvm_vcpu *vcpu) | ||
1687 | { | ||
1688 | struct ia64_psr vpsr; | ||
1689 | |||
1690 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1691 | vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
1692 | |||
1693 | if (!vpsr.ic) | ||
1694 | VCPU(vcpu, ifs) = regs->cr_ifs; | ||
1695 | regs->cr_ifs = IA64_IFS_V; | ||
1696 | return (IA64_NO_FAULT); | ||
1697 | } | ||
1698 | |||
1699 | |||
1700 | |||
1701 | /************************************************************************** | ||
1702 | VCPU banked general register access routines | ||
1703 | **************************************************************************/ | ||
1704 | #define vcpu_bsw0_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \ | ||
1705 | do { \ | ||
1706 | __asm__ __volatile__ ( \ | ||
1707 | ";;extr.u %0 = %3,%6,16;;\n" \ | ||
1708 | "dep %1 = %0, %1, 0, 16;;\n" \ | ||
1709 | "st8 [%4] = %1\n" \ | ||
1710 | "extr.u %0 = %2, 16, 16;;\n" \ | ||
1711 | "dep %3 = %0, %3, %6, 16;;\n" \ | ||
1712 | "st8 [%5] = %3\n" \ | ||
1713 | ::"r"(i), "r"(*b1unat), "r"(*b0unat), \ | ||
1714 | "r"(*runat), "r"(b1unat), "r"(runat), \ | ||
1715 | "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \ | ||
1716 | } while (0) | ||
1717 | |||
1718 | void vcpu_bsw0(struct kvm_vcpu *vcpu) | ||
1719 | { | ||
1720 | unsigned long i; | ||
1721 | |||
1722 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1723 | unsigned long *r = ®s->r16; | ||
1724 | unsigned long *b0 = &VCPU(vcpu, vbgr[0]); | ||
1725 | unsigned long *b1 = &VCPU(vcpu, vgr[0]); | ||
1726 | unsigned long *runat = ®s->eml_unat; | ||
1727 | unsigned long *b0unat = &VCPU(vcpu, vbnat); | ||
1728 | unsigned long *b1unat = &VCPU(vcpu, vnat); | ||
1729 | |||
1730 | |||
1731 | if (VCPU(vcpu, vpsr) & IA64_PSR_BN) { | ||
1732 | for (i = 0; i < 16; i++) { | ||
1733 | *b1++ = *r; | ||
1734 | *r++ = *b0++; | ||
1735 | } | ||
1736 | vcpu_bsw0_unat(i, b0unat, b1unat, runat, | ||
1737 | VMM_PT_REGS_R16_SLOT); | ||
1738 | VCPU(vcpu, vpsr) &= ~IA64_PSR_BN; | ||
1739 | } | ||
1740 | } | ||
1741 | |||
1742 | #define vcpu_bsw1_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \ | ||
1743 | do { \ | ||
1744 | __asm__ __volatile__ (";;extr.u %0 = %3, %6, 16;;\n" \ | ||
1745 | "dep %1 = %0, %1, 16, 16;;\n" \ | ||
1746 | "st8 [%4] = %1\n" \ | ||
1747 | "extr.u %0 = %2, 0, 16;;\n" \ | ||
1748 | "dep %3 = %0, %3, %6, 16;;\n" \ | ||
1749 | "st8 [%5] = %3\n" \ | ||
1750 | ::"r"(i), "r"(*b0unat), "r"(*b1unat), \ | ||
1751 | "r"(*runat), "r"(b0unat), "r"(runat), \ | ||
1752 | "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \ | ||
1753 | } while (0) | ||
1754 | |||
1755 | void vcpu_bsw1(struct kvm_vcpu *vcpu) | ||
1756 | { | ||
1757 | unsigned long i; | ||
1758 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1759 | unsigned long *r = ®s->r16; | ||
1760 | unsigned long *b0 = &VCPU(vcpu, vbgr[0]); | ||
1761 | unsigned long *b1 = &VCPU(vcpu, vgr[0]); | ||
1762 | unsigned long *runat = ®s->eml_unat; | ||
1763 | unsigned long *b0unat = &VCPU(vcpu, vbnat); | ||
1764 | unsigned long *b1unat = &VCPU(vcpu, vnat); | ||
1765 | |||
1766 | if (!(VCPU(vcpu, vpsr) & IA64_PSR_BN)) { | ||
1767 | for (i = 0; i < 16; i++) { | ||
1768 | *b0++ = *r; | ||
1769 | *r++ = *b1++; | ||
1770 | } | ||
1771 | vcpu_bsw1_unat(i, b0unat, b1unat, runat, | ||
1772 | VMM_PT_REGS_R16_SLOT); | ||
1773 | VCPU(vcpu, vpsr) |= IA64_PSR_BN; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | |||
1778 | |||
1779 | |||
1780 | void vcpu_rfi(struct kvm_vcpu *vcpu) | ||
1781 | { | ||
1782 | unsigned long ifs, psr; | ||
1783 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1784 | |||
1785 | psr = VCPU(vcpu, ipsr); | ||
1786 | if (psr & IA64_PSR_BN) | ||
1787 | vcpu_bsw1(vcpu); | ||
1788 | else | ||
1789 | vcpu_bsw0(vcpu); | ||
1790 | vcpu_set_psr(vcpu, psr); | ||
1791 | ifs = VCPU(vcpu, ifs); | ||
1792 | if (ifs >> 63) | ||
1793 | regs->cr_ifs = ifs; | ||
1794 | regs->cr_iip = VCPU(vcpu, iip); | ||
1795 | } | ||
1796 | |||
1797 | |||
1798 | /* | ||
1799 | VPSR can't keep track of below bits of guest PSR | ||
1800 | This function gets guest PSR | ||
1801 | */ | ||
1802 | |||
1803 | unsigned long vcpu_get_psr(struct kvm_vcpu *vcpu) | ||
1804 | { | ||
1805 | unsigned long mask; | ||
1806 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1807 | |||
1808 | mask = IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | | ||
1809 | IA64_PSR_MFH | IA64_PSR_CPL | IA64_PSR_RI; | ||
1810 | return (VCPU(vcpu, vpsr) & ~mask) | (regs->cr_ipsr & mask); | ||
1811 | } | ||
1812 | |||
1813 | void kvm_rsm(struct kvm_vcpu *vcpu, INST64 inst) | ||
1814 | { | ||
1815 | unsigned long vpsr; | ||
1816 | unsigned long imm24 = (inst.M44.i<<23) | (inst.M44.i2<<21) | ||
1817 | | inst.M44.imm; | ||
1818 | |||
1819 | vpsr = vcpu_get_psr(vcpu); | ||
1820 | vpsr &= (~imm24); | ||
1821 | vcpu_set_psr(vcpu, vpsr); | ||
1822 | } | ||
1823 | |||
1824 | void kvm_ssm(struct kvm_vcpu *vcpu, INST64 inst) | ||
1825 | { | ||
1826 | unsigned long vpsr; | ||
1827 | unsigned long imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | ||
1828 | | inst.M44.imm; | ||
1829 | |||
1830 | vpsr = vcpu_get_psr(vcpu); | ||
1831 | vpsr |= imm24; | ||
1832 | vcpu_set_psr(vcpu, vpsr); | ||
1833 | } | ||
1834 | |||
1835 | /* Generate Mask | ||
1836 | * Parameter: | ||
1837 | * bit -- starting bit | ||
1838 | * len -- how many bits | ||
1839 | */ | ||
1840 | #define MASK(bit,len) \ | ||
1841 | ({ \ | ||
1842 | __u64 ret; \ | ||
1843 | \ | ||
1844 | __asm __volatile("dep %0=-1, r0, %1, %2"\ | ||
1845 | : "=r" (ret): \ | ||
1846 | "M" (bit), \ | ||
1847 | "M" (len)); \ | ||
1848 | ret; \ | ||
1849 | }) | ||
1850 | |||
1851 | void vcpu_set_psr_l(struct kvm_vcpu *vcpu, unsigned long val) | ||
1852 | { | ||
1853 | val = (val & MASK(0, 32)) | (vcpu_get_psr(vcpu) & MASK(32, 32)); | ||
1854 | vcpu_set_psr(vcpu, val); | ||
1855 | } | ||
1856 | |||
1857 | void kvm_mov_to_psr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1858 | { | ||
1859 | unsigned long val; | ||
1860 | |||
1861 | val = vcpu_get_gr(vcpu, inst.M35.r2); | ||
1862 | vcpu_set_psr_l(vcpu, val); | ||
1863 | } | ||
1864 | |||
1865 | void kvm_mov_from_psr(struct kvm_vcpu *vcpu, INST64 inst) | ||
1866 | { | ||
1867 | unsigned long val; | ||
1868 | |||
1869 | val = vcpu_get_psr(vcpu); | ||
1870 | val = (val & MASK(0, 32)) | (val & MASK(35, 2)); | ||
1871 | vcpu_set_gr(vcpu, inst.M33.r1, val, 0); | ||
1872 | } | ||
1873 | |||
1874 | void vcpu_increment_iip(struct kvm_vcpu *vcpu) | ||
1875 | { | ||
1876 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1877 | struct ia64_psr *ipsr = (struct ia64_psr *)®s->cr_ipsr; | ||
1878 | if (ipsr->ri == 2) { | ||
1879 | ipsr->ri = 0; | ||
1880 | regs->cr_iip += 16; | ||
1881 | } else | ||
1882 | ipsr->ri++; | ||
1883 | } | ||
1884 | |||
1885 | void vcpu_decrement_iip(struct kvm_vcpu *vcpu) | ||
1886 | { | ||
1887 | struct kvm_pt_regs *regs = vcpu_regs(vcpu); | ||
1888 | struct ia64_psr *ipsr = (struct ia64_psr *)®s->cr_ipsr; | ||
1889 | |||
1890 | if (ipsr->ri == 0) { | ||
1891 | ipsr->ri = 2; | ||
1892 | regs->cr_iip -= 16; | ||
1893 | } else | ||
1894 | ipsr->ri--; | ||
1895 | } | ||
1896 | |||
1897 | /** Emulate a privileged operation. | ||
1898 | * | ||
1899 | * | ||
1900 | * @param vcpu virtual cpu | ||
1901 | * @cause the reason cause virtualization fault | ||
1902 | * @opcode the instruction code which cause virtualization fault | ||
1903 | */ | ||
1904 | |||
1905 | void kvm_emulate(struct kvm_vcpu *vcpu, struct kvm_pt_regs *regs) | ||
1906 | { | ||
1907 | unsigned long status, cause, opcode ; | ||
1908 | INST64 inst; | ||
1909 | |||
1910 | status = IA64_NO_FAULT; | ||
1911 | cause = VMX(vcpu, cause); | ||
1912 | opcode = VMX(vcpu, opcode); | ||
1913 | inst.inst = opcode; | ||
1914 | /* | ||
1915 | * Switch to actual virtual rid in rr0 and rr4, | ||
1916 | * which is required by some tlb related instructions. | ||
1917 | */ | ||
1918 | prepare_if_physical_mode(vcpu); | ||
1919 | |||
1920 | switch (cause) { | ||
1921 | case EVENT_RSM: | ||
1922 | kvm_rsm(vcpu, inst); | ||
1923 | break; | ||
1924 | case EVENT_SSM: | ||
1925 | kvm_ssm(vcpu, inst); | ||
1926 | break; | ||
1927 | case EVENT_MOV_TO_PSR: | ||
1928 | kvm_mov_to_psr(vcpu, inst); | ||
1929 | break; | ||
1930 | case EVENT_MOV_FROM_PSR: | ||
1931 | kvm_mov_from_psr(vcpu, inst); | ||
1932 | break; | ||
1933 | case EVENT_MOV_FROM_CR: | ||
1934 | kvm_mov_from_cr(vcpu, inst); | ||
1935 | break; | ||
1936 | case EVENT_MOV_TO_CR: | ||
1937 | kvm_mov_to_cr(vcpu, inst); | ||
1938 | break; | ||
1939 | case EVENT_BSW_0: | ||
1940 | vcpu_bsw0(vcpu); | ||
1941 | break; | ||
1942 | case EVENT_BSW_1: | ||
1943 | vcpu_bsw1(vcpu); | ||
1944 | break; | ||
1945 | case EVENT_COVER: | ||
1946 | vcpu_cover(vcpu); | ||
1947 | break; | ||
1948 | case EVENT_RFI: | ||
1949 | vcpu_rfi(vcpu); | ||
1950 | break; | ||
1951 | case EVENT_ITR_D: | ||
1952 | kvm_itr_d(vcpu, inst); | ||
1953 | break; | ||
1954 | case EVENT_ITR_I: | ||
1955 | kvm_itr_i(vcpu, inst); | ||
1956 | break; | ||
1957 | case EVENT_PTR_D: | ||
1958 | kvm_ptr_d(vcpu, inst); | ||
1959 | break; | ||
1960 | case EVENT_PTR_I: | ||
1961 | kvm_ptr_i(vcpu, inst); | ||
1962 | break; | ||
1963 | case EVENT_ITC_D: | ||
1964 | kvm_itc_d(vcpu, inst); | ||
1965 | break; | ||
1966 | case EVENT_ITC_I: | ||
1967 | kvm_itc_i(vcpu, inst); | ||
1968 | break; | ||
1969 | case EVENT_PTC_L: | ||
1970 | kvm_ptc_l(vcpu, inst); | ||
1971 | break; | ||
1972 | case EVENT_PTC_G: | ||
1973 | kvm_ptc_g(vcpu, inst); | ||
1974 | break; | ||
1975 | case EVENT_PTC_GA: | ||
1976 | kvm_ptc_ga(vcpu, inst); | ||
1977 | break; | ||
1978 | case EVENT_PTC_E: | ||
1979 | kvm_ptc_e(vcpu, inst); | ||
1980 | break; | ||
1981 | case EVENT_MOV_TO_RR: | ||
1982 | kvm_mov_to_rr(vcpu, inst); | ||
1983 | break; | ||
1984 | case EVENT_MOV_FROM_RR: | ||
1985 | kvm_mov_from_rr(vcpu, inst); | ||
1986 | break; | ||
1987 | case EVENT_THASH: | ||
1988 | kvm_thash(vcpu, inst); | ||
1989 | break; | ||
1990 | case EVENT_TTAG: | ||
1991 | kvm_ttag(vcpu, inst); | ||
1992 | break; | ||
1993 | case EVENT_TPA: | ||
1994 | status = kvm_tpa(vcpu, inst); | ||
1995 | break; | ||
1996 | case EVENT_TAK: | ||
1997 | kvm_tak(vcpu, inst); | ||
1998 | break; | ||
1999 | case EVENT_MOV_TO_AR_IMM: | ||
2000 | kvm_mov_to_ar_imm(vcpu, inst); | ||
2001 | break; | ||
2002 | case EVENT_MOV_TO_AR: | ||
2003 | kvm_mov_to_ar_reg(vcpu, inst); | ||
2004 | break; | ||
2005 | case EVENT_MOV_FROM_AR: | ||
2006 | kvm_mov_from_ar_reg(vcpu, inst); | ||
2007 | break; | ||
2008 | case EVENT_MOV_TO_DBR: | ||
2009 | kvm_mov_to_dbr(vcpu, inst); | ||
2010 | break; | ||
2011 | case EVENT_MOV_TO_IBR: | ||
2012 | kvm_mov_to_ibr(vcpu, inst); | ||
2013 | break; | ||
2014 | case EVENT_MOV_TO_PMC: | ||
2015 | kvm_mov_to_pmc(vcpu, inst); | ||
2016 | break; | ||
2017 | case EVENT_MOV_TO_PMD: | ||
2018 | kvm_mov_to_pmd(vcpu, inst); | ||
2019 | break; | ||
2020 | case EVENT_MOV_TO_PKR: | ||
2021 | kvm_mov_to_pkr(vcpu, inst); | ||
2022 | break; | ||
2023 | case EVENT_MOV_FROM_DBR: | ||
2024 | kvm_mov_from_dbr(vcpu, inst); | ||
2025 | break; | ||
2026 | case EVENT_MOV_FROM_IBR: | ||
2027 | kvm_mov_from_ibr(vcpu, inst); | ||
2028 | break; | ||
2029 | case EVENT_MOV_FROM_PMC: | ||
2030 | kvm_mov_from_pmc(vcpu, inst); | ||
2031 | break; | ||
2032 | case EVENT_MOV_FROM_PKR: | ||
2033 | kvm_mov_from_pkr(vcpu, inst); | ||
2034 | break; | ||
2035 | case EVENT_MOV_FROM_CPUID: | ||
2036 | kvm_mov_from_cpuid(vcpu, inst); | ||
2037 | break; | ||
2038 | case EVENT_VMSW: | ||
2039 | status = IA64_FAULT; | ||
2040 | break; | ||
2041 | default: | ||
2042 | break; | ||
2043 | }; | ||
2044 | /*Assume all status is NO_FAULT ?*/ | ||
2045 | if (status == IA64_NO_FAULT && cause != EVENT_RFI) | ||
2046 | vcpu_increment_iip(vcpu); | ||
2047 | |||
2048 | recover_if_physical_mode(vcpu); | ||
2049 | } | ||
2050 | |||
2051 | void init_vcpu(struct kvm_vcpu *vcpu) | ||
2052 | { | ||
2053 | int i; | ||
2054 | |||
2055 | vcpu->arch.mode_flags = GUEST_IN_PHY; | ||
2056 | VMX(vcpu, vrr[0]) = 0x38; | ||
2057 | VMX(vcpu, vrr[1]) = 0x38; | ||
2058 | VMX(vcpu, vrr[2]) = 0x38; | ||
2059 | VMX(vcpu, vrr[3]) = 0x38; | ||
2060 | VMX(vcpu, vrr[4]) = 0x38; | ||
2061 | VMX(vcpu, vrr[5]) = 0x38; | ||
2062 | VMX(vcpu, vrr[6]) = 0x38; | ||
2063 | VMX(vcpu, vrr[7]) = 0x38; | ||
2064 | VCPU(vcpu, vpsr) = IA64_PSR_BN; | ||
2065 | VCPU(vcpu, dcr) = 0; | ||
2066 | /* pta.size must not be 0. The minimum is 15 (32k) */ | ||
2067 | VCPU(vcpu, pta) = 15 << 2; | ||
2068 | VCPU(vcpu, itv) = 0x10000; | ||
2069 | VCPU(vcpu, itm) = 0; | ||
2070 | VMX(vcpu, last_itc) = 0; | ||
2071 | |||
2072 | VCPU(vcpu, lid) = VCPU_LID(vcpu); | ||
2073 | VCPU(vcpu, ivr) = 0; | ||
2074 | VCPU(vcpu, tpr) = 0x10000; | ||
2075 | VCPU(vcpu, eoi) = 0; | ||
2076 | VCPU(vcpu, irr[0]) = 0; | ||
2077 | VCPU(vcpu, irr[1]) = 0; | ||
2078 | VCPU(vcpu, irr[2]) = 0; | ||
2079 | VCPU(vcpu, irr[3]) = 0; | ||
2080 | VCPU(vcpu, pmv) = 0x10000; | ||
2081 | VCPU(vcpu, cmcv) = 0x10000; | ||
2082 | VCPU(vcpu, lrr0) = 0x10000; /* default reset value? */ | ||
2083 | VCPU(vcpu, lrr1) = 0x10000; /* default reset value? */ | ||
2084 | update_vhpi(vcpu, NULL_VECTOR); | ||
2085 | VLSAPIC_XTP(vcpu) = 0x80; /* disabled */ | ||
2086 | |||
2087 | for (i = 0; i < 4; i++) | ||
2088 | VLSAPIC_INSVC(vcpu, i) = 0; | ||
2089 | } | ||
2090 | |||
2091 | void kvm_init_all_rr(struct kvm_vcpu *vcpu) | ||
2092 | { | ||
2093 | unsigned long psr; | ||
2094 | |||
2095 | local_irq_save(psr); | ||
2096 | |||
2097 | /* WARNING: not allow co-exist of both virtual mode and physical | ||
2098 | * mode in same region | ||
2099 | */ | ||
2100 | |||
2101 | vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(VMX(vcpu, vrr[VRN0])); | ||
2102 | vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(VMX(vcpu, vrr[VRN4])); | ||
2103 | |||
2104 | if (is_physical_mode(vcpu)) { | ||
2105 | if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) | ||
2106 | panic_vm(vcpu); | ||
2107 | |||
2108 | ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->arch.metaphysical_rr0); | ||
2109 | ia64_dv_serialize_data(); | ||
2110 | ia64_set_rr((VRN4 << VRN_SHIFT), vcpu->arch.metaphysical_rr4); | ||
2111 | ia64_dv_serialize_data(); | ||
2112 | } else { | ||
2113 | ia64_set_rr((VRN0 << VRN_SHIFT), | ||
2114 | vcpu->arch.metaphysical_saved_rr0); | ||
2115 | ia64_dv_serialize_data(); | ||
2116 | ia64_set_rr((VRN4 << VRN_SHIFT), | ||
2117 | vcpu->arch.metaphysical_saved_rr4); | ||
2118 | ia64_dv_serialize_data(); | ||
2119 | } | ||
2120 | ia64_set_rr((VRN1 << VRN_SHIFT), | ||
2121 | vrrtomrr(VMX(vcpu, vrr[VRN1]))); | ||
2122 | ia64_dv_serialize_data(); | ||
2123 | ia64_set_rr((VRN2 << VRN_SHIFT), | ||
2124 | vrrtomrr(VMX(vcpu, vrr[VRN2]))); | ||
2125 | ia64_dv_serialize_data(); | ||
2126 | ia64_set_rr((VRN3 << VRN_SHIFT), | ||
2127 | vrrtomrr(VMX(vcpu, vrr[VRN3]))); | ||
2128 | ia64_dv_serialize_data(); | ||
2129 | ia64_set_rr((VRN5 << VRN_SHIFT), | ||
2130 | vrrtomrr(VMX(vcpu, vrr[VRN5]))); | ||
2131 | ia64_dv_serialize_data(); | ||
2132 | ia64_set_rr((VRN7 << VRN_SHIFT), | ||
2133 | vrrtomrr(VMX(vcpu, vrr[VRN7]))); | ||
2134 | ia64_dv_serialize_data(); | ||
2135 | ia64_srlz_d(); | ||
2136 | ia64_set_psr(psr); | ||
2137 | } | ||
2138 | |||
2139 | int vmm_entry(void) | ||
2140 | { | ||
2141 | struct kvm_vcpu *v; | ||
2142 | v = current_vcpu; | ||
2143 | |||
2144 | ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)v->arch.vpd, | ||
2145 | 0, 0, 0, 0, 0, 0); | ||
2146 | kvm_init_vtlb(v); | ||
2147 | kvm_init_vhpt(v); | ||
2148 | init_vcpu(v); | ||
2149 | kvm_init_all_rr(v); | ||
2150 | vmm_reset_entry(); | ||
2151 | |||
2152 | return 0; | ||
2153 | } | ||
2154 | |||
2155 | void panic_vm(struct kvm_vcpu *v) | ||
2156 | { | ||
2157 | struct exit_ctl_data *p = &v->arch.exit_data; | ||
2158 | |||
2159 | p->exit_reason = EXIT_REASON_VM_PANIC; | ||
2160 | vmm_transition(v); | ||
2161 | /*Never to return*/ | ||
2162 | while (1); | ||
2163 | } | ||
diff --git a/arch/ia64/kvm/vcpu.h b/arch/ia64/kvm/vcpu.h new file mode 100644 index 000000000000..b0fcfb62c49e --- /dev/null +++ b/arch/ia64/kvm/vcpu.h | |||
@@ -0,0 +1,740 @@ | |||
1 | /* | ||
2 | * vcpu.h: vcpu routines | ||
3 | * Copyright (c) 2005, Intel Corporation. | ||
4 | * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) | ||
5 | * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com) | ||
6 | * | ||
7 | * Copyright (c) 2007, Intel Corporation. | ||
8 | * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) | ||
9 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms and conditions of the GNU General Public License, | ||
13 | * version 2, as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along with | ||
21 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
22 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #ifndef __KVM_VCPU_H__ | ||
28 | #define __KVM_VCPU_H__ | ||
29 | |||
30 | #include <asm/types.h> | ||
31 | #include <asm/fpu.h> | ||
32 | #include <asm/processor.h> | ||
33 | |||
34 | #ifndef __ASSEMBLY__ | ||
35 | #include "vti.h" | ||
36 | |||
37 | #include <linux/kvm_host.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | |||
40 | typedef unsigned long IA64_INST; | ||
41 | |||
42 | typedef union U_IA64_BUNDLE { | ||
43 | unsigned long i64[2]; | ||
44 | struct { unsigned long template:5, slot0:41, slot1a:18, | ||
45 | slot1b:23, slot2:41; }; | ||
46 | /* NOTE: following doesn't work because bitfields can't cross natural | ||
47 | size boundaries | ||
48 | struct { unsigned long template:5, slot0:41, slot1:41, slot2:41; }; */ | ||
49 | } IA64_BUNDLE; | ||
50 | |||
51 | typedef union U_INST64_A5 { | ||
52 | IA64_INST inst; | ||
53 | struct { unsigned long qp:6, r1:7, imm7b:7, r3:2, imm5c:5, | ||
54 | imm9d:9, s:1, major:4; }; | ||
55 | } INST64_A5; | ||
56 | |||
57 | typedef union U_INST64_B4 { | ||
58 | IA64_INST inst; | ||
59 | struct { unsigned long qp:6, btype:3, un3:3, p:1, b2:3, un11:11, x6:6, | ||
60 | wh:2, d:1, un1:1, major:4; }; | ||
61 | } INST64_B4; | ||
62 | |||
63 | typedef union U_INST64_B8 { | ||
64 | IA64_INST inst; | ||
65 | struct { unsigned long qp:6, un21:21, x6:6, un4:4, major:4; }; | ||
66 | } INST64_B8; | ||
67 | |||
68 | typedef union U_INST64_B9 { | ||
69 | IA64_INST inst; | ||
70 | struct { unsigned long qp:6, imm20:20, :1, x6:6, :3, i:1, major:4; }; | ||
71 | } INST64_B9; | ||
72 | |||
73 | typedef union U_INST64_I19 { | ||
74 | IA64_INST inst; | ||
75 | struct { unsigned long qp:6, imm20:20, :1, x6:6, x3:3, i:1, major:4; }; | ||
76 | } INST64_I19; | ||
77 | |||
78 | typedef union U_INST64_I26 { | ||
79 | IA64_INST inst; | ||
80 | struct { unsigned long qp:6, :7, r2:7, ar3:7, x6:6, x3:3, :1, major:4; }; | ||
81 | } INST64_I26; | ||
82 | |||
83 | typedef union U_INST64_I27 { | ||
84 | IA64_INST inst; | ||
85 | struct { unsigned long qp:6, :7, imm:7, ar3:7, x6:6, x3:3, s:1, major:4; }; | ||
86 | } INST64_I27; | ||
87 | |||
88 | typedef union U_INST64_I28 { /* not privileged (mov from AR) */ | ||
89 | IA64_INST inst; | ||
90 | struct { unsigned long qp:6, r1:7, :7, ar3:7, x6:6, x3:3, :1, major:4; }; | ||
91 | } INST64_I28; | ||
92 | |||
93 | typedef union U_INST64_M28 { | ||
94 | IA64_INST inst; | ||
95 | struct { unsigned long qp:6, :14, r3:7, x6:6, x3:3, :1, major:4; }; | ||
96 | } INST64_M28; | ||
97 | |||
98 | typedef union U_INST64_M29 { | ||
99 | IA64_INST inst; | ||
100 | struct { unsigned long qp:6, :7, r2:7, ar3:7, x6:6, x3:3, :1, major:4; }; | ||
101 | } INST64_M29; | ||
102 | |||
103 | typedef union U_INST64_M30 { | ||
104 | IA64_INST inst; | ||
105 | struct { unsigned long qp:6, :7, imm:7, ar3:7, x4:4, x2:2, | ||
106 | x3:3, s:1, major:4; }; | ||
107 | } INST64_M30; | ||
108 | |||
109 | typedef union U_INST64_M31 { | ||
110 | IA64_INST inst; | ||
111 | struct { unsigned long qp:6, r1:7, :7, ar3:7, x6:6, x3:3, :1, major:4; }; | ||
112 | } INST64_M31; | ||
113 | |||
114 | typedef union U_INST64_M32 { | ||
115 | IA64_INST inst; | ||
116 | struct { unsigned long qp:6, :7, r2:7, cr3:7, x6:6, x3:3, :1, major:4; }; | ||
117 | } INST64_M32; | ||
118 | |||
119 | typedef union U_INST64_M33 { | ||
120 | IA64_INST inst; | ||
121 | struct { unsigned long qp:6, r1:7, :7, cr3:7, x6:6, x3:3, :1, major:4; }; | ||
122 | } INST64_M33; | ||
123 | |||
124 | typedef union U_INST64_M35 { | ||
125 | IA64_INST inst; | ||
126 | struct { unsigned long qp:6, :7, r2:7, :7, x6:6, x3:3, :1, major:4; }; | ||
127 | |||
128 | } INST64_M35; | ||
129 | |||
130 | typedef union U_INST64_M36 { | ||
131 | IA64_INST inst; | ||
132 | struct { unsigned long qp:6, r1:7, :14, x6:6, x3:3, :1, major:4; }; | ||
133 | } INST64_M36; | ||
134 | |||
135 | typedef union U_INST64_M37 { | ||
136 | IA64_INST inst; | ||
137 | struct { unsigned long qp:6, imm20a:20, :1, x4:4, x2:2, x3:3, | ||
138 | i:1, major:4; }; | ||
139 | } INST64_M37; | ||
140 | |||
141 | typedef union U_INST64_M41 { | ||
142 | IA64_INST inst; | ||
143 | struct { unsigned long qp:6, :7, r2:7, :7, x6:6, x3:3, :1, major:4; }; | ||
144 | } INST64_M41; | ||
145 | |||
146 | typedef union U_INST64_M42 { | ||
147 | IA64_INST inst; | ||
148 | struct { unsigned long qp:6, :7, r2:7, r3:7, x6:6, x3:3, :1, major:4; }; | ||
149 | } INST64_M42; | ||
150 | |||
151 | typedef union U_INST64_M43 { | ||
152 | IA64_INST inst; | ||
153 | struct { unsigned long qp:6, r1:7, :7, r3:7, x6:6, x3:3, :1, major:4; }; | ||
154 | } INST64_M43; | ||
155 | |||
156 | typedef union U_INST64_M44 { | ||
157 | IA64_INST inst; | ||
158 | struct { unsigned long qp:6, imm:21, x4:4, i2:2, x3:3, i:1, major:4; }; | ||
159 | } INST64_M44; | ||
160 | |||
161 | typedef union U_INST64_M45 { | ||
162 | IA64_INST inst; | ||
163 | struct { unsigned long qp:6, :7, r2:7, r3:7, x6:6, x3:3, :1, major:4; }; | ||
164 | } INST64_M45; | ||
165 | |||
166 | typedef union U_INST64_M46 { | ||
167 | IA64_INST inst; | ||
168 | struct { unsigned long qp:6, r1:7, un7:7, r3:7, x6:6, | ||
169 | x3:3, un1:1, major:4; }; | ||
170 | } INST64_M46; | ||
171 | |||
172 | typedef union U_INST64_M47 { | ||
173 | IA64_INST inst; | ||
174 | struct { unsigned long qp:6, un14:14, r3:7, x6:6, x3:3, un1:1, major:4; }; | ||
175 | } INST64_M47; | ||
176 | |||
177 | typedef union U_INST64_M1{ | ||
178 | IA64_INST inst; | ||
179 | struct { unsigned long qp:6, r1:7, un7:7, r3:7, x:1, hint:2, | ||
180 | x6:6, m:1, major:4; }; | ||
181 | } INST64_M1; | ||
182 | |||
183 | typedef union U_INST64_M2{ | ||
184 | IA64_INST inst; | ||
185 | struct { unsigned long qp:6, r1:7, r2:7, r3:7, x:1, hint:2, | ||
186 | x6:6, m:1, major:4; }; | ||
187 | } INST64_M2; | ||
188 | |||
189 | typedef union U_INST64_M3{ | ||
190 | IA64_INST inst; | ||
191 | struct { unsigned long qp:6, r1:7, imm7:7, r3:7, i:1, hint:2, | ||
192 | x6:6, s:1, major:4; }; | ||
193 | } INST64_M3; | ||
194 | |||
195 | typedef union U_INST64_M4 { | ||
196 | IA64_INST inst; | ||
197 | struct { unsigned long qp:6, un7:7, r2:7, r3:7, x:1, hint:2, | ||
198 | x6:6, m:1, major:4; }; | ||
199 | } INST64_M4; | ||
200 | |||
201 | typedef union U_INST64_M5 { | ||
202 | IA64_INST inst; | ||
203 | struct { unsigned long qp:6, imm7:7, r2:7, r3:7, i:1, hint:2, | ||
204 | x6:6, s:1, major:4; }; | ||
205 | } INST64_M5; | ||
206 | |||
207 | typedef union U_INST64_M6 { | ||
208 | IA64_INST inst; | ||
209 | struct { unsigned long qp:6, f1:7, un7:7, r3:7, x:1, hint:2, | ||
210 | x6:6, m:1, major:4; }; | ||
211 | } INST64_M6; | ||
212 | |||
213 | typedef union U_INST64_M9 { | ||
214 | IA64_INST inst; | ||
215 | struct { unsigned long qp:6, :7, f2:7, r3:7, x:1, hint:2, | ||
216 | x6:6, m:1, major:4; }; | ||
217 | } INST64_M9; | ||
218 | |||
219 | typedef union U_INST64_M10 { | ||
220 | IA64_INST inst; | ||
221 | struct { unsigned long qp:6, imm7:7, f2:7, r3:7, i:1, hint:2, | ||
222 | x6:6, s:1, major:4; }; | ||
223 | } INST64_M10; | ||
224 | |||
225 | typedef union U_INST64_M12 { | ||
226 | IA64_INST inst; | ||
227 | struct { unsigned long qp:6, f1:7, f2:7, r3:7, x:1, hint:2, | ||
228 | x6:6, m:1, major:4; }; | ||
229 | } INST64_M12; | ||
230 | |||
231 | typedef union U_INST64_M15 { | ||
232 | IA64_INST inst; | ||
233 | struct { unsigned long qp:6, :7, imm7:7, r3:7, i:1, hint:2, | ||
234 | x6:6, s:1, major:4; }; | ||
235 | } INST64_M15; | ||
236 | |||
237 | typedef union U_INST64 { | ||
238 | IA64_INST inst; | ||
239 | struct { unsigned long :37, major:4; } generic; | ||
240 | INST64_A5 A5; /* used in build_hypercall_bundle only */ | ||
241 | INST64_B4 B4; /* used in build_hypercall_bundle only */ | ||
242 | INST64_B8 B8; /* rfi, bsw.[01] */ | ||
243 | INST64_B9 B9; /* break.b */ | ||
244 | INST64_I19 I19; /* used in build_hypercall_bundle only */ | ||
245 | INST64_I26 I26; /* mov register to ar (I unit) */ | ||
246 | INST64_I27 I27; /* mov immediate to ar (I unit) */ | ||
247 | INST64_I28 I28; /* mov from ar (I unit) */ | ||
248 | INST64_M1 M1; /* ld integer */ | ||
249 | INST64_M2 M2; | ||
250 | INST64_M3 M3; | ||
251 | INST64_M4 M4; /* st integer */ | ||
252 | INST64_M5 M5; | ||
253 | INST64_M6 M6; /* ldfd floating pointer */ | ||
254 | INST64_M9 M9; /* stfd floating pointer */ | ||
255 | INST64_M10 M10; /* stfd floating pointer */ | ||
256 | INST64_M12 M12; /* ldfd pair floating pointer */ | ||
257 | INST64_M15 M15; /* lfetch + imm update */ | ||
258 | INST64_M28 M28; /* purge translation cache entry */ | ||
259 | INST64_M29 M29; /* mov register to ar (M unit) */ | ||
260 | INST64_M30 M30; /* mov immediate to ar (M unit) */ | ||
261 | INST64_M31 M31; /* mov from ar (M unit) */ | ||
262 | INST64_M32 M32; /* mov reg to cr */ | ||
263 | INST64_M33 M33; /* mov from cr */ | ||
264 | INST64_M35 M35; /* mov to psr */ | ||
265 | INST64_M36 M36; /* mov from psr */ | ||
266 | INST64_M37 M37; /* break.m */ | ||
267 | INST64_M41 M41; /* translation cache insert */ | ||
268 | INST64_M42 M42; /* mov to indirect reg/translation reg insert*/ | ||
269 | INST64_M43 M43; /* mov from indirect reg */ | ||
270 | INST64_M44 M44; /* set/reset system mask */ | ||
271 | INST64_M45 M45; /* translation purge */ | ||
272 | INST64_M46 M46; /* translation access (tpa,tak) */ | ||
273 | INST64_M47 M47; /* purge translation entry */ | ||
274 | } INST64; | ||
275 | |||
276 | #define MASK_41 ((unsigned long)0x1ffffffffff) | ||
277 | |||
278 | /* Virtual address memory attributes encoding */ | ||
279 | #define VA_MATTR_WB 0x0 | ||
280 | #define VA_MATTR_UC 0x4 | ||
281 | #define VA_MATTR_UCE 0x5 | ||
282 | #define VA_MATTR_WC 0x6 | ||
283 | #define VA_MATTR_NATPAGE 0x7 | ||
284 | |||
285 | #define PMASK(size) (~((size) - 1)) | ||
286 | #define PSIZE(size) (1UL<<(size)) | ||
287 | #define CLEARLSB(ppn, nbits) (((ppn) >> (nbits)) << (nbits)) | ||
288 | #define PAGEALIGN(va, ps) CLEARLSB(va, ps) | ||
289 | #define PAGE_FLAGS_RV_MASK (0x2|(0x3UL<<50)|(((1UL<<11)-1)<<53)) | ||
290 | #define _PAGE_MA_ST (0x1 << 2) /* is reserved for software use */ | ||
291 | |||
292 | #define ARCH_PAGE_SHIFT 12 | ||
293 | |||
294 | #define INVALID_TI_TAG (1UL << 63) | ||
295 | |||
296 | #define VTLB_PTE_P_BIT 0 | ||
297 | #define VTLB_PTE_IO_BIT 60 | ||
298 | #define VTLB_PTE_IO (1UL<<VTLB_PTE_IO_BIT) | ||
299 | #define VTLB_PTE_P (1UL<<VTLB_PTE_P_BIT) | ||
300 | |||
301 | #define vcpu_quick_region_check(_tr_regions,_ifa) \ | ||
302 | (_tr_regions & (1 << ((unsigned long)_ifa >> 61))) | ||
303 | |||
304 | #define vcpu_quick_region_set(_tr_regions,_ifa) \ | ||
305 | do {_tr_regions |= (1 << ((unsigned long)_ifa >> 61)); } while (0) | ||
306 | |||
307 | static inline void vcpu_set_tr(struct thash_data *trp, u64 pte, u64 itir, | ||
308 | u64 va, u64 rid) | ||
309 | { | ||
310 | trp->page_flags = pte; | ||
311 | trp->itir = itir; | ||
312 | trp->vadr = va; | ||
313 | trp->rid = rid; | ||
314 | } | ||
315 | |||
316 | extern u64 kvm_lookup_mpa(u64 gpfn); | ||
317 | extern u64 kvm_gpa_to_mpa(u64 gpa); | ||
318 | |||
319 | /* Return I/O type if trye */ | ||
320 | #define __gpfn_is_io(gpfn) \ | ||
321 | ({ \ | ||
322 | u64 pte, ret = 0; \ | ||
323 | pte = kvm_lookup_mpa(gpfn); \ | ||
324 | if (!(pte & GPFN_INV_MASK)) \ | ||
325 | ret = pte & GPFN_IO_MASK; \ | ||
326 | ret; \ | ||
327 | }) | ||
328 | |||
329 | #endif | ||
330 | |||
331 | #define IA64_NO_FAULT 0 | ||
332 | #define IA64_FAULT 1 | ||
333 | |||
334 | #define VMM_RBS_OFFSET ((VMM_TASK_SIZE + 15) & ~15) | ||
335 | |||
336 | #define SW_BAD 0 /* Bad mode transitition */ | ||
337 | #define SW_V2P 1 /* Physical emulatino is activated */ | ||
338 | #define SW_P2V 2 /* Exit physical mode emulation */ | ||
339 | #define SW_SELF 3 /* No mode transition */ | ||
340 | #define SW_NOP 4 /* Mode transition, but without action required */ | ||
341 | |||
342 | #define GUEST_IN_PHY 0x1 | ||
343 | #define GUEST_PHY_EMUL 0x2 | ||
344 | |||
345 | #define current_vcpu ((struct kvm_vcpu *) ia64_getreg(_IA64_REG_TP)) | ||
346 | |||
347 | #define VRN_SHIFT 61 | ||
348 | #define VRN_MASK 0xe000000000000000 | ||
349 | #define VRN0 0x0UL | ||
350 | #define VRN1 0x1UL | ||
351 | #define VRN2 0x2UL | ||
352 | #define VRN3 0x3UL | ||
353 | #define VRN4 0x4UL | ||
354 | #define VRN5 0x5UL | ||
355 | #define VRN6 0x6UL | ||
356 | #define VRN7 0x7UL | ||
357 | |||
358 | #define IRQ_NO_MASKED 0 | ||
359 | #define IRQ_MASKED_BY_VTPR 1 | ||
360 | #define IRQ_MASKED_BY_INSVC 2 /* masked by inservice IRQ */ | ||
361 | |||
362 | #define PTA_BASE_SHIFT 15 | ||
363 | |||
364 | #define IA64_PSR_VM_BIT 46 | ||
365 | #define IA64_PSR_VM (__IA64_UL(1) << IA64_PSR_VM_BIT) | ||
366 | |||
367 | /* Interruption Function State */ | ||
368 | #define IA64_IFS_V_BIT 63 | ||
369 | #define IA64_IFS_V (__IA64_UL(1) << IA64_IFS_V_BIT) | ||
370 | |||
371 | #define PHY_PAGE_UC (_PAGE_A|_PAGE_D|_PAGE_P|_PAGE_MA_UC|_PAGE_AR_RWX) | ||
372 | #define PHY_PAGE_WB (_PAGE_A|_PAGE_D|_PAGE_P|_PAGE_MA_WB|_PAGE_AR_RWX) | ||
373 | |||
374 | #ifndef __ASSEMBLY__ | ||
375 | |||
376 | #include <asm/gcc_intrin.h> | ||
377 | |||
378 | #define is_physical_mode(v) \ | ||
379 | ((v->arch.mode_flags) & GUEST_IN_PHY) | ||
380 | |||
381 | #define is_virtual_mode(v) \ | ||
382 | (!is_physical_mode(v)) | ||
383 | |||
384 | #define MODE_IND(psr) \ | ||
385 | (((psr).it << 2) + ((psr).dt << 1) + (psr).rt) | ||
386 | |||
387 | #define _vmm_raw_spin_lock(x) \ | ||
388 | do { \ | ||
389 | __u32 *ia64_spinlock_ptr = (__u32 *) (x); \ | ||
390 | __u64 ia64_spinlock_val; \ | ||
391 | ia64_spinlock_val = ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0);\ | ||
392 | if (unlikely(ia64_spinlock_val)) { \ | ||
393 | do { \ | ||
394 | while (*ia64_spinlock_ptr) \ | ||
395 | ia64_barrier(); \ | ||
396 | ia64_spinlock_val = \ | ||
397 | ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0);\ | ||
398 | } while (ia64_spinlock_val); \ | ||
399 | } \ | ||
400 | } while (0) | ||
401 | |||
402 | #define _vmm_raw_spin_unlock(x) \ | ||
403 | do { barrier(); \ | ||
404 | ((spinlock_t *)x)->raw_lock.lock = 0; } \ | ||
405 | while (0) | ||
406 | |||
407 | void vmm_spin_lock(spinlock_t *lock); | ||
408 | void vmm_spin_unlock(spinlock_t *lock); | ||
409 | enum { | ||
410 | I_TLB = 1, | ||
411 | D_TLB = 2 | ||
412 | }; | ||
413 | |||
414 | union kvm_va { | ||
415 | struct { | ||
416 | unsigned long off : 60; /* intra-region offset */ | ||
417 | unsigned long reg : 4; /* region number */ | ||
418 | } f; | ||
419 | unsigned long l; | ||
420 | void *p; | ||
421 | }; | ||
422 | |||
423 | #define __kvm_pa(x) ({union kvm_va _v; _v.l = (long) (x); \ | ||
424 | _v.f.reg = 0; _v.l; }) | ||
425 | #define __kvm_va(x) ({union kvm_va _v; _v.l = (long) (x); \ | ||
426 | _v.f.reg = -1; _v.p; }) | ||
427 | |||
428 | #define _REGION_ID(x) ({union ia64_rr _v; _v.val = (long)(x); \ | ||
429 | _v.rid; }) | ||
430 | #define _REGION_PAGE_SIZE(x) ({union ia64_rr _v; _v.val = (long)(x); \ | ||
431 | _v.ps; }) | ||
432 | #define _REGION_HW_WALKER(x) ({union ia64_rr _v; _v.val = (long)(x); \ | ||
433 | _v.ve; }) | ||
434 | |||
435 | enum vhpt_ref{ DATA_REF, NA_REF, INST_REF, RSE_REF }; | ||
436 | enum tlb_miss_type { INSTRUCTION, DATA, REGISTER }; | ||
437 | |||
438 | #define VCPU(_v, _x) ((_v)->arch.vpd->_x) | ||
439 | #define VMX(_v, _x) ((_v)->arch._x) | ||
440 | |||
441 | #define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i]) | ||
442 | #define VLSAPIC_XTP(_v) VMX(_v, xtp) | ||
443 | |||
444 | static inline unsigned long itir_ps(unsigned long itir) | ||
445 | { | ||
446 | return ((itir >> 2) & 0x3f); | ||
447 | } | ||
448 | |||
449 | |||
450 | /************************************************************************** | ||
451 | VCPU control register access routines | ||
452 | **************************************************************************/ | ||
453 | |||
454 | static inline u64 vcpu_get_itir(struct kvm_vcpu *vcpu) | ||
455 | { | ||
456 | return ((u64)VCPU(vcpu, itir)); | ||
457 | } | ||
458 | |||
459 | static inline void vcpu_set_itir(struct kvm_vcpu *vcpu, u64 val) | ||
460 | { | ||
461 | VCPU(vcpu, itir) = val; | ||
462 | } | ||
463 | |||
464 | static inline u64 vcpu_get_ifa(struct kvm_vcpu *vcpu) | ||
465 | { | ||
466 | return ((u64)VCPU(vcpu, ifa)); | ||
467 | } | ||
468 | |||
469 | static inline void vcpu_set_ifa(struct kvm_vcpu *vcpu, u64 val) | ||
470 | { | ||
471 | VCPU(vcpu, ifa) = val; | ||
472 | } | ||
473 | |||
474 | static inline u64 vcpu_get_iva(struct kvm_vcpu *vcpu) | ||
475 | { | ||
476 | return ((u64)VCPU(vcpu, iva)); | ||
477 | } | ||
478 | |||
479 | static inline u64 vcpu_get_pta(struct kvm_vcpu *vcpu) | ||
480 | { | ||
481 | return ((u64)VCPU(vcpu, pta)); | ||
482 | } | ||
483 | |||
484 | static inline u64 vcpu_get_lid(struct kvm_vcpu *vcpu) | ||
485 | { | ||
486 | return ((u64)VCPU(vcpu, lid)); | ||
487 | } | ||
488 | |||
489 | static inline u64 vcpu_get_tpr(struct kvm_vcpu *vcpu) | ||
490 | { | ||
491 | return ((u64)VCPU(vcpu, tpr)); | ||
492 | } | ||
493 | |||
494 | static inline u64 vcpu_get_eoi(struct kvm_vcpu *vcpu) | ||
495 | { | ||
496 | return (0UL); /*reads of eoi always return 0 */ | ||
497 | } | ||
498 | |||
499 | static inline u64 vcpu_get_irr0(struct kvm_vcpu *vcpu) | ||
500 | { | ||
501 | return ((u64)VCPU(vcpu, irr[0])); | ||
502 | } | ||
503 | |||
504 | static inline u64 vcpu_get_irr1(struct kvm_vcpu *vcpu) | ||
505 | { | ||
506 | return ((u64)VCPU(vcpu, irr[1])); | ||
507 | } | ||
508 | |||
509 | static inline u64 vcpu_get_irr2(struct kvm_vcpu *vcpu) | ||
510 | { | ||
511 | return ((u64)VCPU(vcpu, irr[2])); | ||
512 | } | ||
513 | |||
514 | static inline u64 vcpu_get_irr3(struct kvm_vcpu *vcpu) | ||
515 | { | ||
516 | return ((u64)VCPU(vcpu, irr[3])); | ||
517 | } | ||
518 | |||
519 | static inline void vcpu_set_dcr(struct kvm_vcpu *vcpu, u64 val) | ||
520 | { | ||
521 | ia64_setreg(_IA64_REG_CR_DCR, val); | ||
522 | } | ||
523 | |||
524 | static inline void vcpu_set_isr(struct kvm_vcpu *vcpu, u64 val) | ||
525 | { | ||
526 | VCPU(vcpu, isr) = val; | ||
527 | } | ||
528 | |||
529 | static inline void vcpu_set_lid(struct kvm_vcpu *vcpu, u64 val) | ||
530 | { | ||
531 | VCPU(vcpu, lid) = val; | ||
532 | } | ||
533 | |||
534 | static inline void vcpu_set_ipsr(struct kvm_vcpu *vcpu, u64 val) | ||
535 | { | ||
536 | VCPU(vcpu, ipsr) = val; | ||
537 | } | ||
538 | |||
539 | static inline void vcpu_set_iip(struct kvm_vcpu *vcpu, u64 val) | ||
540 | { | ||
541 | VCPU(vcpu, iip) = val; | ||
542 | } | ||
543 | |||
544 | static inline void vcpu_set_ifs(struct kvm_vcpu *vcpu, u64 val) | ||
545 | { | ||
546 | VCPU(vcpu, ifs) = val; | ||
547 | } | ||
548 | |||
549 | static inline void vcpu_set_iipa(struct kvm_vcpu *vcpu, u64 val) | ||
550 | { | ||
551 | VCPU(vcpu, iipa) = val; | ||
552 | } | ||
553 | |||
554 | static inline void vcpu_set_iha(struct kvm_vcpu *vcpu, u64 val) | ||
555 | { | ||
556 | VCPU(vcpu, iha) = val; | ||
557 | } | ||
558 | |||
559 | |||
560 | static inline u64 vcpu_get_rr(struct kvm_vcpu *vcpu, u64 reg) | ||
561 | { | ||
562 | return vcpu->arch.vrr[reg>>61]; | ||
563 | } | ||
564 | |||
565 | /************************************************************************** | ||
566 | VCPU debug breakpoint register access routines | ||
567 | **************************************************************************/ | ||
568 | |||
569 | static inline void vcpu_set_dbr(struct kvm_vcpu *vcpu, u64 reg, u64 val) | ||
570 | { | ||
571 | __ia64_set_dbr(reg, val); | ||
572 | } | ||
573 | |||
574 | static inline void vcpu_set_ibr(struct kvm_vcpu *vcpu, u64 reg, u64 val) | ||
575 | { | ||
576 | ia64_set_ibr(reg, val); | ||
577 | } | ||
578 | |||
579 | static inline u64 vcpu_get_dbr(struct kvm_vcpu *vcpu, u64 reg) | ||
580 | { | ||
581 | return ((u64)__ia64_get_dbr(reg)); | ||
582 | } | ||
583 | |||
584 | static inline u64 vcpu_get_ibr(struct kvm_vcpu *vcpu, u64 reg) | ||
585 | { | ||
586 | return ((u64)ia64_get_ibr(reg)); | ||
587 | } | ||
588 | |||
589 | /************************************************************************** | ||
590 | VCPU performance monitor register access routines | ||
591 | **************************************************************************/ | ||
592 | static inline void vcpu_set_pmc(struct kvm_vcpu *vcpu, u64 reg, u64 val) | ||
593 | { | ||
594 | /* NOTE: Writes to unimplemented PMC registers are discarded */ | ||
595 | ia64_set_pmc(reg, val); | ||
596 | } | ||
597 | |||
598 | static inline void vcpu_set_pmd(struct kvm_vcpu *vcpu, u64 reg, u64 val) | ||
599 | { | ||
600 | /* NOTE: Writes to unimplemented PMD registers are discarded */ | ||
601 | ia64_set_pmd(reg, val); | ||
602 | } | ||
603 | |||
604 | static inline u64 vcpu_get_pmc(struct kvm_vcpu *vcpu, u64 reg) | ||
605 | { | ||
606 | /* NOTE: Reads from unimplemented PMC registers return zero */ | ||
607 | return ((u64)ia64_get_pmc(reg)); | ||
608 | } | ||
609 | |||
610 | static inline u64 vcpu_get_pmd(struct kvm_vcpu *vcpu, u64 reg) | ||
611 | { | ||
612 | /* NOTE: Reads from unimplemented PMD registers return zero */ | ||
613 | return ((u64)ia64_get_pmd(reg)); | ||
614 | } | ||
615 | |||
616 | static inline unsigned long vrrtomrr(unsigned long val) | ||
617 | { | ||
618 | union ia64_rr rr; | ||
619 | rr.val = val; | ||
620 | rr.rid = (rr.rid << 4) | 0xe; | ||
621 | if (rr.ps > PAGE_SHIFT) | ||
622 | rr.ps = PAGE_SHIFT; | ||
623 | rr.ve = 1; | ||
624 | return rr.val; | ||
625 | } | ||
626 | |||
627 | |||
628 | static inline int highest_bits(int *dat) | ||
629 | { | ||
630 | u32 bits, bitnum; | ||
631 | int i; | ||
632 | |||
633 | /* loop for all 256 bits */ | ||
634 | for (i = 7; i >= 0 ; i--) { | ||
635 | bits = dat[i]; | ||
636 | if (bits) { | ||
637 | bitnum = fls(bits); | ||
638 | return i * 32 + bitnum - 1; | ||
639 | } | ||
640 | } | ||
641 | return NULL_VECTOR; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * The pending irq is higher than the inservice one. | ||
646 | * | ||
647 | */ | ||
648 | static inline int is_higher_irq(int pending, int inservice) | ||
649 | { | ||
650 | return ((pending > inservice) | ||
651 | || ((pending != NULL_VECTOR) | ||
652 | && (inservice == NULL_VECTOR))); | ||
653 | } | ||
654 | |||
655 | static inline int is_higher_class(int pending, int mic) | ||
656 | { | ||
657 | return ((pending >> 4) > mic); | ||
658 | } | ||
659 | |||
660 | /* | ||
661 | * Return 0-255 for pending irq. | ||
662 | * NULL_VECTOR: when no pending. | ||
663 | */ | ||
664 | static inline int highest_pending_irq(struct kvm_vcpu *vcpu) | ||
665 | { | ||
666 | if (VCPU(vcpu, irr[0]) & (1UL<<NMI_VECTOR)) | ||
667 | return NMI_VECTOR; | ||
668 | if (VCPU(vcpu, irr[0]) & (1UL<<ExtINT_VECTOR)) | ||
669 | return ExtINT_VECTOR; | ||
670 | |||
671 | return highest_bits((int *)&VCPU(vcpu, irr[0])); | ||
672 | } | ||
673 | |||
674 | static inline int highest_inservice_irq(struct kvm_vcpu *vcpu) | ||
675 | { | ||
676 | if (VMX(vcpu, insvc[0]) & (1UL<<NMI_VECTOR)) | ||
677 | return NMI_VECTOR; | ||
678 | if (VMX(vcpu, insvc[0]) & (1UL<<ExtINT_VECTOR)) | ||
679 | return ExtINT_VECTOR; | ||
680 | |||
681 | return highest_bits((int *)&(VMX(vcpu, insvc[0]))); | ||
682 | } | ||
683 | |||
684 | extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, u64 reg, | ||
685 | struct ia64_fpreg *val); | ||
686 | extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, u64 reg, | ||
687 | struct ia64_fpreg *val); | ||
688 | extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, u64 reg); | ||
689 | extern void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 val, int nat); | ||
690 | extern u64 vcpu_get_psr(struct kvm_vcpu *vcpu); | ||
691 | extern void vcpu_set_psr(struct kvm_vcpu *vcpu, u64 val); | ||
692 | extern u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr); | ||
693 | extern void vcpu_bsw0(struct kvm_vcpu *vcpu); | ||
694 | extern void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, | ||
695 | u64 itir, u64 va, int type); | ||
696 | extern struct thash_data *vhpt_lookup(u64 va); | ||
697 | extern u64 guest_vhpt_lookup(u64 iha, u64 *pte); | ||
698 | extern void thash_purge_entries(struct kvm_vcpu *v, u64 va, u64 ps); | ||
699 | extern void thash_purge_entries_remote(struct kvm_vcpu *v, u64 va, u64 ps); | ||
700 | extern u64 translate_phy_pte(u64 *pte, u64 itir, u64 va); | ||
701 | extern int thash_purge_and_insert(struct kvm_vcpu *v, u64 pte, | ||
702 | u64 itir, u64 ifa, int type); | ||
703 | extern void thash_purge_all(struct kvm_vcpu *v); | ||
704 | extern struct thash_data *vtlb_lookup(struct kvm_vcpu *v, | ||
705 | u64 va, int is_data); | ||
706 | extern int vtr_find_overlap(struct kvm_vcpu *vcpu, u64 va, | ||
707 | u64 ps, int is_data); | ||
708 | |||
709 | extern void vcpu_increment_iip(struct kvm_vcpu *v); | ||
710 | extern void vcpu_decrement_iip(struct kvm_vcpu *vcpu); | ||
711 | extern void vcpu_pend_interrupt(struct kvm_vcpu *vcpu, u8 vec); | ||
712 | extern void vcpu_unpend_interrupt(struct kvm_vcpu *vcpu, u8 vec); | ||
713 | extern void data_page_not_present(struct kvm_vcpu *vcpu, u64 vadr); | ||
714 | extern void dnat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr); | ||
715 | extern void alt_dtlb(struct kvm_vcpu *vcpu, u64 vadr); | ||
716 | extern void nested_dtlb(struct kvm_vcpu *vcpu); | ||
717 | extern void dvhpt_fault(struct kvm_vcpu *vcpu, u64 vadr); | ||
718 | extern int vhpt_enabled(struct kvm_vcpu *vcpu, u64 vadr, enum vhpt_ref ref); | ||
719 | |||
720 | extern void update_vhpi(struct kvm_vcpu *vcpu, int vec); | ||
721 | extern int irq_masked(struct kvm_vcpu *vcpu, int h_pending, int h_inservice); | ||
722 | |||
723 | extern int fetch_code(struct kvm_vcpu *vcpu, u64 gip, IA64_BUNDLE *pbundle); | ||
724 | extern void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma); | ||
725 | extern void vmm_transition(struct kvm_vcpu *vcpu); | ||
726 | extern void vmm_trampoline(union context *from, union context *to); | ||
727 | extern int vmm_entry(void); | ||
728 | extern u64 vcpu_get_itc(struct kvm_vcpu *vcpu); | ||
729 | |||
730 | extern void vmm_reset_entry(void); | ||
731 | void kvm_init_vtlb(struct kvm_vcpu *v); | ||
732 | void kvm_init_vhpt(struct kvm_vcpu *v); | ||
733 | void thash_init(struct thash_cb *hcb, u64 sz); | ||
734 | |||
735 | void panic_vm(struct kvm_vcpu *v); | ||
736 | |||
737 | extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2, u64 arg3, | ||
738 | u64 arg4, u64 arg5, u64 arg6, u64 arg7); | ||
739 | #endif | ||
740 | #endif /* __VCPU_H__ */ | ||
diff --git a/arch/ia64/kvm/vmm.c b/arch/ia64/kvm/vmm.c new file mode 100644 index 000000000000..2275bf4e681a --- /dev/null +++ b/arch/ia64/kvm/vmm.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * vmm.c: vmm module interface with kvm module | ||
3 | * | ||
4 | * Copyright (c) 2007, Intel Corporation. | ||
5 | * | ||
6 | * Xiantao Zhang (xiantao.zhang@intel.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
19 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
20 | */ | ||
21 | |||
22 | |||
23 | #include<linux/module.h> | ||
24 | #include<asm/fpswa.h> | ||
25 | |||
26 | #include "vcpu.h" | ||
27 | |||
28 | MODULE_AUTHOR("Intel"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | extern char kvm_ia64_ivt; | ||
32 | extern fpswa_interface_t *vmm_fpswa_interface; | ||
33 | |||
34 | struct kvm_vmm_info vmm_info = { | ||
35 | .module = THIS_MODULE, | ||
36 | .vmm_entry = vmm_entry, | ||
37 | .tramp_entry = vmm_trampoline, | ||
38 | .vmm_ivt = (unsigned long)&kvm_ia64_ivt, | ||
39 | }; | ||
40 | |||
41 | static int __init kvm_vmm_init(void) | ||
42 | { | ||
43 | |||
44 | vmm_fpswa_interface = fpswa_interface; | ||
45 | |||
46 | /*Register vmm data to kvm side*/ | ||
47 | return kvm_init(&vmm_info, 1024, THIS_MODULE); | ||
48 | } | ||
49 | |||
50 | static void __exit kvm_vmm_exit(void) | ||
51 | { | ||
52 | kvm_exit(); | ||
53 | return ; | ||
54 | } | ||
55 | |||
56 | void vmm_spin_lock(spinlock_t *lock) | ||
57 | { | ||
58 | _vmm_raw_spin_lock(lock); | ||
59 | } | ||
60 | |||
61 | void vmm_spin_unlock(spinlock_t *lock) | ||
62 | { | ||
63 | _vmm_raw_spin_unlock(lock); | ||
64 | } | ||
65 | module_init(kvm_vmm_init) | ||
66 | module_exit(kvm_vmm_exit) | ||
diff --git a/arch/ia64/kvm/vmm_ivt.S b/arch/ia64/kvm/vmm_ivt.S new file mode 100644 index 000000000000..3ee5f481c06d --- /dev/null +++ b/arch/ia64/kvm/vmm_ivt.S | |||
@@ -0,0 +1,1424 @@ | |||
1 | /* | ||
2 | * /ia64/kvm_ivt.S | ||
3 | * | ||
4 | * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co | ||
5 | * Stephane Eranian <eranian@hpl.hp.com> | ||
6 | * David Mosberger <davidm@hpl.hp.com> | ||
7 | * Copyright (C) 2000, 2002-2003 Intel Co | ||
8 | * Asit Mallick <asit.k.mallick@intel.com> | ||
9 | * Suresh Siddha <suresh.b.siddha@intel.com> | ||
10 | * Kenneth Chen <kenneth.w.chen@intel.com> | ||
11 | * Fenghua Yu <fenghua.yu@intel.com> | ||
12 | * | ||
13 | * | ||
14 | * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling | ||
15 | * for SMP | ||
16 | * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB | ||
17 | * handler now uses virtual PT. | ||
18 | * | ||
19 | * 07/6/20 Xuefei Xu (Anthony Xu) (anthony.xu@intel.com) | ||
20 | * Supporting Intel virtualization architecture | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file defines the interruption vector table used by the CPU. | ||
26 | * It does not include one entry per possible cause of interruption. | ||
27 | * | ||
28 | * The first 20 entries of the table contain 64 bundles each while the | ||
29 | * remaining 48 entries contain only 16 bundles each. | ||
30 | * | ||
31 | * The 64 bundles are used to allow inlining the whole handler for | ||
32 | * critical | ||
33 | * interruptions like TLB misses. | ||
34 | * | ||
35 | * For each entry, the comment is as follows: | ||
36 | * | ||
37 | * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss | ||
38 | * (12,51) | ||
39 | * entry offset ----/ / / / | ||
40 | * / | ||
41 | * entry number ---------/ / / | ||
42 | * / | ||
43 | * size of the entry -------------/ / | ||
44 | * / | ||
45 | * vector name -------------------------------------/ | ||
46 | * / | ||
47 | * interruptions triggering this vector | ||
48 | * ----------------------/ | ||
49 | * | ||
50 | * The table is 32KB in size and must be aligned on 32KB | ||
51 | * boundary. | ||
52 | * (The CPU ignores the 15 lower bits of the address) | ||
53 | * | ||
54 | * Table is based upon EAS2.6 (Oct 1999) | ||
55 | */ | ||
56 | |||
57 | |||
58 | #include <asm/asmmacro.h> | ||
59 | #include <asm/cache.h> | ||
60 | #include <asm/pgtable.h> | ||
61 | |||
62 | #include "asm-offsets.h" | ||
63 | #include "vcpu.h" | ||
64 | #include "kvm_minstate.h" | ||
65 | #include "vti.h" | ||
66 | |||
67 | #if 1 | ||
68 | # define PSR_DEFAULT_BITS psr.ac | ||
69 | #else | ||
70 | # define PSR_DEFAULT_BITS 0 | ||
71 | #endif | ||
72 | |||
73 | |||
74 | #define KVM_FAULT(n) \ | ||
75 | kvm_fault_##n:; \ | ||
76 | mov r19=n;; \ | ||
77 | br.sptk.many kvm_fault_##n; \ | ||
78 | ;; \ | ||
79 | |||
80 | |||
81 | #define KVM_REFLECT(n) \ | ||
82 | mov r31=pr; \ | ||
83 | mov r19=n; /* prepare to save predicates */ \ | ||
84 | mov r29=cr.ipsr; \ | ||
85 | ;; \ | ||
86 | tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \ | ||
87 | (p7)br.sptk.many kvm_dispatch_reflection; \ | ||
88 | br.sptk.many kvm_panic; \ | ||
89 | |||
90 | |||
91 | GLOBAL_ENTRY(kvm_panic) | ||
92 | br.sptk.many kvm_panic | ||
93 | ;; | ||
94 | END(kvm_panic) | ||
95 | |||
96 | |||
97 | |||
98 | |||
99 | |||
100 | .section .text.ivt,"ax" | ||
101 | |||
102 | .align 32768 // align on 32KB boundary | ||
103 | .global kvm_ia64_ivt | ||
104 | kvm_ia64_ivt: | ||
105 | /////////////////////////////////////////////////////////////// | ||
106 | // 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) | ||
107 | ENTRY(kvm_vhpt_miss) | ||
108 | KVM_FAULT(0) | ||
109 | END(kvm_vhpt_miss) | ||
110 | |||
111 | |||
112 | .org kvm_ia64_ivt+0x400 | ||
113 | //////////////////////////////////////////////////////////////// | ||
114 | // 0x0400 Entry 1 (size 64 bundles) ITLB (21) | ||
115 | ENTRY(kvm_itlb_miss) | ||
116 | mov r31 = pr | ||
117 | mov r29=cr.ipsr; | ||
118 | ;; | ||
119 | tbit.z p6,p7=r29,IA64_PSR_VM_BIT; | ||
120 | (p6) br.sptk kvm_alt_itlb_miss | ||
121 | mov r19 = 1 | ||
122 | br.sptk kvm_itlb_miss_dispatch | ||
123 | KVM_FAULT(1); | ||
124 | END(kvm_itlb_miss) | ||
125 | |||
126 | .org kvm_ia64_ivt+0x0800 | ||
127 | ////////////////////////////////////////////////////////////////// | ||
128 | // 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) | ||
129 | ENTRY(kvm_dtlb_miss) | ||
130 | mov r31 = pr | ||
131 | mov r29=cr.ipsr; | ||
132 | ;; | ||
133 | tbit.z p6,p7=r29,IA64_PSR_VM_BIT; | ||
134 | (p6)br.sptk kvm_alt_dtlb_miss | ||
135 | br.sptk kvm_dtlb_miss_dispatch | ||
136 | END(kvm_dtlb_miss) | ||
137 | |||
138 | .org kvm_ia64_ivt+0x0c00 | ||
139 | //////////////////////////////////////////////////////////////////// | ||
140 | // 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) | ||
141 | ENTRY(kvm_alt_itlb_miss) | ||
142 | mov r16=cr.ifa // get address that caused the TLB miss | ||
143 | ;; | ||
144 | movl r17=PAGE_KERNEL | ||
145 | mov r24=cr.ipsr | ||
146 | movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) | ||
147 | ;; | ||
148 | and r19=r19,r16 // clear ed, reserved bits, and PTE control bits | ||
149 | ;; | ||
150 | or r19=r17,r19 // insert PTE control bits into r19 | ||
151 | ;; | ||
152 | movl r20=IA64_GRANULE_SHIFT<<2 | ||
153 | ;; | ||
154 | mov cr.itir=r20 | ||
155 | ;; | ||
156 | itc.i r19 // insert the TLB entry | ||
157 | mov pr=r31,-1 | ||
158 | rfi | ||
159 | END(kvm_alt_itlb_miss) | ||
160 | |||
161 | .org kvm_ia64_ivt+0x1000 | ||
162 | ///////////////////////////////////////////////////////////////////// | ||
163 | // 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) | ||
164 | ENTRY(kvm_alt_dtlb_miss) | ||
165 | mov r16=cr.ifa // get address that caused the TLB miss | ||
166 | ;; | ||
167 | movl r17=PAGE_KERNEL | ||
168 | movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) | ||
169 | mov r24=cr.ipsr | ||
170 | ;; | ||
171 | and r19=r19,r16 // clear ed, reserved bits, and PTE control bits | ||
172 | ;; | ||
173 | or r19=r19,r17 // insert PTE control bits into r19 | ||
174 | ;; | ||
175 | movl r20=IA64_GRANULE_SHIFT<<2 | ||
176 | ;; | ||
177 | mov cr.itir=r20 | ||
178 | ;; | ||
179 | itc.d r19 // insert the TLB entry | ||
180 | mov pr=r31,-1 | ||
181 | rfi | ||
182 | END(kvm_alt_dtlb_miss) | ||
183 | |||
184 | .org kvm_ia64_ivt+0x1400 | ||
185 | ////////////////////////////////////////////////////////////////////// | ||
186 | // 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) | ||
187 | ENTRY(kvm_nested_dtlb_miss) | ||
188 | KVM_FAULT(5) | ||
189 | END(kvm_nested_dtlb_miss) | ||
190 | |||
191 | .org kvm_ia64_ivt+0x1800 | ||
192 | ///////////////////////////////////////////////////////////////////// | ||
193 | // 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) | ||
194 | ENTRY(kvm_ikey_miss) | ||
195 | KVM_REFLECT(6) | ||
196 | END(kvm_ikey_miss) | ||
197 | |||
198 | .org kvm_ia64_ivt+0x1c00 | ||
199 | ///////////////////////////////////////////////////////////////////// | ||
200 | // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) | ||
201 | ENTRY(kvm_dkey_miss) | ||
202 | KVM_REFLECT(7) | ||
203 | END(kvm_dkey_miss) | ||
204 | |||
205 | .org kvm_ia64_ivt+0x2000 | ||
206 | //////////////////////////////////////////////////////////////////// | ||
207 | // 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) | ||
208 | ENTRY(kvm_dirty_bit) | ||
209 | KVM_REFLECT(8) | ||
210 | END(kvm_dirty_bit) | ||
211 | |||
212 | .org kvm_ia64_ivt+0x2400 | ||
213 | //////////////////////////////////////////////////////////////////// | ||
214 | // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) | ||
215 | ENTRY(kvm_iaccess_bit) | ||
216 | KVM_REFLECT(9) | ||
217 | END(kvm_iaccess_bit) | ||
218 | |||
219 | .org kvm_ia64_ivt+0x2800 | ||
220 | /////////////////////////////////////////////////////////////////// | ||
221 | // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) | ||
222 | ENTRY(kvm_daccess_bit) | ||
223 | KVM_REFLECT(10) | ||
224 | END(kvm_daccess_bit) | ||
225 | |||
226 | .org kvm_ia64_ivt+0x2c00 | ||
227 | ///////////////////////////////////////////////////////////////// | ||
228 | // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) | ||
229 | ENTRY(kvm_break_fault) | ||
230 | mov r31=pr | ||
231 | mov r19=11 | ||
232 | mov r29=cr.ipsr | ||
233 | ;; | ||
234 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
235 | ;; | ||
236 | alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!) | ||
237 | mov out0=cr.ifa | ||
238 | mov out2=cr.isr // FIXME: pity to make this slow access twice | ||
239 | mov out3=cr.iim // FIXME: pity to make this slow access twice | ||
240 | adds r3=8,r2 // set up second base pointer | ||
241 | ;; | ||
242 | ssm psr.ic | ||
243 | ;; | ||
244 | srlz.i // guarantee that interruption collection is on | ||
245 | ;; | ||
246 | //(p15)ssm psr.i // restore psr.i | ||
247 | addl r14=@gprel(ia64_leave_hypervisor),gp | ||
248 | ;; | ||
249 | KVM_SAVE_REST | ||
250 | mov rp=r14 | ||
251 | ;; | ||
252 | adds out1=16,sp | ||
253 | br.call.sptk.many b6=kvm_ia64_handle_break | ||
254 | ;; | ||
255 | END(kvm_break_fault) | ||
256 | |||
257 | .org kvm_ia64_ivt+0x3000 | ||
258 | ///////////////////////////////////////////////////////////////// | ||
259 | // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) | ||
260 | ENTRY(kvm_interrupt) | ||
261 | mov r31=pr // prepare to save predicates | ||
262 | mov r19=12 | ||
263 | mov r29=cr.ipsr | ||
264 | ;; | ||
265 | tbit.z p6,p7=r29,IA64_PSR_VM_BIT | ||
266 | tbit.z p0,p15=r29,IA64_PSR_I_BIT | ||
267 | ;; | ||
268 | (p7) br.sptk kvm_dispatch_interrupt | ||
269 | ;; | ||
270 | mov r27=ar.rsc /* M */ | ||
271 | mov r20=r1 /* A */ | ||
272 | mov r25=ar.unat /* M */ | ||
273 | mov r26=ar.pfs /* I */ | ||
274 | mov r28=cr.iip /* M */ | ||
275 | cover /* B (or nothing) */ | ||
276 | ;; | ||
277 | mov r1=sp | ||
278 | ;; | ||
279 | invala /* M */ | ||
280 | mov r30=cr.ifs | ||
281 | ;; | ||
282 | addl r1=-VMM_PT_REGS_SIZE,r1 | ||
283 | ;; | ||
284 | adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line size */ | ||
285 | adds r16=PT(CR_IPSR),r1 | ||
286 | ;; | ||
287 | lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES | ||
288 | st8 [r16]=r29 /* save cr.ipsr */ | ||
289 | ;; | ||
290 | lfetch.fault.excl.nt1 [r17] | ||
291 | mov r29=b0 | ||
292 | ;; | ||
293 | adds r16=PT(R8),r1 /* initialize first base pointer */ | ||
294 | adds r17=PT(R9),r1 /* initialize second base pointer */ | ||
295 | mov r18=r0 /* make sure r18 isn't NaT */ | ||
296 | ;; | ||
297 | .mem.offset 0,0; st8.spill [r16]=r8,16 | ||
298 | .mem.offset 8,0; st8.spill [r17]=r9,16 | ||
299 | ;; | ||
300 | .mem.offset 0,0; st8.spill [r16]=r10,24 | ||
301 | .mem.offset 8,0; st8.spill [r17]=r11,24 | ||
302 | ;; | ||
303 | st8 [r16]=r28,16 /* save cr.iip */ | ||
304 | st8 [r17]=r30,16 /* save cr.ifs */ | ||
305 | mov r8=ar.fpsr /* M */ | ||
306 | mov r9=ar.csd | ||
307 | mov r10=ar.ssd | ||
308 | movl r11=FPSR_DEFAULT /* L-unit */ | ||
309 | ;; | ||
310 | st8 [r16]=r25,16 /* save ar.unat */ | ||
311 | st8 [r17]=r26,16 /* save ar.pfs */ | ||
312 | shl r18=r18,16 /* compute ar.rsc to be used for "loadrs" */ | ||
313 | ;; | ||
314 | st8 [r16]=r27,16 /* save ar.rsc */ | ||
315 | adds r17=16,r17 /* skip over ar_rnat field */ | ||
316 | ;; | ||
317 | st8 [r17]=r31,16 /* save predicates */ | ||
318 | adds r16=16,r16 /* skip over ar_bspstore field */ | ||
319 | ;; | ||
320 | st8 [r16]=r29,16 /* save b0 */ | ||
321 | st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */ | ||
322 | ;; | ||
323 | .mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */ | ||
324 | .mem.offset 8,0; st8.spill [r17]=r12,16 | ||
325 | adds r12=-16,r1 | ||
326 | /* switch to kernel memory stack (with 16 bytes of scratch) */ | ||
327 | ;; | ||
328 | .mem.offset 0,0; st8.spill [r16]=r13,16 | ||
329 | .mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */ | ||
330 | ;; | ||
331 | .mem.offset 0,0; st8.spill [r16]=r15,16 | ||
332 | .mem.offset 8,0; st8.spill [r17]=r14,16 | ||
333 | dep r14=-1,r0,60,4 | ||
334 | ;; | ||
335 | .mem.offset 0,0; st8.spill [r16]=r2,16 | ||
336 | .mem.offset 8,0; st8.spill [r17]=r3,16 | ||
337 | adds r2=VMM_PT_REGS_R16_OFFSET,r1 | ||
338 | adds r14 = VMM_VCPU_GP_OFFSET,r13 | ||
339 | ;; | ||
340 | mov r8=ar.ccv | ||
341 | ld8 r14 = [r14] | ||
342 | ;; | ||
343 | mov r1=r14 /* establish kernel global pointer */ | ||
344 | ;; \ | ||
345 | bsw.1 | ||
346 | ;; | ||
347 | alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group | ||
348 | mov out0=r13 | ||
349 | ;; | ||
350 | ssm psr.ic | ||
351 | ;; | ||
352 | srlz.i | ||
353 | ;; | ||
354 | //(p15) ssm psr.i | ||
355 | adds r3=8,r2 // set up second base pointer for SAVE_REST | ||
356 | srlz.i // ensure everybody knows psr.ic is back on | ||
357 | ;; | ||
358 | .mem.offset 0,0; st8.spill [r2]=r16,16 | ||
359 | .mem.offset 8,0; st8.spill [r3]=r17,16 | ||
360 | ;; | ||
361 | .mem.offset 0,0; st8.spill [r2]=r18,16 | ||
362 | .mem.offset 8,0; st8.spill [r3]=r19,16 | ||
363 | ;; | ||
364 | .mem.offset 0,0; st8.spill [r2]=r20,16 | ||
365 | .mem.offset 8,0; st8.spill [r3]=r21,16 | ||
366 | mov r18=b6 | ||
367 | ;; | ||
368 | .mem.offset 0,0; st8.spill [r2]=r22,16 | ||
369 | .mem.offset 8,0; st8.spill [r3]=r23,16 | ||
370 | mov r19=b7 | ||
371 | ;; | ||
372 | .mem.offset 0,0; st8.spill [r2]=r24,16 | ||
373 | .mem.offset 8,0; st8.spill [r3]=r25,16 | ||
374 | ;; | ||
375 | .mem.offset 0,0; st8.spill [r2]=r26,16 | ||
376 | .mem.offset 8,0; st8.spill [r3]=r27,16 | ||
377 | ;; | ||
378 | .mem.offset 0,0; st8.spill [r2]=r28,16 | ||
379 | .mem.offset 8,0; st8.spill [r3]=r29,16 | ||
380 | ;; | ||
381 | .mem.offset 0,0; st8.spill [r2]=r30,16 | ||
382 | .mem.offset 8,0; st8.spill [r3]=r31,32 | ||
383 | ;; | ||
384 | mov ar.fpsr=r11 /* M-unit */ | ||
385 | st8 [r2]=r8,8 /* ar.ccv */ | ||
386 | adds r24=PT(B6)-PT(F7),r3 | ||
387 | ;; | ||
388 | stf.spill [r2]=f6,32 | ||
389 | stf.spill [r3]=f7,32 | ||
390 | ;; | ||
391 | stf.spill [r2]=f8,32 | ||
392 | stf.spill [r3]=f9,32 | ||
393 | ;; | ||
394 | stf.spill [r2]=f10 | ||
395 | stf.spill [r3]=f11 | ||
396 | adds r25=PT(B7)-PT(F11),r3 | ||
397 | ;; | ||
398 | st8 [r24]=r18,16 /* b6 */ | ||
399 | st8 [r25]=r19,16 /* b7 */ | ||
400 | ;; | ||
401 | st8 [r24]=r9 /* ar.csd */ | ||
402 | st8 [r25]=r10 /* ar.ssd */ | ||
403 | ;; | ||
404 | srlz.d // make sure we see the effect of cr.ivr | ||
405 | addl r14=@gprel(ia64_leave_nested),gp | ||
406 | ;; | ||
407 | mov rp=r14 | ||
408 | br.call.sptk.many b6=kvm_ia64_handle_irq | ||
409 | ;; | ||
410 | END(kvm_interrupt) | ||
411 | |||
412 | .global kvm_dispatch_vexirq | ||
413 | .org kvm_ia64_ivt+0x3400 | ||
414 | ////////////////////////////////////////////////////////////////////// | ||
415 | // 0x3400 Entry 13 (size 64 bundles) Reserved | ||
416 | ENTRY(kvm_virtual_exirq) | ||
417 | mov r31=pr | ||
418 | mov r19=13 | ||
419 | mov r30 =r0 | ||
420 | ;; | ||
421 | kvm_dispatch_vexirq: | ||
422 | cmp.eq p6,p0 = 1,r30 | ||
423 | ;; | ||
424 | (p6)add r29 = VMM_VCPU_SAVED_GP_OFFSET,r21 | ||
425 | ;; | ||
426 | (p6)ld8 r1 = [r29] | ||
427 | ;; | ||
428 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
429 | alloc r14=ar.pfs,0,0,1,0 | ||
430 | mov out0=r13 | ||
431 | |||
432 | ssm psr.ic | ||
433 | ;; | ||
434 | srlz.i // guarantee that interruption collection is on | ||
435 | ;; | ||
436 | //(p15) ssm psr.i // restore psr.i | ||
437 | adds r3=8,r2 // set up second base pointer | ||
438 | ;; | ||
439 | KVM_SAVE_REST | ||
440 | addl r14=@gprel(ia64_leave_hypervisor),gp | ||
441 | ;; | ||
442 | mov rp=r14 | ||
443 | br.call.sptk.many b6=kvm_vexirq | ||
444 | END(kvm_virtual_exirq) | ||
445 | |||
446 | .org kvm_ia64_ivt+0x3800 | ||
447 | ///////////////////////////////////////////////////////////////////// | ||
448 | // 0x3800 Entry 14 (size 64 bundles) Reserved | ||
449 | KVM_FAULT(14) | ||
450 | // this code segment is from 2.6.16.13 | ||
451 | |||
452 | |||
453 | .org kvm_ia64_ivt+0x3c00 | ||
454 | /////////////////////////////////////////////////////////////////////// | ||
455 | // 0x3c00 Entry 15 (size 64 bundles) Reserved | ||
456 | KVM_FAULT(15) | ||
457 | |||
458 | |||
459 | .org kvm_ia64_ivt+0x4000 | ||
460 | /////////////////////////////////////////////////////////////////////// | ||
461 | // 0x4000 Entry 16 (size 64 bundles) Reserved | ||
462 | KVM_FAULT(16) | ||
463 | |||
464 | .org kvm_ia64_ivt+0x4400 | ||
465 | ////////////////////////////////////////////////////////////////////// | ||
466 | // 0x4400 Entry 17 (size 64 bundles) Reserved | ||
467 | KVM_FAULT(17) | ||
468 | |||
469 | .org kvm_ia64_ivt+0x4800 | ||
470 | ////////////////////////////////////////////////////////////////////// | ||
471 | // 0x4800 Entry 18 (size 64 bundles) Reserved | ||
472 | KVM_FAULT(18) | ||
473 | |||
474 | .org kvm_ia64_ivt+0x4c00 | ||
475 | ////////////////////////////////////////////////////////////////////// | ||
476 | // 0x4c00 Entry 19 (size 64 bundles) Reserved | ||
477 | KVM_FAULT(19) | ||
478 | |||
479 | .org kvm_ia64_ivt+0x5000 | ||
480 | ////////////////////////////////////////////////////////////////////// | ||
481 | // 0x5000 Entry 20 (size 16 bundles) Page Not Present | ||
482 | ENTRY(kvm_page_not_present) | ||
483 | KVM_REFLECT(20) | ||
484 | END(kvm_page_not_present) | ||
485 | |||
486 | .org kvm_ia64_ivt+0x5100 | ||
487 | /////////////////////////////////////////////////////////////////////// | ||
488 | // 0x5100 Entry 21 (size 16 bundles) Key Permission vector | ||
489 | ENTRY(kvm_key_permission) | ||
490 | KVM_REFLECT(21) | ||
491 | END(kvm_key_permission) | ||
492 | |||
493 | .org kvm_ia64_ivt+0x5200 | ||
494 | ////////////////////////////////////////////////////////////////////// | ||
495 | // 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) | ||
496 | ENTRY(kvm_iaccess_rights) | ||
497 | KVM_REFLECT(22) | ||
498 | END(kvm_iaccess_rights) | ||
499 | |||
500 | .org kvm_ia64_ivt+0x5300 | ||
501 | ////////////////////////////////////////////////////////////////////// | ||
502 | // 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) | ||
503 | ENTRY(kvm_daccess_rights) | ||
504 | KVM_REFLECT(23) | ||
505 | END(kvm_daccess_rights) | ||
506 | |||
507 | .org kvm_ia64_ivt+0x5400 | ||
508 | ///////////////////////////////////////////////////////////////////// | ||
509 | // 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) | ||
510 | ENTRY(kvm_general_exception) | ||
511 | KVM_REFLECT(24) | ||
512 | KVM_FAULT(24) | ||
513 | END(kvm_general_exception) | ||
514 | |||
515 | .org kvm_ia64_ivt+0x5500 | ||
516 | ////////////////////////////////////////////////////////////////////// | ||
517 | // 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) | ||
518 | ENTRY(kvm_disabled_fp_reg) | ||
519 | KVM_REFLECT(25) | ||
520 | END(kvm_disabled_fp_reg) | ||
521 | |||
522 | .org kvm_ia64_ivt+0x5600 | ||
523 | //////////////////////////////////////////////////////////////////// | ||
524 | // 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) | ||
525 | ENTRY(kvm_nat_consumption) | ||
526 | KVM_REFLECT(26) | ||
527 | END(kvm_nat_consumption) | ||
528 | |||
529 | .org kvm_ia64_ivt+0x5700 | ||
530 | ///////////////////////////////////////////////////////////////////// | ||
531 | // 0x5700 Entry 27 (size 16 bundles) Speculation (40) | ||
532 | ENTRY(kvm_speculation_vector) | ||
533 | KVM_REFLECT(27) | ||
534 | END(kvm_speculation_vector) | ||
535 | |||
536 | .org kvm_ia64_ivt+0x5800 | ||
537 | ///////////////////////////////////////////////////////////////////// | ||
538 | // 0x5800 Entry 28 (size 16 bundles) Reserved | ||
539 | KVM_FAULT(28) | ||
540 | |||
541 | .org kvm_ia64_ivt+0x5900 | ||
542 | /////////////////////////////////////////////////////////////////// | ||
543 | // 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) | ||
544 | ENTRY(kvm_debug_vector) | ||
545 | KVM_FAULT(29) | ||
546 | END(kvm_debug_vector) | ||
547 | |||
548 | .org kvm_ia64_ivt+0x5a00 | ||
549 | /////////////////////////////////////////////////////////////// | ||
550 | // 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) | ||
551 | ENTRY(kvm_unaligned_access) | ||
552 | KVM_REFLECT(30) | ||
553 | END(kvm_unaligned_access) | ||
554 | |||
555 | .org kvm_ia64_ivt+0x5b00 | ||
556 | ////////////////////////////////////////////////////////////////////// | ||
557 | // 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) | ||
558 | ENTRY(kvm_unsupported_data_reference) | ||
559 | KVM_REFLECT(31) | ||
560 | END(kvm_unsupported_data_reference) | ||
561 | |||
562 | .org kvm_ia64_ivt+0x5c00 | ||
563 | //////////////////////////////////////////////////////////////////// | ||
564 | // 0x5c00 Entry 32 (size 16 bundles) Floating Point FAULT (65) | ||
565 | ENTRY(kvm_floating_point_fault) | ||
566 | KVM_REFLECT(32) | ||
567 | END(kvm_floating_point_fault) | ||
568 | |||
569 | .org kvm_ia64_ivt+0x5d00 | ||
570 | ///////////////////////////////////////////////////////////////////// | ||
571 | // 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) | ||
572 | ENTRY(kvm_floating_point_trap) | ||
573 | KVM_REFLECT(33) | ||
574 | END(kvm_floating_point_trap) | ||
575 | |||
576 | .org kvm_ia64_ivt+0x5e00 | ||
577 | ////////////////////////////////////////////////////////////////////// | ||
578 | // 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) | ||
579 | ENTRY(kvm_lower_privilege_trap) | ||
580 | KVM_REFLECT(34) | ||
581 | END(kvm_lower_privilege_trap) | ||
582 | |||
583 | .org kvm_ia64_ivt+0x5f00 | ||
584 | ////////////////////////////////////////////////////////////////////// | ||
585 | // 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) | ||
586 | ENTRY(kvm_taken_branch_trap) | ||
587 | KVM_REFLECT(35) | ||
588 | END(kvm_taken_branch_trap) | ||
589 | |||
590 | .org kvm_ia64_ivt+0x6000 | ||
591 | //////////////////////////////////////////////////////////////////// | ||
592 | // 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) | ||
593 | ENTRY(kvm_single_step_trap) | ||
594 | KVM_REFLECT(36) | ||
595 | END(kvm_single_step_trap) | ||
596 | .global kvm_virtualization_fault_back | ||
597 | .org kvm_ia64_ivt+0x6100 | ||
598 | ///////////////////////////////////////////////////////////////////// | ||
599 | // 0x6100 Entry 37 (size 16 bundles) Virtualization Fault | ||
600 | ENTRY(kvm_virtualization_fault) | ||
601 | mov r31=pr | ||
602 | adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21 | ||
603 | ;; | ||
604 | st8 [r16] = r1 | ||
605 | adds r17 = VMM_VCPU_GP_OFFSET, r21 | ||
606 | ;; | ||
607 | ld8 r1 = [r17] | ||
608 | cmp.eq p6,p0=EVENT_MOV_FROM_AR,r24 | ||
609 | cmp.eq p7,p0=EVENT_MOV_FROM_RR,r24 | ||
610 | cmp.eq p8,p0=EVENT_MOV_TO_RR,r24 | ||
611 | cmp.eq p9,p0=EVENT_RSM,r24 | ||
612 | cmp.eq p10,p0=EVENT_SSM,r24 | ||
613 | cmp.eq p11,p0=EVENT_MOV_TO_PSR,r24 | ||
614 | cmp.eq p12,p0=EVENT_THASH,r24 | ||
615 | (p6) br.dptk.many kvm_asm_mov_from_ar | ||
616 | (p7) br.dptk.many kvm_asm_mov_from_rr | ||
617 | (p8) br.dptk.many kvm_asm_mov_to_rr | ||
618 | (p9) br.dptk.many kvm_asm_rsm | ||
619 | (p10) br.dptk.many kvm_asm_ssm | ||
620 | (p11) br.dptk.many kvm_asm_mov_to_psr | ||
621 | (p12) br.dptk.many kvm_asm_thash | ||
622 | ;; | ||
623 | kvm_virtualization_fault_back: | ||
624 | adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21 | ||
625 | ;; | ||
626 | ld8 r1 = [r16] | ||
627 | ;; | ||
628 | mov r19=37 | ||
629 | adds r16 = VMM_VCPU_CAUSE_OFFSET,r21 | ||
630 | adds r17 = VMM_VCPU_OPCODE_OFFSET,r21 | ||
631 | ;; | ||
632 | st8 [r16] = r24 | ||
633 | st8 [r17] = r25 | ||
634 | ;; | ||
635 | cmp.ne p6,p0=EVENT_RFI, r24 | ||
636 | (p6) br.sptk kvm_dispatch_virtualization_fault | ||
637 | ;; | ||
638 | adds r18=VMM_VPD_BASE_OFFSET,r21 | ||
639 | ;; | ||
640 | ld8 r18=[r18] | ||
641 | ;; | ||
642 | adds r18=VMM_VPD_VIFS_OFFSET,r18 | ||
643 | ;; | ||
644 | ld8 r18=[r18] | ||
645 | ;; | ||
646 | tbit.z p6,p0=r18,63 | ||
647 | (p6) br.sptk kvm_dispatch_virtualization_fault | ||
648 | ;; | ||
649 | //if vifs.v=1 desert current register frame | ||
650 | alloc r18=ar.pfs,0,0,0,0 | ||
651 | br.sptk kvm_dispatch_virtualization_fault | ||
652 | END(kvm_virtualization_fault) | ||
653 | |||
654 | .org kvm_ia64_ivt+0x6200 | ||
655 | ////////////////////////////////////////////////////////////// | ||
656 | // 0x6200 Entry 38 (size 16 bundles) Reserved | ||
657 | KVM_FAULT(38) | ||
658 | |||
659 | .org kvm_ia64_ivt+0x6300 | ||
660 | ///////////////////////////////////////////////////////////////// | ||
661 | // 0x6300 Entry 39 (size 16 bundles) Reserved | ||
662 | KVM_FAULT(39) | ||
663 | |||
664 | .org kvm_ia64_ivt+0x6400 | ||
665 | ///////////////////////////////////////////////////////////////// | ||
666 | // 0x6400 Entry 40 (size 16 bundles) Reserved | ||
667 | KVM_FAULT(40) | ||
668 | |||
669 | .org kvm_ia64_ivt+0x6500 | ||
670 | ////////////////////////////////////////////////////////////////// | ||
671 | // 0x6500 Entry 41 (size 16 bundles) Reserved | ||
672 | KVM_FAULT(41) | ||
673 | |||
674 | .org kvm_ia64_ivt+0x6600 | ||
675 | ////////////////////////////////////////////////////////////////// | ||
676 | // 0x6600 Entry 42 (size 16 bundles) Reserved | ||
677 | KVM_FAULT(42) | ||
678 | |||
679 | .org kvm_ia64_ivt+0x6700 | ||
680 | ////////////////////////////////////////////////////////////////// | ||
681 | // 0x6700 Entry 43 (size 16 bundles) Reserved | ||
682 | KVM_FAULT(43) | ||
683 | |||
684 | .org kvm_ia64_ivt+0x6800 | ||
685 | ////////////////////////////////////////////////////////////////// | ||
686 | // 0x6800 Entry 44 (size 16 bundles) Reserved | ||
687 | KVM_FAULT(44) | ||
688 | |||
689 | .org kvm_ia64_ivt+0x6900 | ||
690 | /////////////////////////////////////////////////////////////////// | ||
691 | // 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception | ||
692 | //(17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) | ||
693 | ENTRY(kvm_ia32_exception) | ||
694 | KVM_FAULT(45) | ||
695 | END(kvm_ia32_exception) | ||
696 | |||
697 | .org kvm_ia64_ivt+0x6a00 | ||
698 | //////////////////////////////////////////////////////////////////// | ||
699 | // 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) | ||
700 | ENTRY(kvm_ia32_intercept) | ||
701 | KVM_FAULT(47) | ||
702 | END(kvm_ia32_intercept) | ||
703 | |||
704 | .org kvm_ia64_ivt+0x6c00 | ||
705 | ///////////////////////////////////////////////////////////////////// | ||
706 | // 0x6c00 Entry 48 (size 16 bundles) Reserved | ||
707 | KVM_FAULT(48) | ||
708 | |||
709 | .org kvm_ia64_ivt+0x6d00 | ||
710 | ////////////////////////////////////////////////////////////////////// | ||
711 | // 0x6d00 Entry 49 (size 16 bundles) Reserved | ||
712 | KVM_FAULT(49) | ||
713 | |||
714 | .org kvm_ia64_ivt+0x6e00 | ||
715 | ////////////////////////////////////////////////////////////////////// | ||
716 | // 0x6e00 Entry 50 (size 16 bundles) Reserved | ||
717 | KVM_FAULT(50) | ||
718 | |||
719 | .org kvm_ia64_ivt+0x6f00 | ||
720 | ///////////////////////////////////////////////////////////////////// | ||
721 | // 0x6f00 Entry 51 (size 16 bundles) Reserved | ||
722 | KVM_FAULT(52) | ||
723 | |||
724 | .org kvm_ia64_ivt+0x7100 | ||
725 | //////////////////////////////////////////////////////////////////// | ||
726 | // 0x7100 Entry 53 (size 16 bundles) Reserved | ||
727 | KVM_FAULT(53) | ||
728 | |||
729 | .org kvm_ia64_ivt+0x7200 | ||
730 | ///////////////////////////////////////////////////////////////////// | ||
731 | // 0x7200 Entry 54 (size 16 bundles) Reserved | ||
732 | KVM_FAULT(54) | ||
733 | |||
734 | .org kvm_ia64_ivt+0x7300 | ||
735 | //////////////////////////////////////////////////////////////////// | ||
736 | // 0x7300 Entry 55 (size 16 bundles) Reserved | ||
737 | KVM_FAULT(55) | ||
738 | |||
739 | .org kvm_ia64_ivt+0x7400 | ||
740 | //////////////////////////////////////////////////////////////////// | ||
741 | // 0x7400 Entry 56 (size 16 bundles) Reserved | ||
742 | KVM_FAULT(56) | ||
743 | |||
744 | .org kvm_ia64_ivt+0x7500 | ||
745 | ///////////////////////////////////////////////////////////////////// | ||
746 | // 0x7500 Entry 57 (size 16 bundles) Reserved | ||
747 | KVM_FAULT(57) | ||
748 | |||
749 | .org kvm_ia64_ivt+0x7600 | ||
750 | ///////////////////////////////////////////////////////////////////// | ||
751 | // 0x7600 Entry 58 (size 16 bundles) Reserved | ||
752 | KVM_FAULT(58) | ||
753 | |||
754 | .org kvm_ia64_ivt+0x7700 | ||
755 | //////////////////////////////////////////////////////////////////// | ||
756 | // 0x7700 Entry 59 (size 16 bundles) Reserved | ||
757 | KVM_FAULT(59) | ||
758 | |||
759 | .org kvm_ia64_ivt+0x7800 | ||
760 | //////////////////////////////////////////////////////////////////// | ||
761 | // 0x7800 Entry 60 (size 16 bundles) Reserved | ||
762 | KVM_FAULT(60) | ||
763 | |||
764 | .org kvm_ia64_ivt+0x7900 | ||
765 | ///////////////////////////////////////////////////////////////////// | ||
766 | // 0x7900 Entry 61 (size 16 bundles) Reserved | ||
767 | KVM_FAULT(61) | ||
768 | |||
769 | .org kvm_ia64_ivt+0x7a00 | ||
770 | ///////////////////////////////////////////////////////////////////// | ||
771 | // 0x7a00 Entry 62 (size 16 bundles) Reserved | ||
772 | KVM_FAULT(62) | ||
773 | |||
774 | .org kvm_ia64_ivt+0x7b00 | ||
775 | ///////////////////////////////////////////////////////////////////// | ||
776 | // 0x7b00 Entry 63 (size 16 bundles) Reserved | ||
777 | KVM_FAULT(63) | ||
778 | |||
779 | .org kvm_ia64_ivt+0x7c00 | ||
780 | //////////////////////////////////////////////////////////////////// | ||
781 | // 0x7c00 Entry 64 (size 16 bundles) Reserved | ||
782 | KVM_FAULT(64) | ||
783 | |||
784 | .org kvm_ia64_ivt+0x7d00 | ||
785 | ///////////////////////////////////////////////////////////////////// | ||
786 | // 0x7d00 Entry 65 (size 16 bundles) Reserved | ||
787 | KVM_FAULT(65) | ||
788 | |||
789 | .org kvm_ia64_ivt+0x7e00 | ||
790 | ///////////////////////////////////////////////////////////////////// | ||
791 | // 0x7e00 Entry 66 (size 16 bundles) Reserved | ||
792 | KVM_FAULT(66) | ||
793 | |||
794 | .org kvm_ia64_ivt+0x7f00 | ||
795 | //////////////////////////////////////////////////////////////////// | ||
796 | // 0x7f00 Entry 67 (size 16 bundles) Reserved | ||
797 | KVM_FAULT(67) | ||
798 | |||
799 | .org kvm_ia64_ivt+0x8000 | ||
800 | // There is no particular reason for this code to be here, other than that | ||
801 | // there happens to be space here that would go unused otherwise. If this | ||
802 | // fault ever gets "unreserved", simply moved the following code to a more | ||
803 | // suitable spot... | ||
804 | |||
805 | |||
806 | ENTRY(kvm_dtlb_miss_dispatch) | ||
807 | mov r19 = 2 | ||
808 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
809 | alloc r14=ar.pfs,0,0,3,0 | ||
810 | mov out0=cr.ifa | ||
811 | mov out1=r15 | ||
812 | adds r3=8,r2 // set up second base pointer | ||
813 | ;; | ||
814 | ssm psr.ic | ||
815 | ;; | ||
816 | srlz.i // guarantee that interruption collection is on | ||
817 | ;; | ||
818 | //(p15) ssm psr.i // restore psr.i | ||
819 | addl r14=@gprel(ia64_leave_hypervisor_prepare),gp | ||
820 | ;; | ||
821 | KVM_SAVE_REST | ||
822 | KVM_SAVE_EXTRA | ||
823 | mov rp=r14 | ||
824 | ;; | ||
825 | adds out2=16,r12 | ||
826 | br.call.sptk.many b6=kvm_page_fault | ||
827 | END(kvm_dtlb_miss_dispatch) | ||
828 | |||
829 | ENTRY(kvm_itlb_miss_dispatch) | ||
830 | |||
831 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
832 | alloc r14=ar.pfs,0,0,3,0 | ||
833 | mov out0=cr.ifa | ||
834 | mov out1=r15 | ||
835 | adds r3=8,r2 // set up second base pointer | ||
836 | ;; | ||
837 | ssm psr.ic | ||
838 | ;; | ||
839 | srlz.i // guarantee that interruption collection is on | ||
840 | ;; | ||
841 | //(p15) ssm psr.i // restore psr.i | ||
842 | addl r14=@gprel(ia64_leave_hypervisor),gp | ||
843 | ;; | ||
844 | KVM_SAVE_REST | ||
845 | mov rp=r14 | ||
846 | ;; | ||
847 | adds out2=16,r12 | ||
848 | br.call.sptk.many b6=kvm_page_fault | ||
849 | END(kvm_itlb_miss_dispatch) | ||
850 | |||
851 | ENTRY(kvm_dispatch_reflection) | ||
852 | /* | ||
853 | * Input: | ||
854 | * psr.ic: off | ||
855 | * r19: intr type (offset into ivt, see ia64_int.h) | ||
856 | * r31: contains saved predicates (pr) | ||
857 | */ | ||
858 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
859 | alloc r14=ar.pfs,0,0,5,0 | ||
860 | mov out0=cr.ifa | ||
861 | mov out1=cr.isr | ||
862 | mov out2=cr.iim | ||
863 | mov out3=r15 | ||
864 | adds r3=8,r2 // set up second base pointer | ||
865 | ;; | ||
866 | ssm psr.ic | ||
867 | ;; | ||
868 | srlz.i // guarantee that interruption collection is on | ||
869 | ;; | ||
870 | //(p15) ssm psr.i // restore psr.i | ||
871 | addl r14=@gprel(ia64_leave_hypervisor),gp | ||
872 | ;; | ||
873 | KVM_SAVE_REST | ||
874 | mov rp=r14 | ||
875 | ;; | ||
876 | adds out4=16,r12 | ||
877 | br.call.sptk.many b6=reflect_interruption | ||
878 | END(kvm_dispatch_reflection) | ||
879 | |||
880 | ENTRY(kvm_dispatch_virtualization_fault) | ||
881 | adds r16 = VMM_VCPU_CAUSE_OFFSET,r21 | ||
882 | adds r17 = VMM_VCPU_OPCODE_OFFSET,r21 | ||
883 | ;; | ||
884 | st8 [r16] = r24 | ||
885 | st8 [r17] = r25 | ||
886 | ;; | ||
887 | KVM_SAVE_MIN_WITH_COVER_R19 | ||
888 | ;; | ||
889 | alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) | ||
890 | mov out0=r13 //vcpu | ||
891 | adds r3=8,r2 // set up second base pointer | ||
892 | ;; | ||
893 | ssm psr.ic | ||
894 | ;; | ||
895 | srlz.i // guarantee that interruption collection is on | ||
896 | ;; | ||
897 | //(p15) ssm psr.i // restore psr.i | ||
898 | addl r14=@gprel(ia64_leave_hypervisor_prepare),gp | ||
899 | ;; | ||
900 | KVM_SAVE_REST | ||
901 | KVM_SAVE_EXTRA | ||
902 | mov rp=r14 | ||
903 | ;; | ||
904 | adds out1=16,sp //regs | ||
905 | br.call.sptk.many b6=kvm_emulate | ||
906 | END(kvm_dispatch_virtualization_fault) | ||
907 | |||
908 | |||
909 | ENTRY(kvm_dispatch_interrupt) | ||
910 | KVM_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3 | ||
911 | ;; | ||
912 | alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group | ||
913 | //mov out0=cr.ivr // pass cr.ivr as first arg | ||
914 | adds r3=8,r2 // set up second base pointer for SAVE_REST | ||
915 | ;; | ||
916 | ssm psr.ic | ||
917 | ;; | ||
918 | srlz.i | ||
919 | ;; | ||
920 | //(p15) ssm psr.i | ||
921 | addl r14=@gprel(ia64_leave_hypervisor),gp | ||
922 | ;; | ||
923 | KVM_SAVE_REST | ||
924 | mov rp=r14 | ||
925 | ;; | ||
926 | mov out0=r13 // pass pointer to pt_regs as second arg | ||
927 | br.call.sptk.many b6=kvm_ia64_handle_irq | ||
928 | END(kvm_dispatch_interrupt) | ||
929 | |||
930 | |||
931 | |||
932 | |||
933 | GLOBAL_ENTRY(ia64_leave_nested) | ||
934 | rsm psr.i | ||
935 | ;; | ||
936 | adds r21=PT(PR)+16,r12 | ||
937 | ;; | ||
938 | lfetch [r21],PT(CR_IPSR)-PT(PR) | ||
939 | adds r2=PT(B6)+16,r12 | ||
940 | adds r3=PT(R16)+16,r12 | ||
941 | ;; | ||
942 | lfetch [r21] | ||
943 | ld8 r28=[r2],8 // load b6 | ||
944 | adds r29=PT(R24)+16,r12 | ||
945 | |||
946 | ld8.fill r16=[r3] | ||
947 | adds r3=PT(AR_CSD)-PT(R16),r3 | ||
948 | adds r30=PT(AR_CCV)+16,r12 | ||
949 | ;; | ||
950 | ld8.fill r24=[r29] | ||
951 | ld8 r15=[r30] // load ar.ccv | ||
952 | ;; | ||
953 | ld8 r29=[r2],16 // load b7 | ||
954 | ld8 r30=[r3],16 // load ar.csd | ||
955 | ;; | ||
956 | ld8 r31=[r2],16 // load ar.ssd | ||
957 | ld8.fill r8=[r3],16 | ||
958 | ;; | ||
959 | ld8.fill r9=[r2],16 | ||
960 | ld8.fill r10=[r3],PT(R17)-PT(R10) | ||
961 | ;; | ||
962 | ld8.fill r11=[r2],PT(R18)-PT(R11) | ||
963 | ld8.fill r17=[r3],16 | ||
964 | ;; | ||
965 | ld8.fill r18=[r2],16 | ||
966 | ld8.fill r19=[r3],16 | ||
967 | ;; | ||
968 | ld8.fill r20=[r2],16 | ||
969 | ld8.fill r21=[r3],16 | ||
970 | mov ar.csd=r30 | ||
971 | mov ar.ssd=r31 | ||
972 | ;; | ||
973 | rsm psr.i | psr.ic | ||
974 | // initiate turning off of interrupt and interruption collection | ||
975 | invala // invalidate ALAT | ||
976 | ;; | ||
977 | srlz.i | ||
978 | ;; | ||
979 | ld8.fill r22=[r2],24 | ||
980 | ld8.fill r23=[r3],24 | ||
981 | mov b6=r28 | ||
982 | ;; | ||
983 | ld8.fill r25=[r2],16 | ||
984 | ld8.fill r26=[r3],16 | ||
985 | mov b7=r29 | ||
986 | ;; | ||
987 | ld8.fill r27=[r2],16 | ||
988 | ld8.fill r28=[r3],16 | ||
989 | ;; | ||
990 | ld8.fill r29=[r2],16 | ||
991 | ld8.fill r30=[r3],24 | ||
992 | ;; | ||
993 | ld8.fill r31=[r2],PT(F9)-PT(R31) | ||
994 | adds r3=PT(F10)-PT(F6),r3 | ||
995 | ;; | ||
996 | ldf.fill f9=[r2],PT(F6)-PT(F9) | ||
997 | ldf.fill f10=[r3],PT(F8)-PT(F10) | ||
998 | ;; | ||
999 | ldf.fill f6=[r2],PT(F7)-PT(F6) | ||
1000 | ;; | ||
1001 | ldf.fill f7=[r2],PT(F11)-PT(F7) | ||
1002 | ldf.fill f8=[r3],32 | ||
1003 | ;; | ||
1004 | srlz.i // ensure interruption collection is off | ||
1005 | mov ar.ccv=r15 | ||
1006 | ;; | ||
1007 | bsw.0 // switch back to bank 0 (no stop bit required beforehand...) | ||
1008 | ;; | ||
1009 | ldf.fill f11=[r2] | ||
1010 | // mov r18=r13 | ||
1011 | // mov r21=r13 | ||
1012 | adds r16=PT(CR_IPSR)+16,r12 | ||
1013 | adds r17=PT(CR_IIP)+16,r12 | ||
1014 | ;; | ||
1015 | ld8 r29=[r16],16 // load cr.ipsr | ||
1016 | ld8 r28=[r17],16 // load cr.iip | ||
1017 | ;; | ||
1018 | ld8 r30=[r16],16 // load cr.ifs | ||
1019 | ld8 r25=[r17],16 // load ar.unat | ||
1020 | ;; | ||
1021 | ld8 r26=[r16],16 // load ar.pfs | ||
1022 | ld8 r27=[r17],16 // load ar.rsc | ||
1023 | cmp.eq p9,p0=r0,r0 | ||
1024 | // set p9 to indicate that we should restore cr.ifs | ||
1025 | ;; | ||
1026 | ld8 r24=[r16],16 // load ar.rnat (may be garbage) | ||
1027 | ld8 r23=[r17],16// load ar.bspstore (may be garbage) | ||
1028 | ;; | ||
1029 | ld8 r31=[r16],16 // load predicates | ||
1030 | ld8 r22=[r17],16 // load b0 | ||
1031 | ;; | ||
1032 | ld8 r19=[r16],16 // load ar.rsc value for "loadrs" | ||
1033 | ld8.fill r1=[r17],16 // load r1 | ||
1034 | ;; | ||
1035 | ld8.fill r12=[r16],16 | ||
1036 | ld8.fill r13=[r17],16 | ||
1037 | ;; | ||
1038 | ld8 r20=[r16],16 // ar.fpsr | ||
1039 | ld8.fill r15=[r17],16 | ||
1040 | ;; | ||
1041 | ld8.fill r14=[r16],16 | ||
1042 | ld8.fill r2=[r17] | ||
1043 | ;; | ||
1044 | ld8.fill r3=[r16] | ||
1045 | ;; | ||
1046 | mov r16=ar.bsp // get existing backing store pointer | ||
1047 | ;; | ||
1048 | mov b0=r22 | ||
1049 | mov ar.pfs=r26 | ||
1050 | mov cr.ifs=r30 | ||
1051 | mov cr.ipsr=r29 | ||
1052 | mov ar.fpsr=r20 | ||
1053 | mov cr.iip=r28 | ||
1054 | ;; | ||
1055 | mov ar.rsc=r27 | ||
1056 | mov ar.unat=r25 | ||
1057 | mov pr=r31,-1 | ||
1058 | rfi | ||
1059 | END(ia64_leave_nested) | ||
1060 | |||
1061 | |||
1062 | |||
1063 | GLOBAL_ENTRY(ia64_leave_hypervisor_prepare) | ||
1064 | /* | ||
1065 | * work.need_resched etc. mustn't get changed | ||
1066 | *by this CPU before it returns to | ||
1067 | ;; | ||
1068 | * user- or fsys-mode, hence we disable interrupts early on: | ||
1069 | */ | ||
1070 | adds r2 = PT(R4)+16,r12 | ||
1071 | adds r3 = PT(R5)+16,r12 | ||
1072 | adds r8 = PT(EML_UNAT)+16,r12 | ||
1073 | ;; | ||
1074 | ld8 r8 = [r8] | ||
1075 | ;; | ||
1076 | mov ar.unat=r8 | ||
1077 | ;; | ||
1078 | ld8.fill r4=[r2],16 //load r4 | ||
1079 | ld8.fill r5=[r3],16 //load r5 | ||
1080 | ;; | ||
1081 | ld8.fill r6=[r2] //load r6 | ||
1082 | ld8.fill r7=[r3] //load r7 | ||
1083 | ;; | ||
1084 | END(ia64_leave_hypervisor_prepare) | ||
1085 | //fall through | ||
1086 | GLOBAL_ENTRY(ia64_leave_hypervisor) | ||
1087 | rsm psr.i | ||
1088 | ;; | ||
1089 | br.call.sptk.many b0=leave_hypervisor_tail | ||
1090 | ;; | ||
1091 | adds r20=PT(PR)+16,r12 | ||
1092 | adds r8=PT(EML_UNAT)+16,r12 | ||
1093 | ;; | ||
1094 | ld8 r8=[r8] | ||
1095 | ;; | ||
1096 | mov ar.unat=r8 | ||
1097 | ;; | ||
1098 | lfetch [r20],PT(CR_IPSR)-PT(PR) | ||
1099 | adds r2 = PT(B6)+16,r12 | ||
1100 | adds r3 = PT(B7)+16,r12 | ||
1101 | ;; | ||
1102 | lfetch [r20] | ||
1103 | ;; | ||
1104 | ld8 r24=[r2],16 /* B6 */ | ||
1105 | ld8 r25=[r3],16 /* B7 */ | ||
1106 | ;; | ||
1107 | ld8 r26=[r2],16 /* ar_csd */ | ||
1108 | ld8 r27=[r3],16 /* ar_ssd */ | ||
1109 | mov b6 = r24 | ||
1110 | ;; | ||
1111 | ld8.fill r8=[r2],16 | ||
1112 | ld8.fill r9=[r3],16 | ||
1113 | mov b7 = r25 | ||
1114 | ;; | ||
1115 | mov ar.csd = r26 | ||
1116 | mov ar.ssd = r27 | ||
1117 | ;; | ||
1118 | ld8.fill r10=[r2],PT(R15)-PT(R10) | ||
1119 | ld8.fill r11=[r3],PT(R14)-PT(R11) | ||
1120 | ;; | ||
1121 | ld8.fill r15=[r2],PT(R16)-PT(R15) | ||
1122 | ld8.fill r14=[r3],PT(R17)-PT(R14) | ||
1123 | ;; | ||
1124 | ld8.fill r16=[r2],16 | ||
1125 | ld8.fill r17=[r3],16 | ||
1126 | ;; | ||
1127 | ld8.fill r18=[r2],16 | ||
1128 | ld8.fill r19=[r3],16 | ||
1129 | ;; | ||
1130 | ld8.fill r20=[r2],16 | ||
1131 | ld8.fill r21=[r3],16 | ||
1132 | ;; | ||
1133 | ld8.fill r22=[r2],16 | ||
1134 | ld8.fill r23=[r3],16 | ||
1135 | ;; | ||
1136 | ld8.fill r24=[r2],16 | ||
1137 | ld8.fill r25=[r3],16 | ||
1138 | ;; | ||
1139 | ld8.fill r26=[r2],16 | ||
1140 | ld8.fill r27=[r3],16 | ||
1141 | ;; | ||
1142 | ld8.fill r28=[r2],16 | ||
1143 | ld8.fill r29=[r3],16 | ||
1144 | ;; | ||
1145 | ld8.fill r30=[r2],PT(F6)-PT(R30) | ||
1146 | ld8.fill r31=[r3],PT(F7)-PT(R31) | ||
1147 | ;; | ||
1148 | rsm psr.i | psr.ic | ||
1149 | // initiate turning off of interrupt and interruption collection | ||
1150 | invala // invalidate ALAT | ||
1151 | ;; | ||
1152 | srlz.i // ensure interruption collection is off | ||
1153 | ;; | ||
1154 | bsw.0 | ||
1155 | ;; | ||
1156 | adds r16 = PT(CR_IPSR)+16,r12 | ||
1157 | adds r17 = PT(CR_IIP)+16,r12 | ||
1158 | mov r21=r13 // get current | ||
1159 | ;; | ||
1160 | ld8 r31=[r16],16 // load cr.ipsr | ||
1161 | ld8 r30=[r17],16 // load cr.iip | ||
1162 | ;; | ||
1163 | ld8 r29=[r16],16 // load cr.ifs | ||
1164 | ld8 r28=[r17],16 // load ar.unat | ||
1165 | ;; | ||
1166 | ld8 r27=[r16],16 // load ar.pfs | ||
1167 | ld8 r26=[r17],16 // load ar.rsc | ||
1168 | ;; | ||
1169 | ld8 r25=[r16],16 // load ar.rnat | ||
1170 | ld8 r24=[r17],16 // load ar.bspstore | ||
1171 | ;; | ||
1172 | ld8 r23=[r16],16 // load predicates | ||
1173 | ld8 r22=[r17],16 // load b0 | ||
1174 | ;; | ||
1175 | ld8 r20=[r16],16 // load ar.rsc value for "loadrs" | ||
1176 | ld8.fill r1=[r17],16 //load r1 | ||
1177 | ;; | ||
1178 | ld8.fill r12=[r16],16 //load r12 | ||
1179 | ld8.fill r13=[r17],PT(R2)-PT(R13) //load r13 | ||
1180 | ;; | ||
1181 | ld8 r19=[r16],PT(R3)-PT(AR_FPSR) //load ar_fpsr | ||
1182 | ld8.fill r2=[r17],PT(AR_CCV)-PT(R2) //load r2 | ||
1183 | ;; | ||
1184 | ld8.fill r3=[r16] //load r3 | ||
1185 | ld8 r18=[r17] //load ar_ccv | ||
1186 | ;; | ||
1187 | mov ar.fpsr=r19 | ||
1188 | mov ar.ccv=r18 | ||
1189 | shr.u r18=r20,16 | ||
1190 | ;; | ||
1191 | kvm_rbs_switch: | ||
1192 | mov r19=96 | ||
1193 | |||
1194 | kvm_dont_preserve_current_frame: | ||
1195 | /* | ||
1196 | * To prevent leaking bits between the hypervisor and guest domain, | ||
1197 | * we must clear the stacked registers in the "invalid" partition here. | ||
1198 | * 5 registers/cycle on McKinley). | ||
1199 | */ | ||
1200 | # define pRecurse p6 | ||
1201 | # define pReturn p7 | ||
1202 | # define Nregs 14 | ||
1203 | |||
1204 | alloc loc0=ar.pfs,2,Nregs-2,2,0 | ||
1205 | shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8)) | ||
1206 | sub r19=r19,r18 // r19 = (physStackedSize + 8) - dirtySize | ||
1207 | ;; | ||
1208 | mov ar.rsc=r20 // load ar.rsc to be used for "loadrs" | ||
1209 | shladd in0=loc1,3,r19 | ||
1210 | mov in1=0 | ||
1211 | ;; | ||
1212 | TEXT_ALIGN(32) | ||
1213 | kvm_rse_clear_invalid: | ||
1214 | alloc loc0=ar.pfs,2,Nregs-2,2,0 | ||
1215 | cmp.lt pRecurse,p0=Nregs*8,in0 | ||
1216 | // if more than Nregs regs left to clear, (re)curse | ||
1217 | add out0=-Nregs*8,in0 | ||
1218 | add out1=1,in1 // increment recursion count | ||
1219 | mov loc1=0 | ||
1220 | mov loc2=0 | ||
1221 | ;; | ||
1222 | mov loc3=0 | ||
1223 | mov loc4=0 | ||
1224 | mov loc5=0 | ||
1225 | mov loc6=0 | ||
1226 | mov loc7=0 | ||
1227 | (pRecurse) br.call.dptk.few b0=kvm_rse_clear_invalid | ||
1228 | ;; | ||
1229 | mov loc8=0 | ||
1230 | mov loc9=0 | ||
1231 | cmp.ne pReturn,p0=r0,in1 | ||
1232 | // if recursion count != 0, we need to do a br.ret | ||
1233 | mov loc10=0 | ||
1234 | mov loc11=0 | ||
1235 | (pReturn) br.ret.dptk.many b0 | ||
1236 | |||
1237 | # undef pRecurse | ||
1238 | # undef pReturn | ||
1239 | |||
1240 | // loadrs has already been shifted | ||
1241 | alloc r16=ar.pfs,0,0,0,0 // drop current register frame | ||
1242 | ;; | ||
1243 | loadrs | ||
1244 | ;; | ||
1245 | mov ar.bspstore=r24 | ||
1246 | ;; | ||
1247 | mov ar.unat=r28 | ||
1248 | mov ar.rnat=r25 | ||
1249 | mov ar.rsc=r26 | ||
1250 | ;; | ||
1251 | mov cr.ipsr=r31 | ||
1252 | mov cr.iip=r30 | ||
1253 | mov cr.ifs=r29 | ||
1254 | mov ar.pfs=r27 | ||
1255 | adds r18=VMM_VPD_BASE_OFFSET,r21 | ||
1256 | ;; | ||
1257 | ld8 r18=[r18] //vpd | ||
1258 | adds r17=VMM_VCPU_ISR_OFFSET,r21 | ||
1259 | ;; | ||
1260 | ld8 r17=[r17] | ||
1261 | adds r19=VMM_VPD_VPSR_OFFSET,r18 | ||
1262 | ;; | ||
1263 | ld8 r19=[r19] //vpsr | ||
1264 | adds r20=VMM_VCPU_VSA_BASE_OFFSET,r21 | ||
1265 | ;; | ||
1266 | ld8 r20=[r20] | ||
1267 | ;; | ||
1268 | //vsa_sync_write_start | ||
1269 | mov r25=r18 | ||
1270 | adds r16= VMM_VCPU_GP_OFFSET,r21 | ||
1271 | ;; | ||
1272 | ld8 r16= [r16] // Put gp in r24 | ||
1273 | movl r24=@gprel(ia64_vmm_entry) // calculate return address | ||
1274 | ;; | ||
1275 | add r24=r24,r16 | ||
1276 | ;; | ||
1277 | add r16=PAL_VPS_SYNC_WRITE,r20 | ||
1278 | ;; | ||
1279 | mov b0=r16 | ||
1280 | br.cond.sptk b0 // call the service | ||
1281 | ;; | ||
1282 | END(ia64_leave_hypervisor) | ||
1283 | // fall through | ||
1284 | GLOBAL_ENTRY(ia64_vmm_entry) | ||
1285 | /* | ||
1286 | * must be at bank 0 | ||
1287 | * parameter: | ||
1288 | * r17:cr.isr | ||
1289 | * r18:vpd | ||
1290 | * r19:vpsr | ||
1291 | * r20:__vsa_base | ||
1292 | * r22:b0 | ||
1293 | * r23:predicate | ||
1294 | */ | ||
1295 | mov r24=r22 | ||
1296 | mov r25=r18 | ||
1297 | tbit.nz p1,p2 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic | ||
1298 | ;; | ||
1299 | (p1) add r29=PAL_VPS_RESUME_NORMAL,r20 | ||
1300 | (p1) br.sptk.many ia64_vmm_entry_out | ||
1301 | ;; | ||
1302 | tbit.nz p1,p2 = r17,IA64_ISR_IR_BIT //p1=cr.isr.ir | ||
1303 | ;; | ||
1304 | (p1) add r29=PAL_VPS_RESUME_NORMAL,r20 | ||
1305 | (p2) add r29=PAL_VPS_RESUME_HANDLER,r20 | ||
1306 | (p2) ld8 r26=[r25] | ||
1307 | ;; | ||
1308 | ia64_vmm_entry_out: | ||
1309 | mov pr=r23,-2 | ||
1310 | mov b0=r29 | ||
1311 | ;; | ||
1312 | br.cond.sptk b0 // call pal service | ||
1313 | END(ia64_vmm_entry) | ||
1314 | |||
1315 | |||
1316 | |||
1317 | /* | ||
1318 | * extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2, | ||
1319 | * u64 arg3, u64 arg4, u64 arg5, | ||
1320 | * u64 arg6, u64 arg7); | ||
1321 | * | ||
1322 | * XXX: The currently defined services use only 4 args at the max. The | ||
1323 | * rest are not consumed. | ||
1324 | */ | ||
1325 | GLOBAL_ENTRY(ia64_call_vsa) | ||
1326 | .regstk 4,4,0,0 | ||
1327 | |||
1328 | rpsave = loc0 | ||
1329 | pfssave = loc1 | ||
1330 | psrsave = loc2 | ||
1331 | entry = loc3 | ||
1332 | hostret = r24 | ||
1333 | |||
1334 | alloc pfssave=ar.pfs,4,4,0,0 | ||
1335 | mov rpsave=rp | ||
1336 | adds entry=VMM_VCPU_VSA_BASE_OFFSET, r13 | ||
1337 | ;; | ||
1338 | ld8 entry=[entry] | ||
1339 | 1: mov hostret=ip | ||
1340 | mov r25=in1 // copy arguments | ||
1341 | mov r26=in2 | ||
1342 | mov r27=in3 | ||
1343 | mov psrsave=psr | ||
1344 | ;; | ||
1345 | tbit.nz p6,p0=psrsave,14 // IA64_PSR_I | ||
1346 | tbit.nz p7,p0=psrsave,13 // IA64_PSR_IC | ||
1347 | ;; | ||
1348 | add hostret=2f-1b,hostret // calculate return address | ||
1349 | add entry=entry,in0 | ||
1350 | ;; | ||
1351 | rsm psr.i | psr.ic | ||
1352 | ;; | ||
1353 | srlz.i | ||
1354 | mov b6=entry | ||
1355 | br.cond.sptk b6 // call the service | ||
1356 | 2: | ||
1357 | // Architectural sequence for enabling interrupts if necessary | ||
1358 | (p7) ssm psr.ic | ||
1359 | ;; | ||
1360 | (p7) srlz.i | ||
1361 | ;; | ||
1362 | //(p6) ssm psr.i | ||
1363 | ;; | ||
1364 | mov rp=rpsave | ||
1365 | mov ar.pfs=pfssave | ||
1366 | mov r8=r31 | ||
1367 | ;; | ||
1368 | srlz.d | ||
1369 | br.ret.sptk rp | ||
1370 | |||
1371 | END(ia64_call_vsa) | ||
1372 | |||
1373 | #define INIT_BSPSTORE ((4<<30)-(12<<20)-0x100) | ||
1374 | |||
1375 | GLOBAL_ENTRY(vmm_reset_entry) | ||
1376 | //set up ipsr, iip, vpd.vpsr, dcr | ||
1377 | // For IPSR: it/dt/rt=1, i/ic=1, si=1, vm/bn=1 | ||
1378 | // For DCR: all bits 0 | ||
1379 | adds r14=-VMM_PT_REGS_SIZE, r12 | ||
1380 | ;; | ||
1381 | movl r6=0x501008826000 // IPSR dt/rt/it:1;i/ic:1, si:1, vm/bn:1 | ||
1382 | movl r10=0x8000000000000000 | ||
1383 | adds r16=PT(CR_IIP), r14 | ||
1384 | adds r20=PT(R1), r14 | ||
1385 | ;; | ||
1386 | rsm psr.ic | psr.i | ||
1387 | ;; | ||
1388 | srlz.i | ||
1389 | ;; | ||
1390 | bsw.0 | ||
1391 | ;; | ||
1392 | mov r21 =r13 | ||
1393 | ;; | ||
1394 | bsw.1 | ||
1395 | ;; | ||
1396 | mov ar.rsc = 0 | ||
1397 | ;; | ||
1398 | flushrs | ||
1399 | ;; | ||
1400 | mov ar.bspstore = 0 | ||
1401 | // clear BSPSTORE | ||
1402 | ;; | ||
1403 | mov cr.ipsr=r6 | ||
1404 | mov cr.ifs=r10 | ||
1405 | ld8 r4 = [r16] // Set init iip for first run. | ||
1406 | ld8 r1 = [r20] | ||
1407 | ;; | ||
1408 | mov cr.iip=r4 | ||
1409 | ;; | ||
1410 | adds r16=VMM_VPD_BASE_OFFSET,r13 | ||
1411 | adds r20=VMM_VCPU_VSA_BASE_OFFSET,r13 | ||
1412 | ;; | ||
1413 | ld8 r18=[r16] | ||
1414 | ld8 r20=[r20] | ||
1415 | ;; | ||
1416 | adds r19=VMM_VPD_VPSR_OFFSET,r18 | ||
1417 | ;; | ||
1418 | ld8 r19=[r19] | ||
1419 | mov r17=r0 | ||
1420 | mov r22=r0 | ||
1421 | mov r23=r0 | ||
1422 | br.cond.sptk ia64_vmm_entry | ||
1423 | br.ret.sptk b0 | ||
1424 | END(vmm_reset_entry) | ||
diff --git a/arch/ia64/kvm/vti.h b/arch/ia64/kvm/vti.h new file mode 100644 index 000000000000..f6c5617e16af --- /dev/null +++ b/arch/ia64/kvm/vti.h | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * vti.h: prototype for generial vt related interface | ||
3 | * Copyright (c) 2004, Intel Corporation. | ||
4 | * | ||
5 | * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com) | ||
6 | * Fred Yang (fred.yang@intel.com) | ||
7 | * Kun Tian (Kevin Tian) (kevin.tian@intel.com) | ||
8 | * | ||
9 | * Copyright (c) 2007, Intel Corporation. | ||
10 | * Zhang xiantao <xiantao.zhang@intel.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms and conditions of the GNU General Public License, | ||
14 | * version 2, as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
19 | * more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along with | ||
22 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
23 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
24 | */ | ||
25 | #ifndef _KVM_VT_I_H | ||
26 | #define _KVM_VT_I_H | ||
27 | |||
28 | #ifndef __ASSEMBLY__ | ||
29 | #include <asm/page.h> | ||
30 | |||
31 | #include <linux/kvm_host.h> | ||
32 | |||
33 | /* define itr.i and itr.d in ia64_itr function */ | ||
34 | #define ITR 0x01 | ||
35 | #define DTR 0x02 | ||
36 | #define IaDTR 0x03 | ||
37 | |||
38 | #define IA64_TR_VMM 6 /*itr6, dtr6 : maps vmm code, vmbuffer*/ | ||
39 | #define IA64_TR_VM_DATA 7 /*dtr7 : maps current vm data*/ | ||
40 | |||
41 | #define RR6 (6UL<<61) | ||
42 | #define RR7 (7UL<<61) | ||
43 | |||
44 | |||
45 | /* config_options in pal_vp_init_env */ | ||
46 | #define VP_INITIALIZE 1UL | ||
47 | #define VP_FR_PMC 1UL<<1 | ||
48 | #define VP_OPCODE 1UL<<8 | ||
49 | #define VP_CAUSE 1UL<<9 | ||
50 | #define VP_FW_ACC 1UL<<63 | ||
51 | |||
52 | /* init vp env with initializing vm_buffer */ | ||
53 | #define VP_INIT_ENV_INITALIZE (VP_INITIALIZE | VP_FR_PMC |\ | ||
54 | VP_OPCODE | VP_CAUSE | VP_FW_ACC) | ||
55 | /* init vp env without initializing vm_buffer */ | ||
56 | #define VP_INIT_ENV VP_FR_PMC | VP_OPCODE | VP_CAUSE | VP_FW_ACC | ||
57 | |||
58 | #define PAL_VP_CREATE 265 | ||
59 | /* Stacked Virt. Initializes a new VPD for the operation of | ||
60 | * a new virtual processor in the virtual environment. | ||
61 | */ | ||
62 | #define PAL_VP_ENV_INFO 266 | ||
63 | /*Stacked Virt. Returns the parameters needed to enter a virtual environment.*/ | ||
64 | #define PAL_VP_EXIT_ENV 267 | ||
65 | /*Stacked Virt. Allows a logical processor to exit a virtual environment.*/ | ||
66 | #define PAL_VP_INIT_ENV 268 | ||
67 | /*Stacked Virt. Allows a logical processor to enter a virtual environment.*/ | ||
68 | #define PAL_VP_REGISTER 269 | ||
69 | /*Stacked Virt. Register a different host IVT for the virtual processor.*/ | ||
70 | #define PAL_VP_RESUME 270 | ||
71 | /* Renamed from PAL_VP_RESUME */ | ||
72 | #define PAL_VP_RESTORE 270 | ||
73 | /*Stacked Virt. Resumes virtual processor operation on the logical processor.*/ | ||
74 | #define PAL_VP_SUSPEND 271 | ||
75 | /* Renamed from PAL_VP_SUSPEND */ | ||
76 | #define PAL_VP_SAVE 271 | ||
77 | /* Stacked Virt. Suspends operation for the specified virtual processor on | ||
78 | * the logical processor. | ||
79 | */ | ||
80 | #define PAL_VP_TERMINATE 272 | ||
81 | /* Stacked Virt. Terminates operation for the specified virtual processor.*/ | ||
82 | |||
83 | union vac { | ||
84 | unsigned long value; | ||
85 | struct { | ||
86 | int a_int:1; | ||
87 | int a_from_int_cr:1; | ||
88 | int a_to_int_cr:1; | ||
89 | int a_from_psr:1; | ||
90 | int a_from_cpuid:1; | ||
91 | int a_cover:1; | ||
92 | int a_bsw:1; | ||
93 | long reserved:57; | ||
94 | }; | ||
95 | }; | ||
96 | |||
97 | union vdc { | ||
98 | unsigned long value; | ||
99 | struct { | ||
100 | int d_vmsw:1; | ||
101 | int d_extint:1; | ||
102 | int d_ibr_dbr:1; | ||
103 | int d_pmc:1; | ||
104 | int d_to_pmd:1; | ||
105 | int d_itm:1; | ||
106 | long reserved:58; | ||
107 | }; | ||
108 | }; | ||
109 | |||
110 | struct vpd { | ||
111 | union vac vac; | ||
112 | union vdc vdc; | ||
113 | unsigned long virt_env_vaddr; | ||
114 | unsigned long reserved1[29]; | ||
115 | unsigned long vhpi; | ||
116 | unsigned long reserved2[95]; | ||
117 | unsigned long vgr[16]; | ||
118 | unsigned long vbgr[16]; | ||
119 | unsigned long vnat; | ||
120 | unsigned long vbnat; | ||
121 | unsigned long vcpuid[5]; | ||
122 | unsigned long reserved3[11]; | ||
123 | unsigned long vpsr; | ||
124 | unsigned long vpr; | ||
125 | unsigned long reserved4[76]; | ||
126 | union { | ||
127 | unsigned long vcr[128]; | ||
128 | struct { | ||
129 | unsigned long dcr; | ||
130 | unsigned long itm; | ||
131 | unsigned long iva; | ||
132 | unsigned long rsv1[5]; | ||
133 | unsigned long pta; | ||
134 | unsigned long rsv2[7]; | ||
135 | unsigned long ipsr; | ||
136 | unsigned long isr; | ||
137 | unsigned long rsv3; | ||
138 | unsigned long iip; | ||
139 | unsigned long ifa; | ||
140 | unsigned long itir; | ||
141 | unsigned long iipa; | ||
142 | unsigned long ifs; | ||
143 | unsigned long iim; | ||
144 | unsigned long iha; | ||
145 | unsigned long rsv4[38]; | ||
146 | unsigned long lid; | ||
147 | unsigned long ivr; | ||
148 | unsigned long tpr; | ||
149 | unsigned long eoi; | ||
150 | unsigned long irr[4]; | ||
151 | unsigned long itv; | ||
152 | unsigned long pmv; | ||
153 | unsigned long cmcv; | ||
154 | unsigned long rsv5[5]; | ||
155 | unsigned long lrr0; | ||
156 | unsigned long lrr1; | ||
157 | unsigned long rsv6[46]; | ||
158 | }; | ||
159 | }; | ||
160 | unsigned long reserved5[128]; | ||
161 | unsigned long reserved6[3456]; | ||
162 | unsigned long vmm_avail[128]; | ||
163 | unsigned long reserved7[4096]; | ||
164 | }; | ||
165 | |||
166 | #define PAL_PROC_VM_BIT (1UL << 40) | ||
167 | #define PAL_PROC_VMSW_BIT (1UL << 54) | ||
168 | |||
169 | static inline s64 ia64_pal_vp_env_info(u64 *buffer_size, | ||
170 | u64 *vp_env_info) | ||
171 | { | ||
172 | struct ia64_pal_retval iprv; | ||
173 | PAL_CALL_STK(iprv, PAL_VP_ENV_INFO, 0, 0, 0); | ||
174 | *buffer_size = iprv.v0; | ||
175 | *vp_env_info = iprv.v1; | ||
176 | return iprv.status; | ||
177 | } | ||
178 | |||
179 | static inline s64 ia64_pal_vp_exit_env(u64 iva) | ||
180 | { | ||
181 | struct ia64_pal_retval iprv; | ||
182 | |||
183 | PAL_CALL_STK(iprv, PAL_VP_EXIT_ENV, (u64)iva, 0, 0); | ||
184 | return iprv.status; | ||
185 | } | ||
186 | |||
187 | static inline s64 ia64_pal_vp_init_env(u64 config_options, u64 pbase_addr, | ||
188 | u64 vbase_addr, u64 *vsa_base) | ||
189 | { | ||
190 | struct ia64_pal_retval iprv; | ||
191 | |||
192 | PAL_CALL_STK(iprv, PAL_VP_INIT_ENV, config_options, pbase_addr, | ||
193 | vbase_addr); | ||
194 | *vsa_base = iprv.v0; | ||
195 | |||
196 | return iprv.status; | ||
197 | } | ||
198 | |||
199 | static inline s64 ia64_pal_vp_restore(u64 *vpd, u64 pal_proc_vector) | ||
200 | { | ||
201 | struct ia64_pal_retval iprv; | ||
202 | |||
203 | PAL_CALL_STK(iprv, PAL_VP_RESTORE, (u64)vpd, pal_proc_vector, 0); | ||
204 | |||
205 | return iprv.status; | ||
206 | } | ||
207 | |||
208 | static inline s64 ia64_pal_vp_save(u64 *vpd, u64 pal_proc_vector) | ||
209 | { | ||
210 | struct ia64_pal_retval iprv; | ||
211 | |||
212 | PAL_CALL_STK(iprv, PAL_VP_SAVE, (u64)vpd, pal_proc_vector, 0); | ||
213 | |||
214 | return iprv.status; | ||
215 | } | ||
216 | |||
217 | #endif | ||
218 | |||
219 | /*VPD field offset*/ | ||
220 | #define VPD_VAC_START_OFFSET 0 | ||
221 | #define VPD_VDC_START_OFFSET 8 | ||
222 | #define VPD_VHPI_START_OFFSET 256 | ||
223 | #define VPD_VGR_START_OFFSET 1024 | ||
224 | #define VPD_VBGR_START_OFFSET 1152 | ||
225 | #define VPD_VNAT_START_OFFSET 1280 | ||
226 | #define VPD_VBNAT_START_OFFSET 1288 | ||
227 | #define VPD_VCPUID_START_OFFSET 1296 | ||
228 | #define VPD_VPSR_START_OFFSET 1424 | ||
229 | #define VPD_VPR_START_OFFSET 1432 | ||
230 | #define VPD_VRSE_CFLE_START_OFFSET 1440 | ||
231 | #define VPD_VCR_START_OFFSET 2048 | ||
232 | #define VPD_VTPR_START_OFFSET 2576 | ||
233 | #define VPD_VRR_START_OFFSET 3072 | ||
234 | #define VPD_VMM_VAIL_START_OFFSET 31744 | ||
235 | |||
236 | /*Virtualization faults*/ | ||
237 | |||
238 | #define EVENT_MOV_TO_AR 1 | ||
239 | #define EVENT_MOV_TO_AR_IMM 2 | ||
240 | #define EVENT_MOV_FROM_AR 3 | ||
241 | #define EVENT_MOV_TO_CR 4 | ||
242 | #define EVENT_MOV_FROM_CR 5 | ||
243 | #define EVENT_MOV_TO_PSR 6 | ||
244 | #define EVENT_MOV_FROM_PSR 7 | ||
245 | #define EVENT_ITC_D 8 | ||
246 | #define EVENT_ITC_I 9 | ||
247 | #define EVENT_MOV_TO_RR 10 | ||
248 | #define EVENT_MOV_TO_DBR 11 | ||
249 | #define EVENT_MOV_TO_IBR 12 | ||
250 | #define EVENT_MOV_TO_PKR 13 | ||
251 | #define EVENT_MOV_TO_PMC 14 | ||
252 | #define EVENT_MOV_TO_PMD 15 | ||
253 | #define EVENT_ITR_D 16 | ||
254 | #define EVENT_ITR_I 17 | ||
255 | #define EVENT_MOV_FROM_RR 18 | ||
256 | #define EVENT_MOV_FROM_DBR 19 | ||
257 | #define EVENT_MOV_FROM_IBR 20 | ||
258 | #define EVENT_MOV_FROM_PKR 21 | ||
259 | #define EVENT_MOV_FROM_PMC 22 | ||
260 | #define EVENT_MOV_FROM_CPUID 23 | ||
261 | #define EVENT_SSM 24 | ||
262 | #define EVENT_RSM 25 | ||
263 | #define EVENT_PTC_L 26 | ||
264 | #define EVENT_PTC_G 27 | ||
265 | #define EVENT_PTC_GA 28 | ||
266 | #define EVENT_PTR_D 29 | ||
267 | #define EVENT_PTR_I 30 | ||
268 | #define EVENT_THASH 31 | ||
269 | #define EVENT_TTAG 32 | ||
270 | #define EVENT_TPA 33 | ||
271 | #define EVENT_TAK 34 | ||
272 | #define EVENT_PTC_E 35 | ||
273 | #define EVENT_COVER 36 | ||
274 | #define EVENT_RFI 37 | ||
275 | #define EVENT_BSW_0 38 | ||
276 | #define EVENT_BSW_1 39 | ||
277 | #define EVENT_VMSW 40 | ||
278 | |||
279 | /**PAL virtual services offsets */ | ||
280 | #define PAL_VPS_RESUME_NORMAL 0x0000 | ||
281 | #define PAL_VPS_RESUME_HANDLER 0x0400 | ||
282 | #define PAL_VPS_SYNC_READ 0x0800 | ||
283 | #define PAL_VPS_SYNC_WRITE 0x0c00 | ||
284 | #define PAL_VPS_SET_PENDING_INTERRUPT 0x1000 | ||
285 | #define PAL_VPS_THASH 0x1400 | ||
286 | #define PAL_VPS_TTAG 0x1800 | ||
287 | #define PAL_VPS_RESTORE 0x1c00 | ||
288 | #define PAL_VPS_SAVE 0x2000 | ||
289 | |||
290 | #endif/* _VT_I_H*/ | ||
diff --git a/arch/ia64/kvm/vtlb.c b/arch/ia64/kvm/vtlb.c new file mode 100644 index 000000000000..def4576d22b1 --- /dev/null +++ b/arch/ia64/kvm/vtlb.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | * vtlb.c: guest virtual tlb handling module. | ||
3 | * Copyright (c) 2004, Intel Corporation. | ||
4 | * Yaozu Dong (Eddie Dong) <Eddie.dong@intel.com> | ||
5 | * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com> | ||
6 | * | ||
7 | * Copyright (c) 2007, Intel Corporation. | ||
8 | * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com> | ||
9 | * Xiantao Zhang <xiantao.zhang@intel.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms and conditions of the GNU General Public License, | ||
13 | * version 2, as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along with | ||
21 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
22 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "vcpu.h" | ||
27 | |||
28 | #include <linux/rwsem.h> | ||
29 | |||
30 | #include <asm/tlb.h> | ||
31 | |||
32 | /* | ||
33 | * Check to see if the address rid:va is translated by the TLB | ||
34 | */ | ||
35 | |||
36 | static int __is_tr_translated(struct thash_data *trp, u64 rid, u64 va) | ||
37 | { | ||
38 | return ((trp->p) && (trp->rid == rid) | ||
39 | && ((va-trp->vadr) < PSIZE(trp->ps))); | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * Only for GUEST TR format. | ||
44 | */ | ||
45 | static int __is_tr_overlap(struct thash_data *trp, u64 rid, u64 sva, u64 eva) | ||
46 | { | ||
47 | u64 sa1, ea1; | ||
48 | |||
49 | if (!trp->p || trp->rid != rid) | ||
50 | return 0; | ||
51 | |||
52 | sa1 = trp->vadr; | ||
53 | ea1 = sa1 + PSIZE(trp->ps) - 1; | ||
54 | eva -= 1; | ||
55 | if ((sva > ea1) || (sa1 > eva)) | ||
56 | return 0; | ||
57 | else | ||
58 | return 1; | ||
59 | |||
60 | } | ||
61 | |||
62 | void machine_tlb_purge(u64 va, u64 ps) | ||
63 | { | ||
64 | ia64_ptcl(va, ps << 2); | ||
65 | } | ||
66 | |||
67 | void local_flush_tlb_all(void) | ||
68 | { | ||
69 | int i, j; | ||
70 | unsigned long flags, count0, count1; | ||
71 | unsigned long stride0, stride1, addr; | ||
72 | |||
73 | addr = current_vcpu->arch.ptce_base; | ||
74 | count0 = current_vcpu->arch.ptce_count[0]; | ||
75 | count1 = current_vcpu->arch.ptce_count[1]; | ||
76 | stride0 = current_vcpu->arch.ptce_stride[0]; | ||
77 | stride1 = current_vcpu->arch.ptce_stride[1]; | ||
78 | |||
79 | local_irq_save(flags); | ||
80 | for (i = 0; i < count0; ++i) { | ||
81 | for (j = 0; j < count1; ++j) { | ||
82 | ia64_ptce(addr); | ||
83 | addr += stride1; | ||
84 | } | ||
85 | addr += stride0; | ||
86 | } | ||
87 | local_irq_restore(flags); | ||
88 | ia64_srlz_i(); /* srlz.i implies srlz.d */ | ||
89 | } | ||
90 | |||
91 | int vhpt_enabled(struct kvm_vcpu *vcpu, u64 vadr, enum vhpt_ref ref) | ||
92 | { | ||
93 | union ia64_rr vrr; | ||
94 | union ia64_pta vpta; | ||
95 | struct ia64_psr vpsr; | ||
96 | |||
97 | vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr); | ||
98 | vrr.val = vcpu_get_rr(vcpu, vadr); | ||
99 | vpta.val = vcpu_get_pta(vcpu); | ||
100 | |||
101 | if (vrr.ve & vpta.ve) { | ||
102 | switch (ref) { | ||
103 | case DATA_REF: | ||
104 | case NA_REF: | ||
105 | return vpsr.dt; | ||
106 | case INST_REF: | ||
107 | return vpsr.dt && vpsr.it && vpsr.ic; | ||
108 | case RSE_REF: | ||
109 | return vpsr.dt && vpsr.rt; | ||
110 | |||
111 | } | ||
112 | } | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | struct thash_data *vsa_thash(union ia64_pta vpta, u64 va, u64 vrr, u64 *tag) | ||
117 | { | ||
118 | u64 index, pfn, rid, pfn_bits; | ||
119 | |||
120 | pfn_bits = vpta.size - 5 - 8; | ||
121 | pfn = REGION_OFFSET(va) >> _REGION_PAGE_SIZE(vrr); | ||
122 | rid = _REGION_ID(vrr); | ||
123 | index = ((rid & 0xff) << pfn_bits)|(pfn & ((1UL << pfn_bits) - 1)); | ||
124 | *tag = ((rid >> 8) & 0xffff) | ((pfn >> pfn_bits) << 16); | ||
125 | |||
126 | return (struct thash_data *)((vpta.base << PTA_BASE_SHIFT) + | ||
127 | (index << 5)); | ||
128 | } | ||
129 | |||
130 | struct thash_data *__vtr_lookup(struct kvm_vcpu *vcpu, u64 va, int type) | ||
131 | { | ||
132 | |||
133 | struct thash_data *trp; | ||
134 | int i; | ||
135 | u64 rid; | ||
136 | |||
137 | rid = vcpu_get_rr(vcpu, va); | ||
138 | rid = rid & RR_RID_MASK;; | ||
139 | if (type == D_TLB) { | ||
140 | if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) { | ||
141 | for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0; | ||
142 | i < NDTRS; i++, trp++) { | ||
143 | if (__is_tr_translated(trp, rid, va)) | ||
144 | return trp; | ||
145 | } | ||
146 | } | ||
147 | } else { | ||
148 | if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) { | ||
149 | for (trp = (struct thash_data *)&vcpu->arch.itrs, i = 0; | ||
150 | i < NITRS; i++, trp++) { | ||
151 | if (__is_tr_translated(trp, rid, va)) | ||
152 | return trp; | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | static void vhpt_insert(u64 pte, u64 itir, u64 ifa, u64 gpte) | ||
161 | { | ||
162 | union ia64_rr rr; | ||
163 | struct thash_data *head; | ||
164 | unsigned long ps, gpaddr; | ||
165 | |||
166 | ps = itir_ps(itir); | ||
167 | |||
168 | gpaddr = ((gpte & _PAGE_PPN_MASK) >> ps << ps) | | ||
169 | (ifa & ((1UL << ps) - 1)); | ||
170 | |||
171 | rr.val = ia64_get_rr(ifa); | ||
172 | head = (struct thash_data *)ia64_thash(ifa); | ||
173 | head->etag = INVALID_TI_TAG; | ||
174 | ia64_mf(); | ||
175 | head->page_flags = pte & ~PAGE_FLAGS_RV_MASK; | ||
176 | head->itir = rr.ps << 2; | ||
177 | head->etag = ia64_ttag(ifa); | ||
178 | head->gpaddr = gpaddr; | ||
179 | } | ||
180 | |||
181 | void mark_pages_dirty(struct kvm_vcpu *v, u64 pte, u64 ps) | ||
182 | { | ||
183 | u64 i, dirty_pages = 1; | ||
184 | u64 base_gfn = (pte&_PAGE_PPN_MASK) >> PAGE_SHIFT; | ||
185 | spinlock_t *lock = __kvm_va(v->arch.dirty_log_lock_pa); | ||
186 | void *dirty_bitmap = (void *)v - (KVM_VCPU_OFS + v->vcpu_id * VCPU_SIZE) | ||
187 | + KVM_MEM_DIRTY_LOG_OFS; | ||
188 | dirty_pages <<= ps <= PAGE_SHIFT ? 0 : ps - PAGE_SHIFT; | ||
189 | |||
190 | vmm_spin_lock(lock); | ||
191 | for (i = 0; i < dirty_pages; i++) { | ||
192 | /* avoid RMW */ | ||
193 | if (!test_bit(base_gfn + i, dirty_bitmap)) | ||
194 | set_bit(base_gfn + i , dirty_bitmap); | ||
195 | } | ||
196 | vmm_spin_unlock(lock); | ||
197 | } | ||
198 | |||
199 | void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va, int type) | ||
200 | { | ||
201 | u64 phy_pte, psr; | ||
202 | union ia64_rr mrr; | ||
203 | |||
204 | mrr.val = ia64_get_rr(va); | ||
205 | phy_pte = translate_phy_pte(&pte, itir, va); | ||
206 | |||
207 | if (itir_ps(itir) >= mrr.ps) { | ||
208 | vhpt_insert(phy_pte, itir, va, pte); | ||
209 | } else { | ||
210 | phy_pte &= ~PAGE_FLAGS_RV_MASK; | ||
211 | psr = ia64_clear_ic(); | ||
212 | ia64_itc(type, va, phy_pte, itir_ps(itir)); | ||
213 | ia64_set_psr(psr); | ||
214 | } | ||
215 | |||
216 | if (!(pte&VTLB_PTE_IO)) | ||
217 | mark_pages_dirty(v, pte, itir_ps(itir)); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * vhpt lookup | ||
222 | */ | ||
223 | struct thash_data *vhpt_lookup(u64 va) | ||
224 | { | ||
225 | struct thash_data *head; | ||
226 | u64 tag; | ||
227 | |||
228 | head = (struct thash_data *)ia64_thash(va); | ||
229 | tag = ia64_ttag(va); | ||
230 | if (head->etag == tag) | ||
231 | return head; | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | u64 guest_vhpt_lookup(u64 iha, u64 *pte) | ||
236 | { | ||
237 | u64 ret; | ||
238 | struct thash_data *data; | ||
239 | |||
240 | data = __vtr_lookup(current_vcpu, iha, D_TLB); | ||
241 | if (data != NULL) | ||
242 | thash_vhpt_insert(current_vcpu, data->page_flags, | ||
243 | data->itir, iha, D_TLB); | ||
244 | |||
245 | asm volatile ("rsm psr.ic|psr.i;;" | ||
246 | "srlz.d;;" | ||
247 | "ld8.s r9=[%1];;" | ||
248 | "tnat.nz p6,p7=r9;;" | ||
249 | "(p6) mov %0=1;" | ||
250 | "(p6) mov r9=r0;" | ||
251 | "(p7) extr.u r9=r9,0,53;;" | ||
252 | "(p7) mov %0=r0;" | ||
253 | "(p7) st8 [%2]=r9;;" | ||
254 | "ssm psr.ic;;" | ||
255 | "srlz.d;;" | ||
256 | /* "ssm psr.i;;" Once interrupts in vmm open, need fix*/ | ||
257 | : "=r"(ret) : "r"(iha), "r"(pte):"memory"); | ||
258 | |||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * purge software guest tlb | ||
264 | */ | ||
265 | |||
266 | static void vtlb_purge(struct kvm_vcpu *v, u64 va, u64 ps) | ||
267 | { | ||
268 | struct thash_data *cur; | ||
269 | u64 start, curadr, size, psbits, tag, rr_ps, num; | ||
270 | union ia64_rr vrr; | ||
271 | struct thash_cb *hcb = &v->arch.vtlb; | ||
272 | |||
273 | vrr.val = vcpu_get_rr(v, va); | ||
274 | psbits = VMX(v, psbits[(va >> 61)]); | ||
275 | start = va & ~((1UL << ps) - 1); | ||
276 | while (psbits) { | ||
277 | curadr = start; | ||
278 | rr_ps = __ffs(psbits); | ||
279 | psbits &= ~(1UL << rr_ps); | ||
280 | num = 1UL << ((ps < rr_ps) ? 0 : (ps - rr_ps)); | ||
281 | size = PSIZE(rr_ps); | ||
282 | vrr.ps = rr_ps; | ||
283 | while (num) { | ||
284 | cur = vsa_thash(hcb->pta, curadr, vrr.val, &tag); | ||
285 | if (cur->etag == tag && cur->ps == rr_ps) | ||
286 | cur->etag = INVALID_TI_TAG; | ||
287 | curadr += size; | ||
288 | num--; | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | |||
294 | /* | ||
295 | * purge VHPT and machine TLB | ||
296 | */ | ||
297 | static void vhpt_purge(struct kvm_vcpu *v, u64 va, u64 ps) | ||
298 | { | ||
299 | struct thash_data *cur; | ||
300 | u64 start, size, tag, num; | ||
301 | union ia64_rr rr; | ||
302 | |||
303 | start = va & ~((1UL << ps) - 1); | ||
304 | rr.val = ia64_get_rr(va); | ||
305 | size = PSIZE(rr.ps); | ||
306 | num = 1UL << ((ps < rr.ps) ? 0 : (ps - rr.ps)); | ||
307 | while (num) { | ||
308 | cur = (struct thash_data *)ia64_thash(start); | ||
309 | tag = ia64_ttag(start); | ||
310 | if (cur->etag == tag) | ||
311 | cur->etag = INVALID_TI_TAG; | ||
312 | start += size; | ||
313 | num--; | ||
314 | } | ||
315 | machine_tlb_purge(va, ps); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Insert an entry into hash TLB or VHPT. | ||
320 | * NOTES: | ||
321 | * 1: When inserting VHPT to thash, "va" is a must covered | ||
322 | * address by the inserted machine VHPT entry. | ||
323 | * 2: The format of entry is always in TLB. | ||
324 | * 3: The caller need to make sure the new entry will not overlap | ||
325 | * with any existed entry. | ||
326 | */ | ||
327 | void vtlb_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va) | ||
328 | { | ||
329 | struct thash_data *head; | ||
330 | union ia64_rr vrr; | ||
331 | u64 tag; | ||
332 | struct thash_cb *hcb = &v->arch.vtlb; | ||
333 | |||
334 | vrr.val = vcpu_get_rr(v, va); | ||
335 | vrr.ps = itir_ps(itir); | ||
336 | VMX(v, psbits[va >> 61]) |= (1UL << vrr.ps); | ||
337 | head = vsa_thash(hcb->pta, va, vrr.val, &tag); | ||
338 | head->page_flags = pte; | ||
339 | head->itir = itir; | ||
340 | head->etag = tag; | ||
341 | } | ||
342 | |||
343 | int vtr_find_overlap(struct kvm_vcpu *vcpu, u64 va, u64 ps, int type) | ||
344 | { | ||
345 | struct thash_data *trp; | ||
346 | int i; | ||
347 | u64 end, rid; | ||
348 | |||
349 | rid = vcpu_get_rr(vcpu, va); | ||
350 | rid = rid & RR_RID_MASK; | ||
351 | end = va + PSIZE(ps); | ||
352 | if (type == D_TLB) { | ||
353 | if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) { | ||
354 | for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0; | ||
355 | i < NDTRS; i++, trp++) { | ||
356 | if (__is_tr_overlap(trp, rid, va, end)) | ||
357 | return i; | ||
358 | } | ||
359 | } | ||
360 | } else { | ||
361 | if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) { | ||
362 | for (trp = (struct thash_data *)&vcpu->arch.itrs, i = 0; | ||
363 | i < NITRS; i++, trp++) { | ||
364 | if (__is_tr_overlap(trp, rid, va, end)) | ||
365 | return i; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | return -1; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Purge entries in VTLB and VHPT | ||
374 | */ | ||
375 | void thash_purge_entries(struct kvm_vcpu *v, u64 va, u64 ps) | ||
376 | { | ||
377 | if (vcpu_quick_region_check(v->arch.tc_regions, va)) | ||
378 | vtlb_purge(v, va, ps); | ||
379 | vhpt_purge(v, va, ps); | ||
380 | } | ||
381 | |||
382 | void thash_purge_entries_remote(struct kvm_vcpu *v, u64 va, u64 ps) | ||
383 | { | ||
384 | u64 old_va = va; | ||
385 | va = REGION_OFFSET(va); | ||
386 | if (vcpu_quick_region_check(v->arch.tc_regions, old_va)) | ||
387 | vtlb_purge(v, va, ps); | ||
388 | vhpt_purge(v, va, ps); | ||
389 | } | ||
390 | |||
391 | u64 translate_phy_pte(u64 *pte, u64 itir, u64 va) | ||
392 | { | ||
393 | u64 ps, ps_mask, paddr, maddr; | ||
394 | union pte_flags phy_pte; | ||
395 | |||
396 | ps = itir_ps(itir); | ||
397 | ps_mask = ~((1UL << ps) - 1); | ||
398 | phy_pte.val = *pte; | ||
399 | paddr = *pte; | ||
400 | paddr = ((paddr & _PAGE_PPN_MASK) & ps_mask) | (va & ~ps_mask); | ||
401 | maddr = kvm_lookup_mpa(paddr >> PAGE_SHIFT); | ||
402 | if (maddr & GPFN_IO_MASK) { | ||
403 | *pte |= VTLB_PTE_IO; | ||
404 | return -1; | ||
405 | } | ||
406 | maddr = ((maddr & _PAGE_PPN_MASK) & PAGE_MASK) | | ||
407 | (paddr & ~PAGE_MASK); | ||
408 | phy_pte.ppn = maddr >> ARCH_PAGE_SHIFT; | ||
409 | return phy_pte.val; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Purge overlap TCs and then insert the new entry to emulate itc ops. | ||
414 | * Notes: Only TC entry can purge and insert. | ||
415 | * 1 indicates this is MMIO | ||
416 | */ | ||
417 | int thash_purge_and_insert(struct kvm_vcpu *v, u64 pte, u64 itir, | ||
418 | u64 ifa, int type) | ||
419 | { | ||
420 | u64 ps; | ||
421 | u64 phy_pte; | ||
422 | union ia64_rr vrr, mrr; | ||
423 | int ret = 0; | ||
424 | |||
425 | ps = itir_ps(itir); | ||
426 | vrr.val = vcpu_get_rr(v, ifa); | ||
427 | mrr.val = ia64_get_rr(ifa); | ||
428 | |||
429 | phy_pte = translate_phy_pte(&pte, itir, ifa); | ||
430 | |||
431 | /* Ensure WB attribute if pte is related to a normal mem page, | ||
432 | * which is required by vga acceleration since qemu maps shared | ||
433 | * vram buffer with WB. | ||
434 | */ | ||
435 | if (!(pte & VTLB_PTE_IO) && ((pte & _PAGE_MA_MASK) != _PAGE_MA_NAT)) { | ||
436 | pte &= ~_PAGE_MA_MASK; | ||
437 | phy_pte &= ~_PAGE_MA_MASK; | ||
438 | } | ||
439 | |||
440 | if (pte & VTLB_PTE_IO) | ||
441 | ret = 1; | ||
442 | |||
443 | vtlb_purge(v, ifa, ps); | ||
444 | vhpt_purge(v, ifa, ps); | ||
445 | |||
446 | if (ps == mrr.ps) { | ||
447 | if (!(pte&VTLB_PTE_IO)) { | ||
448 | vhpt_insert(phy_pte, itir, ifa, pte); | ||
449 | } else { | ||
450 | vtlb_insert(v, pte, itir, ifa); | ||
451 | vcpu_quick_region_set(VMX(v, tc_regions), ifa); | ||
452 | } | ||
453 | } else if (ps > mrr.ps) { | ||
454 | vtlb_insert(v, pte, itir, ifa); | ||
455 | vcpu_quick_region_set(VMX(v, tc_regions), ifa); | ||
456 | if (!(pte&VTLB_PTE_IO)) | ||
457 | vhpt_insert(phy_pte, itir, ifa, pte); | ||
458 | } else { | ||
459 | u64 psr; | ||
460 | phy_pte &= ~PAGE_FLAGS_RV_MASK; | ||
461 | psr = ia64_clear_ic(); | ||
462 | ia64_itc(type, ifa, phy_pte, ps); | ||
463 | ia64_set_psr(psr); | ||
464 | } | ||
465 | if (!(pte&VTLB_PTE_IO)) | ||
466 | mark_pages_dirty(v, pte, ps); | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Purge all TCs or VHPT entries including those in Hash table. | ||
473 | * | ||
474 | */ | ||
475 | |||
476 | void thash_purge_all(struct kvm_vcpu *v) | ||
477 | { | ||
478 | int i; | ||
479 | struct thash_data *head; | ||
480 | struct thash_cb *vtlb, *vhpt; | ||
481 | vtlb = &v->arch.vtlb; | ||
482 | vhpt = &v->arch.vhpt; | ||
483 | |||
484 | for (i = 0; i < 8; i++) | ||
485 | VMX(v, psbits[i]) = 0; | ||
486 | |||
487 | head = vtlb->hash; | ||
488 | for (i = 0; i < vtlb->num; i++) { | ||
489 | head->page_flags = 0; | ||
490 | head->etag = INVALID_TI_TAG; | ||
491 | head->itir = 0; | ||
492 | head->next = 0; | ||
493 | head++; | ||
494 | }; | ||
495 | |||
496 | head = vhpt->hash; | ||
497 | for (i = 0; i < vhpt->num; i++) { | ||
498 | head->page_flags = 0; | ||
499 | head->etag = INVALID_TI_TAG; | ||
500 | head->itir = 0; | ||
501 | head->next = 0; | ||
502 | head++; | ||
503 | }; | ||
504 | |||
505 | local_flush_tlb_all(); | ||
506 | } | ||
507 | |||
508 | |||
509 | /* | ||
510 | * Lookup the hash table and its collision chain to find an entry | ||
511 | * covering this address rid:va or the entry. | ||
512 | * | ||
513 | * INPUT: | ||
514 | * in: TLB format for both VHPT & TLB. | ||
515 | */ | ||
516 | |||
517 | struct thash_data *vtlb_lookup(struct kvm_vcpu *v, u64 va, int is_data) | ||
518 | { | ||
519 | struct thash_data *cch; | ||
520 | u64 psbits, ps, tag; | ||
521 | union ia64_rr vrr; | ||
522 | |||
523 | struct thash_cb *hcb = &v->arch.vtlb; | ||
524 | |||
525 | cch = __vtr_lookup(v, va, is_data);; | ||
526 | if (cch) | ||
527 | return cch; | ||
528 | |||
529 | if (vcpu_quick_region_check(v->arch.tc_regions, va) == 0) | ||
530 | return NULL; | ||
531 | |||
532 | psbits = VMX(v, psbits[(va >> 61)]); | ||
533 | vrr.val = vcpu_get_rr(v, va); | ||
534 | while (psbits) { | ||
535 | ps = __ffs(psbits); | ||
536 | psbits &= ~(1UL << ps); | ||
537 | vrr.ps = ps; | ||
538 | cch = vsa_thash(hcb->pta, va, vrr.val, &tag); | ||
539 | if (cch->etag == tag && cch->ps == ps) | ||
540 | return cch; | ||
541 | } | ||
542 | |||
543 | return NULL; | ||
544 | } | ||
545 | |||
546 | |||
547 | /* | ||
548 | * Initialize internal control data before service. | ||
549 | */ | ||
550 | void thash_init(struct thash_cb *hcb, u64 sz) | ||
551 | { | ||
552 | int i; | ||
553 | struct thash_data *head; | ||
554 | |||
555 | hcb->pta.val = (unsigned long)hcb->hash; | ||
556 | hcb->pta.vf = 1; | ||
557 | hcb->pta.ve = 1; | ||
558 | hcb->pta.size = sz; | ||
559 | head = hcb->hash; | ||
560 | for (i = 0; i < hcb->num; i++) { | ||
561 | head->page_flags = 0; | ||
562 | head->itir = 0; | ||
563 | head->etag = INVALID_TI_TAG; | ||
564 | head->next = 0; | ||
565 | head++; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | u64 kvm_lookup_mpa(u64 gpfn) | ||
570 | { | ||
571 | u64 *base = (u64 *) KVM_P2M_BASE; | ||
572 | return *(base + gpfn); | ||
573 | } | ||
574 | |||
575 | u64 kvm_gpa_to_mpa(u64 gpa) | ||
576 | { | ||
577 | u64 pte = kvm_lookup_mpa(gpa >> PAGE_SHIFT); | ||
578 | return (pte >> PAGE_SHIFT << PAGE_SHIFT) | (gpa & ~PAGE_MASK); | ||
579 | } | ||
580 | |||
581 | |||
582 | /* | ||
583 | * Fetch guest bundle code. | ||
584 | * INPUT: | ||
585 | * gip: guest ip | ||
586 | * pbundle: used to return fetched bundle. | ||
587 | */ | ||
588 | int fetch_code(struct kvm_vcpu *vcpu, u64 gip, IA64_BUNDLE *pbundle) | ||
589 | { | ||
590 | u64 gpip = 0; /* guest physical IP*/ | ||
591 | u64 *vpa; | ||
592 | struct thash_data *tlb; | ||
593 | u64 maddr; | ||
594 | |||
595 | if (!(VCPU(vcpu, vpsr) & IA64_PSR_IT)) { | ||
596 | /* I-side physical mode */ | ||
597 | gpip = gip; | ||
598 | } else { | ||
599 | tlb = vtlb_lookup(vcpu, gip, I_TLB); | ||
600 | if (tlb) | ||
601 | gpip = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) | | ||
602 | (gip & (PSIZE(tlb->ps) - 1)); | ||
603 | } | ||
604 | if (gpip) { | ||
605 | maddr = kvm_gpa_to_mpa(gpip); | ||
606 | } else { | ||
607 | tlb = vhpt_lookup(gip); | ||
608 | if (tlb == NULL) { | ||
609 | ia64_ptcl(gip, ARCH_PAGE_SHIFT << 2); | ||
610 | return IA64_FAULT; | ||
611 | } | ||
612 | maddr = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) | ||
613 | | (gip & (PSIZE(tlb->ps) - 1)); | ||
614 | } | ||
615 | vpa = (u64 *)__kvm_va(maddr); | ||
616 | |||
617 | pbundle->i64[0] = *vpa++; | ||
618 | pbundle->i64[1] = *vpa; | ||
619 | |||
620 | return IA64_NO_FAULT; | ||
621 | } | ||
622 | |||
623 | |||
624 | void kvm_init_vhpt(struct kvm_vcpu *v) | ||
625 | { | ||
626 | v->arch.vhpt.num = VHPT_NUM_ENTRIES; | ||
627 | thash_init(&v->arch.vhpt, VHPT_SHIFT); | ||
628 | ia64_set_pta(v->arch.vhpt.pta.val); | ||
629 | /*Enable VHPT here?*/ | ||
630 | } | ||
631 | |||
632 | void kvm_init_vtlb(struct kvm_vcpu *v) | ||
633 | { | ||
634 | v->arch.vtlb.num = VTLB_NUM_ENTRIES; | ||
635 | thash_init(&v->arch.vtlb, VTLB_SHIFT); | ||
636 | } | ||
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 5c1de53c8c1c..fc6c6636ffda 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c | |||
@@ -682,15 +682,6 @@ mem_init (void) | |||
682 | } | 682 | } |
683 | 683 | ||
684 | #ifdef CONFIG_MEMORY_HOTPLUG | 684 | #ifdef CONFIG_MEMORY_HOTPLUG |
685 | void online_page(struct page *page) | ||
686 | { | ||
687 | ClearPageReserved(page); | ||
688 | init_page_count(page); | ||
689 | __free_page(page); | ||
690 | totalram_pages++; | ||
691 | num_physpages++; | ||
692 | } | ||
693 | |||
694 | int arch_add_memory(int nid, u64 start, u64 size) | 685 | int arch_add_memory(int nid, u64 start, u64 size) |
695 | { | 686 | { |
696 | pg_data_t *pgdat; | 687 | pg_data_t *pgdat; |
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index dfc6bf1c7b41..49d3120415eb 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c | |||
@@ -550,11 +550,12 @@ static int __init sn2_ptc_init(void) | |||
550 | if (!ia64_platform_is("sn2")) | 550 | if (!ia64_platform_is("sn2")) |
551 | return 0; | 551 | return 0; |
552 | 552 | ||
553 | if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) { | 553 | proc_sn2_ptc = proc_create(PTC_BASENAME, 0444, |
554 | NULL, &proc_sn2_ptc_operations); | ||
555 | if (!&proc_sn2_ptc_operations) { | ||
554 | printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME); | 556 | printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME); |
555 | return -EINVAL; | 557 | return -EINVAL; |
556 | } | 558 | } |
557 | proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations; | ||
558 | spin_lock_init(&sn2_global_ptc_lock); | 559 | spin_lock_init(&sn2_global_ptc_lock); |
559 | return 0; | 560 | return 0; |
560 | } | 561 | } |
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 62b3e9a496ac..2526e5c783a4 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c | |||
@@ -139,30 +139,21 @@ static const struct file_operations proc_sn_topo_fops = { | |||
139 | void register_sn_procfs(void) | 139 | void register_sn_procfs(void) |
140 | { | 140 | { |
141 | static struct proc_dir_entry *sgi_proc_dir = NULL; | 141 | static struct proc_dir_entry *sgi_proc_dir = NULL; |
142 | struct proc_dir_entry *pde; | ||
143 | 142 | ||
144 | BUG_ON(sgi_proc_dir != NULL); | 143 | BUG_ON(sgi_proc_dir != NULL); |
145 | if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL))) | 144 | if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL))) |
146 | return; | 145 | return; |
147 | 146 | ||
148 | pde = create_proc_entry("partition_id", 0444, sgi_proc_dir); | 147 | proc_create("partition_id", 0444, sgi_proc_dir, |
149 | if (pde) | 148 | &proc_partition_id_fops); |
150 | pde->proc_fops = &proc_partition_id_fops; | 149 | proc_create("system_serial_number", 0444, sgi_proc_dir, |
151 | pde = create_proc_entry("system_serial_number", 0444, sgi_proc_dir); | 150 | &proc_system_sn_fops); |
152 | if (pde) | 151 | proc_create("licenseID", 0444, sgi_proc_dir, &proc_license_id_fops); |
153 | pde->proc_fops = &proc_system_sn_fops; | 152 | proc_create("sn_force_interrupt", 0644, sgi_proc_dir, |
154 | pde = create_proc_entry("licenseID", 0444, sgi_proc_dir); | 153 | &proc_sn_force_intr_fops); |
155 | if (pde) | 154 | proc_create("coherence_id", 0444, sgi_proc_dir, |
156 | pde->proc_fops = &proc_license_id_fops; | 155 | &proc_coherence_id_fops); |
157 | pde = create_proc_entry("sn_force_interrupt", 0644, sgi_proc_dir); | 156 | proc_create("sn_topology", 0444, sgi_proc_dir, &proc_sn_topo_fops); |
158 | if (pde) | ||
159 | pde->proc_fops = &proc_sn_force_intr_fops; | ||
160 | pde = create_proc_entry("coherence_id", 0444, sgi_proc_dir); | ||
161 | if (pde) | ||
162 | pde->proc_fops = &proc_coherence_id_fops; | ||
163 | pde = create_proc_entry("sn_topology", 0444, sgi_proc_dir); | ||
164 | if (pde) | ||
165 | pde->proc_fops = &proc_sn_topo_fops; | ||
166 | } | 157 | } |
167 | 158 | ||
168 | #endif /* CONFIG_PROC_FS */ | 159 | #endif /* CONFIG_PROC_FS */ |
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index 18b94b792d54..52175af299a0 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/dma-attrs.h> | ||
13 | #include <asm/dma.h> | 14 | #include <asm/dma.h> |
14 | #include <asm/sn/intr.h> | 15 | #include <asm/sn/intr.h> |
15 | #include <asm/sn/pcibus_provider_defs.h> | 16 | #include <asm/sn/pcibus_provider_defs.h> |
@@ -149,11 +150,12 @@ void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, | |||
149 | EXPORT_SYMBOL(sn_dma_free_coherent); | 150 | EXPORT_SYMBOL(sn_dma_free_coherent); |
150 | 151 | ||
151 | /** | 152 | /** |
152 | * sn_dma_map_single - map a single page for DMA | 153 | * sn_dma_map_single_attrs - map a single page for DMA |
153 | * @dev: device to map for | 154 | * @dev: device to map for |
154 | * @cpu_addr: kernel virtual address of the region to map | 155 | * @cpu_addr: kernel virtual address of the region to map |
155 | * @size: size of the region | 156 | * @size: size of the region |
156 | * @direction: DMA direction | 157 | * @direction: DMA direction |
158 | * @attrs: optional dma attributes | ||
157 | * | 159 | * |
158 | * Map the region pointed to by @cpu_addr for DMA and return the | 160 | * Map the region pointed to by @cpu_addr for DMA and return the |
159 | * DMA address. | 161 | * DMA address. |
@@ -163,42 +165,59 @@ EXPORT_SYMBOL(sn_dma_free_coherent); | |||
163 | * no way of saving the dmamap handle from the alloc to later free | 165 | * no way of saving the dmamap handle from the alloc to later free |
164 | * (which is pretty much unacceptable). | 166 | * (which is pretty much unacceptable). |
165 | * | 167 | * |
168 | * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with | ||
169 | * dma_map_consistent() so that writes force a flush of pending DMA. | ||
170 | * (See "SGI Altix Architecture Considerations for Linux Device Drivers", | ||
171 | * Document Number: 007-4763-001) | ||
172 | * | ||
166 | * TODO: simplify our interface; | 173 | * TODO: simplify our interface; |
167 | * figure out how to save dmamap handle so can use two step. | 174 | * figure out how to save dmamap handle so can use two step. |
168 | */ | 175 | */ |
169 | dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, | 176 | dma_addr_t sn_dma_map_single_attrs(struct device *dev, void *cpu_addr, |
170 | int direction) | 177 | size_t size, int direction, |
178 | struct dma_attrs *attrs) | ||
171 | { | 179 | { |
172 | dma_addr_t dma_addr; | 180 | dma_addr_t dma_addr; |
173 | unsigned long phys_addr; | 181 | unsigned long phys_addr; |
174 | struct pci_dev *pdev = to_pci_dev(dev); | 182 | struct pci_dev *pdev = to_pci_dev(dev); |
175 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | 183 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); |
184 | int dmabarr; | ||
185 | |||
186 | dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs); | ||
176 | 187 | ||
177 | BUG_ON(dev->bus != &pci_bus_type); | 188 | BUG_ON(dev->bus != &pci_bus_type); |
178 | 189 | ||
179 | phys_addr = __pa(cpu_addr); | 190 | phys_addr = __pa(cpu_addr); |
180 | dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS); | 191 | if (dmabarr) |
192 | dma_addr = provider->dma_map_consistent(pdev, phys_addr, | ||
193 | size, SN_DMA_ADDR_PHYS); | ||
194 | else | ||
195 | dma_addr = provider->dma_map(pdev, phys_addr, size, | ||
196 | SN_DMA_ADDR_PHYS); | ||
197 | |||
181 | if (!dma_addr) { | 198 | if (!dma_addr) { |
182 | printk(KERN_ERR "%s: out of ATEs\n", __func__); | 199 | printk(KERN_ERR "%s: out of ATEs\n", __func__); |
183 | return 0; | 200 | return 0; |
184 | } | 201 | } |
185 | return dma_addr; | 202 | return dma_addr; |
186 | } | 203 | } |
187 | EXPORT_SYMBOL(sn_dma_map_single); | 204 | EXPORT_SYMBOL(sn_dma_map_single_attrs); |
188 | 205 | ||
189 | /** | 206 | /** |
190 | * sn_dma_unmap_single - unamp a DMA mapped page | 207 | * sn_dma_unmap_single_attrs - unamp a DMA mapped page |
191 | * @dev: device to sync | 208 | * @dev: device to sync |
192 | * @dma_addr: DMA address to sync | 209 | * @dma_addr: DMA address to sync |
193 | * @size: size of region | 210 | * @size: size of region |
194 | * @direction: DMA direction | 211 | * @direction: DMA direction |
212 | * @attrs: optional dma attributes | ||
195 | * | 213 | * |
196 | * This routine is supposed to sync the DMA region specified | 214 | * This routine is supposed to sync the DMA region specified |
197 | * by @dma_handle into the coherence domain. On SN, we're always cache | 215 | * by @dma_handle into the coherence domain. On SN, we're always cache |
198 | * coherent, so we just need to free any ATEs associated with this mapping. | 216 | * coherent, so we just need to free any ATEs associated with this mapping. |
199 | */ | 217 | */ |
200 | void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | 218 | void sn_dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr, |
201 | int direction) | 219 | size_t size, int direction, |
220 | struct dma_attrs *attrs) | ||
202 | { | 221 | { |
203 | struct pci_dev *pdev = to_pci_dev(dev); | 222 | struct pci_dev *pdev = to_pci_dev(dev); |
204 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | 223 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); |
@@ -207,19 +226,21 @@ void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | |||
207 | 226 | ||
208 | provider->dma_unmap(pdev, dma_addr, direction); | 227 | provider->dma_unmap(pdev, dma_addr, direction); |
209 | } | 228 | } |
210 | EXPORT_SYMBOL(sn_dma_unmap_single); | 229 | EXPORT_SYMBOL(sn_dma_unmap_single_attrs); |
211 | 230 | ||
212 | /** | 231 | /** |
213 | * sn_dma_unmap_sg - unmap a DMA scatterlist | 232 | * sn_dma_unmap_sg_attrs - unmap a DMA scatterlist |
214 | * @dev: device to unmap | 233 | * @dev: device to unmap |
215 | * @sg: scatterlist to unmap | 234 | * @sg: scatterlist to unmap |
216 | * @nhwentries: number of scatterlist entries | 235 | * @nhwentries: number of scatterlist entries |
217 | * @direction: DMA direction | 236 | * @direction: DMA direction |
237 | * @attrs: optional dma attributes | ||
218 | * | 238 | * |
219 | * Unmap a set of streaming mode DMA translations. | 239 | * Unmap a set of streaming mode DMA translations. |
220 | */ | 240 | */ |
221 | void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, | 241 | void sn_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl, |
222 | int nhwentries, int direction) | 242 | int nhwentries, int direction, |
243 | struct dma_attrs *attrs) | ||
223 | { | 244 | { |
224 | int i; | 245 | int i; |
225 | struct pci_dev *pdev = to_pci_dev(dev); | 246 | struct pci_dev *pdev = to_pci_dev(dev); |
@@ -234,25 +255,34 @@ void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, | |||
234 | sg->dma_length = 0; | 255 | sg->dma_length = 0; |
235 | } | 256 | } |
236 | } | 257 | } |
237 | EXPORT_SYMBOL(sn_dma_unmap_sg); | 258 | EXPORT_SYMBOL(sn_dma_unmap_sg_attrs); |
238 | 259 | ||
239 | /** | 260 | /** |
240 | * sn_dma_map_sg - map a scatterlist for DMA | 261 | * sn_dma_map_sg_attrs - map a scatterlist for DMA |
241 | * @dev: device to map for | 262 | * @dev: device to map for |
242 | * @sg: scatterlist to map | 263 | * @sg: scatterlist to map |
243 | * @nhwentries: number of entries | 264 | * @nhwentries: number of entries |
244 | * @direction: direction of the DMA transaction | 265 | * @direction: direction of the DMA transaction |
266 | * @attrs: optional dma attributes | ||
267 | * | ||
268 | * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with | ||
269 | * dma_map_consistent() so that writes force a flush of pending DMA. | ||
270 | * (See "SGI Altix Architecture Considerations for Linux Device Drivers", | ||
271 | * Document Number: 007-4763-001) | ||
245 | * | 272 | * |
246 | * Maps each entry of @sg for DMA. | 273 | * Maps each entry of @sg for DMA. |
247 | */ | 274 | */ |
248 | int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nhwentries, | 275 | int sn_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl, |
249 | int direction) | 276 | int nhwentries, int direction, struct dma_attrs *attrs) |
250 | { | 277 | { |
251 | unsigned long phys_addr; | 278 | unsigned long phys_addr; |
252 | struct scatterlist *saved_sg = sgl, *sg; | 279 | struct scatterlist *saved_sg = sgl, *sg; |
253 | struct pci_dev *pdev = to_pci_dev(dev); | 280 | struct pci_dev *pdev = to_pci_dev(dev); |
254 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | 281 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); |
255 | int i; | 282 | int i; |
283 | int dmabarr; | ||
284 | |||
285 | dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs); | ||
256 | 286 | ||
257 | BUG_ON(dev->bus != &pci_bus_type); | 287 | BUG_ON(dev->bus != &pci_bus_type); |
258 | 288 | ||
@@ -260,11 +290,19 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nhwentries, | |||
260 | * Setup a DMA address for each entry in the scatterlist. | 290 | * Setup a DMA address for each entry in the scatterlist. |
261 | */ | 291 | */ |
262 | for_each_sg(sgl, sg, nhwentries, i) { | 292 | for_each_sg(sgl, sg, nhwentries, i) { |
293 | dma_addr_t dma_addr; | ||
263 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); | 294 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); |
264 | sg->dma_address = provider->dma_map(pdev, | 295 | if (dmabarr) |
265 | phys_addr, sg->length, | 296 | dma_addr = provider->dma_map_consistent(pdev, |
266 | SN_DMA_ADDR_PHYS); | 297 | phys_addr, |
298 | sg->length, | ||
299 | SN_DMA_ADDR_PHYS); | ||
300 | else | ||
301 | dma_addr = provider->dma_map(pdev, phys_addr, | ||
302 | sg->length, | ||
303 | SN_DMA_ADDR_PHYS); | ||
267 | 304 | ||
305 | sg->dma_address = dma_addr; | ||
268 | if (!sg->dma_address) { | 306 | if (!sg->dma_address) { |
269 | printk(KERN_ERR "%s: out of ATEs\n", __func__); | 307 | printk(KERN_ERR "%s: out of ATEs\n", __func__); |
270 | 308 | ||
@@ -272,7 +310,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nhwentries, | |||
272 | * Free any successfully allocated entries. | 310 | * Free any successfully allocated entries. |
273 | */ | 311 | */ |
274 | if (i > 0) | 312 | if (i > 0) |
275 | sn_dma_unmap_sg(dev, saved_sg, i, direction); | 313 | sn_dma_unmap_sg_attrs(dev, saved_sg, i, |
314 | direction, attrs); | ||
276 | return 0; | 315 | return 0; |
277 | } | 316 | } |
278 | 317 | ||
@@ -281,7 +320,7 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nhwentries, | |||
281 | 320 | ||
282 | return nhwentries; | 321 | return nhwentries; |
283 | } | 322 | } |
284 | EXPORT_SYMBOL(sn_dma_map_sg); | 323 | EXPORT_SYMBOL(sn_dma_map_sg_attrs); |
285 | 324 | ||
286 | void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, | 325 | void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, |
287 | size_t size, int direction) | 326 | size_t size, int direction) |
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c index 246a8820c223..b1f012f6c493 100644 --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c | |||
@@ -11,14 +11,12 @@ | |||
11 | #include <linux/stddef.h> | 11 | #include <linux/stddef.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/kbuild.h> | ||
14 | #include <asm/bootinfo.h> | 15 | #include <asm/bootinfo.h> |
15 | #include <asm/irq.h> | 16 | #include <asm/irq.h> |
16 | #include <asm/amigahw.h> | 17 | #include <asm/amigahw.h> |
17 | #include <linux/font.h> | 18 | #include <linux/font.h> |
18 | 19 | ||
19 | #define DEFINE(sym, val) \ | ||
20 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
21 | |||
22 | int main(void) | 20 | int main(void) |
23 | { | 21 | { |
24 | /* offsets into the task struct */ | 22 | /* offsets into the task struct */ |
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 2b412454cb41..ded7dd2f67b2 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c | |||
@@ -186,7 +186,7 @@ int setup_irq(unsigned int irq, struct irq_node *node) | |||
186 | 186 | ||
187 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 187 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
188 | printk("%s: Incorrect IRQ %d from %s\n", | 188 | printk("%s: Incorrect IRQ %d from %s\n", |
189 | __FUNCTION__, irq, node->devname); | 189 | __func__, irq, node->devname); |
190 | return -ENXIO; | 190 | return -ENXIO; |
191 | } | 191 | } |
192 | 192 | ||
@@ -249,7 +249,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
249 | unsigned long flags; | 249 | unsigned long flags; |
250 | 250 | ||
251 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 251 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
252 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); | 252 | printk("%s: Incorrect IRQ %d\n", __func__, irq); |
253 | return; | 253 | return; |
254 | } | 254 | } |
255 | 255 | ||
@@ -267,7 +267,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
267 | node->handler = NULL; | 267 | node->handler = NULL; |
268 | } else | 268 | } else |
269 | printk("%s: Removing probably wrong IRQ %d\n", | 269 | printk("%s: Removing probably wrong IRQ %d\n", |
270 | __FUNCTION__, irq); | 270 | __func__, irq); |
271 | 271 | ||
272 | if (!irq_list[irq]) { | 272 | if (!irq_list[irq]) { |
273 | if (contr->shutdown) | 273 | if (contr->shutdown) |
@@ -288,7 +288,7 @@ void enable_irq(unsigned int irq) | |||
288 | 288 | ||
289 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 289 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
290 | printk("%s: Incorrect IRQ %d\n", | 290 | printk("%s: Incorrect IRQ %d\n", |
291 | __FUNCTION__, irq); | 291 | __func__, irq); |
292 | return; | 292 | return; |
293 | } | 293 | } |
294 | 294 | ||
@@ -312,7 +312,7 @@ void disable_irq(unsigned int irq) | |||
312 | 312 | ||
313 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | 313 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
314 | printk("%s: Incorrect IRQ %d\n", | 314 | printk("%s: Incorrect IRQ %d\n", |
315 | __FUNCTION__, irq); | 315 | __func__, irq); |
316 | return; | 316 | return; |
317 | } | 317 | } |
318 | 318 | ||
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index 5b2799eb96a6..326fb9978094 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c | |||
@@ -109,7 +109,6 @@ | |||
109 | #include <linux/mm.h> | 109 | #include <linux/mm.h> |
110 | #include <linux/delay.h> | 110 | #include <linux/delay.h> |
111 | #include <linux/init.h> | 111 | #include <linux/init.h> |
112 | #include <linux/proc_fs.h> | ||
113 | #include <linux/interrupt.h> | 112 | #include <linux/interrupt.h> |
114 | 113 | ||
115 | #include <asm/bootinfo.h> | 114 | #include <asm/bootinfo.h> |
@@ -124,10 +123,6 @@ | |||
124 | 123 | ||
125 | int iop_scc_present,iop_ism_present; | 124 | int iop_scc_present,iop_ism_present; |
126 | 125 | ||
127 | #ifdef CONFIG_PROC_FS | ||
128 | static int iop_get_proc_info(char *, char **, off_t, int); | ||
129 | #endif /* CONFIG_PROC_FS */ | ||
130 | |||
131 | /* structure for tracking channel listeners */ | 126 | /* structure for tracking channel listeners */ |
132 | 127 | ||
133 | struct listener { | 128 | struct listener { |
@@ -299,12 +294,6 @@ void __init iop_init(void) | |||
299 | iop_listeners[IOP_NUM_ISM][i].devname = NULL; | 294 | iop_listeners[IOP_NUM_ISM][i].devname = NULL; |
300 | iop_listeners[IOP_NUM_ISM][i].handler = NULL; | 295 | iop_listeners[IOP_NUM_ISM][i].handler = NULL; |
301 | } | 296 | } |
302 | |||
303 | #if 0 /* Crashing in 2.4 now, not yet sure why. --jmt */ | ||
304 | #ifdef CONFIG_PROC_FS | ||
305 | create_proc_info_entry("mac_iop", 0, &proc_root, iop_get_proc_info); | ||
306 | #endif | ||
307 | #endif | ||
308 | } | 297 | } |
309 | 298 | ||
310 | /* | 299 | /* |
@@ -637,77 +626,3 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id) | |||
637 | } | 626 | } |
638 | return IRQ_HANDLED; | 627 | return IRQ_HANDLED; |
639 | } | 628 | } |
640 | |||
641 | #ifdef CONFIG_PROC_FS | ||
642 | |||
643 | char *iop_chan_state(int state) | ||
644 | { | ||
645 | switch(state) { | ||
646 | case IOP_MSG_IDLE : return "idle "; | ||
647 | case IOP_MSG_NEW : return "new "; | ||
648 | case IOP_MSG_RCVD : return "received "; | ||
649 | case IOP_MSG_COMPLETE : return "completed "; | ||
650 | default : return "unknown "; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | int iop_dump_one_iop(char *buf, int iop_num, char *iop_name) | ||
655 | { | ||
656 | int i,len = 0; | ||
657 | volatile struct mac_iop *iop = iop_base[iop_num]; | ||
658 | |||
659 | len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name); | ||
660 | len += sprintf(buf+len, "## send_state recv_state device\n"); | ||
661 | len += sprintf(buf+len, "------------------------------------------------\n"); | ||
662 | for (i = 0 ; i < NUM_IOP_CHAN ; i++) { | ||
663 | len += sprintf(buf+len, "%2d %10s %10s %s\n", i, | ||
664 | iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)), | ||
665 | iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)), | ||
666 | iop_listeners[iop_num][i].handler? | ||
667 | iop_listeners[iop_num][i].devname : ""); | ||
668 | |||
669 | } | ||
670 | len += sprintf(buf+len, "\n"); | ||
671 | return len; | ||
672 | } | ||
673 | |||
674 | static int iop_get_proc_info(char *buf, char **start, off_t pos, int count) | ||
675 | { | ||
676 | int len, cnt; | ||
677 | |||
678 | cnt = 0; | ||
679 | len = sprintf(buf, "IOPs detected:\n\n"); | ||
680 | |||
681 | if (iop_scc_present) { | ||
682 | len += sprintf(buf+len, "SCC IOP (%p): status %02X\n", | ||
683 | iop_base[IOP_NUM_SCC], | ||
684 | (uint) iop_base[IOP_NUM_SCC]->status_ctrl); | ||
685 | } | ||
686 | if (iop_ism_present) { | ||
687 | len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n", | ||
688 | iop_base[IOP_NUM_ISM], | ||
689 | (uint) iop_base[IOP_NUM_ISM]->status_ctrl); | ||
690 | } | ||
691 | |||
692 | if (iop_scc_present) { | ||
693 | len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC"); | ||
694 | |||
695 | } | ||
696 | |||
697 | if (iop_ism_present) { | ||
698 | len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM"); | ||
699 | |||
700 | } | ||
701 | |||
702 | if (len >= pos) { | ||
703 | if (!*start) { | ||
704 | *start = buf + pos; | ||
705 | cnt = len - pos; | ||
706 | } else { | ||
707 | cnt += len; | ||
708 | } | ||
709 | } | ||
710 | return (count > cnt) ? cnt : count; | ||
711 | } | ||
712 | |||
713 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 50603d3dce84..3c943d2ec570 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c | |||
@@ -190,7 +190,7 @@ void oss_irq_enable(int irq) { | |||
190 | break; | 190 | break; |
191 | #ifdef DEBUG_IRQUSE | 191 | #ifdef DEBUG_IRQUSE |
192 | default: | 192 | default: |
193 | printk("%s unknown irq %d\n",__FUNCTION__, irq); | 193 | printk("%s unknown irq %d\n", __func__, irq); |
194 | break; | 194 | break; |
195 | #endif | 195 | #endif |
196 | } | 196 | } |
@@ -230,7 +230,7 @@ void oss_irq_disable(int irq) { | |||
230 | break; | 230 | break; |
231 | #ifdef DEBUG_IRQUSE | 231 | #ifdef DEBUG_IRQUSE |
232 | default: | 232 | default: |
233 | printk("%s unknown irq %d\n", __FUNCTION__, irq); | 233 | printk("%s unknown irq %d\n", __func__, irq); |
234 | break; | 234 | break; |
235 | #endif | 235 | #endif |
236 | } | 236 | } |
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index f42caa79e4e8..a2bb01f59642 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c | |||
@@ -79,7 +79,6 @@ void show_mem(void) | |||
79 | 79 | ||
80 | printk("\nMem-info:\n"); | 80 | printk("\nMem-info:\n"); |
81 | show_free_areas(); | 81 | show_free_areas(); |
82 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | ||
83 | for_each_online_pgdat(pgdat) { | 82 | for_each_online_pgdat(pgdat) { |
84 | for (i = 0; i < pgdat->node_spanned_pages; i++) { | 83 | for (i = 0; i < pgdat->node_spanned_pages; i++) { |
85 | struct page *page = pgdat->node_mem_map + i; | 84 | struct page *page = pgdat->node_mem_map + i; |
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 46161cef08b9..9f0e3d59bf92 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c | |||
@@ -47,7 +47,7 @@ static int q40_irq_startup(unsigned int irq) | |||
47 | switch (irq) { | 47 | switch (irq) { |
48 | case 1: case 2: case 8: case 9: | 48 | case 1: case 2: case 8: case 9: |
49 | case 11: case 12: case 13: | 49 | case 11: case 12: case 13: |
50 | printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq); | 50 | printk("%s: ISA IRQ %d not implemented by HW\n", __func__, irq); |
51 | return -ENXIO; | 51 | return -ENXIO; |
52 | } | 52 | } |
53 | return 0; | 53 | return 0; |
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c index d97b89bae53c..fd0c685a7f11 100644 --- a/arch/m68knommu/kernel/asm-offsets.c +++ b/arch/m68knommu/kernel/asm-offsets.c | |||
@@ -13,15 +13,11 @@ | |||
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/ptrace.h> | 14 | #include <linux/ptrace.h> |
15 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
16 | #include <linux/kbuild.h> | ||
16 | #include <asm/bootinfo.h> | 17 | #include <asm/bootinfo.h> |
17 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
18 | #include <asm/thread_info.h> | 19 | #include <asm/thread_info.h> |
19 | 20 | ||
20 | #define DEFINE(sym, val) \ | ||
21 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
22 | |||
23 | #define BLANK() asm volatile("\n->" : : ) | ||
24 | |||
25 | int main(void) | 21 | int main(void) |
26 | { | 22 | { |
27 | /* offsets into the task struct */ | 23 | /* offsets into the task struct */ |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8724ed3298d3..e5a7c5d96364 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -81,7 +81,9 @@ config MIPS_COBALT | |||
81 | config MACH_DECSTATION | 81 | config MACH_DECSTATION |
82 | bool "DECstations" | 82 | bool "DECstations" |
83 | select BOOT_ELF32 | 83 | select BOOT_ELF32 |
84 | select CEVT_DS1287 | ||
84 | select CEVT_R4K | 85 | select CEVT_R4K |
86 | select CSRC_IOASIC | ||
85 | select CSRC_R4K | 87 | select CSRC_R4K |
86 | select CPU_DADDI_WORKAROUNDS if 64BIT | 88 | select CPU_DADDI_WORKAROUNDS if 64BIT |
87 | select CPU_R4000_WORKAROUNDS if 64BIT | 89 | select CPU_R4000_WORKAROUNDS if 64BIT |
@@ -221,6 +223,7 @@ config MIPS_MALTA | |||
221 | select DMA_NONCOHERENT | 223 | select DMA_NONCOHERENT |
222 | select GENERIC_ISA_DMA | 224 | select GENERIC_ISA_DMA |
223 | select IRQ_CPU | 225 | select IRQ_CPU |
226 | select IRQ_GIC | ||
224 | select HW_HAS_PCI | 227 | select HW_HAS_PCI |
225 | select I8253 | 228 | select I8253 |
226 | select I8259 | 229 | select I8259 |
@@ -309,12 +312,12 @@ config MACH_VR41XX | |||
309 | select GENERIC_HARDIRQS_NO__DO_IRQ | 312 | select GENERIC_HARDIRQS_NO__DO_IRQ |
310 | 313 | ||
311 | config PNX8550_JBS | 314 | config PNX8550_JBS |
312 | bool "Philips PNX8550 based JBS board" | 315 | bool "NXP PNX8550 based JBS board" |
313 | select PNX8550 | 316 | select PNX8550 |
314 | select SYS_SUPPORTS_LITTLE_ENDIAN | 317 | select SYS_SUPPORTS_LITTLE_ENDIAN |
315 | 318 | ||
316 | config PNX8550_STB810 | 319 | config PNX8550_STB810 |
317 | bool "Philips PNX8550 based STB810 board" | 320 | bool "NXP PNX8550 based STB810 board" |
318 | select PNX8550 | 321 | select PNX8550 |
319 | select SYS_SUPPORTS_LITTLE_ENDIAN | 322 | select SYS_SUPPORTS_LITTLE_ENDIAN |
320 | 323 | ||
@@ -612,6 +615,7 @@ config TOSHIBA_JMR3927 | |||
612 | select SYS_SUPPORTS_LITTLE_ENDIAN | 615 | select SYS_SUPPORTS_LITTLE_ENDIAN |
613 | select SYS_SUPPORTS_BIG_ENDIAN | 616 | select SYS_SUPPORTS_BIG_ENDIAN |
614 | select GENERIC_HARDIRQS_NO__DO_IRQ | 617 | select GENERIC_HARDIRQS_NO__DO_IRQ |
618 | select GPIO_TXX9 | ||
615 | 619 | ||
616 | config TOSHIBA_RBTX4927 | 620 | config TOSHIBA_RBTX4927 |
617 | bool "Toshiba RBTX49[23]7 board" | 621 | bool "Toshiba RBTX49[23]7 board" |
@@ -653,7 +657,7 @@ config TOSHIBA_RBTX4938 | |||
653 | select SYS_SUPPORTS_BIG_ENDIAN | 657 | select SYS_SUPPORTS_BIG_ENDIAN |
654 | select SYS_SUPPORTS_KGDB | 658 | select SYS_SUPPORTS_KGDB |
655 | select GENERIC_HARDIRQS_NO__DO_IRQ | 659 | select GENERIC_HARDIRQS_NO__DO_IRQ |
656 | select GENERIC_GPIO | 660 | select GPIO_TXX9 |
657 | help | 661 | help |
658 | This Toshiba board is based on the TX4938 processor. Say Y here to | 662 | This Toshiba board is based on the TX4938 processor. Say Y here to |
659 | support this machine type | 663 | support this machine type |
@@ -767,6 +771,9 @@ config BOOT_RAW | |||
767 | config CEVT_BCM1480 | 771 | config CEVT_BCM1480 |
768 | bool | 772 | bool |
769 | 773 | ||
774 | config CEVT_DS1287 | ||
775 | bool | ||
776 | |||
770 | config CEVT_GT641XX | 777 | config CEVT_GT641XX |
771 | bool | 778 | bool |
772 | 779 | ||
@@ -782,12 +789,20 @@ config CEVT_TXX9 | |||
782 | config CSRC_BCM1480 | 789 | config CSRC_BCM1480 |
783 | bool | 790 | bool |
784 | 791 | ||
792 | config CSRC_IOASIC | ||
793 | bool | ||
794 | |||
785 | config CSRC_R4K | 795 | config CSRC_R4K |
786 | bool | 796 | bool |
787 | 797 | ||
788 | config CSRC_SB1250 | 798 | config CSRC_SB1250 |
789 | bool | 799 | bool |
790 | 800 | ||
801 | config GPIO_TXX9 | ||
802 | select GENERIC_GPIO | ||
803 | select HAVE_GPIO_LIB | ||
804 | bool | ||
805 | |||
791 | config CFE | 806 | config CFE |
792 | bool | 807 | bool |
793 | 808 | ||
@@ -840,6 +855,9 @@ config MIPS_NILE4 | |||
840 | config MIPS_DISABLE_OBSOLETE_IDE | 855 | config MIPS_DISABLE_OBSOLETE_IDE |
841 | bool | 856 | bool |
842 | 857 | ||
858 | config SYNC_R4K | ||
859 | bool | ||
860 | |||
843 | config NO_IOPORT | 861 | config NO_IOPORT |
844 | def_bool n | 862 | def_bool n |
845 | 863 | ||
@@ -909,6 +927,9 @@ config IRQ_TXX9 | |||
909 | config IRQ_GT641XX | 927 | config IRQ_GT641XX |
910 | bool | 928 | bool |
911 | 929 | ||
930 | config IRQ_GIC | ||
931 | bool | ||
932 | |||
912 | config MIPS_BOARDS_GEN | 933 | config MIPS_BOARDS_GEN |
913 | bool | 934 | bool |
914 | 935 | ||
@@ -1811,6 +1832,17 @@ config NR_CPUS | |||
1811 | performance should round up your number of processors to the next | 1832 | performance should round up your number of processors to the next |
1812 | power of two. | 1833 | power of two. |
1813 | 1834 | ||
1835 | config MIPS_CMP | ||
1836 | bool "MIPS CMP framework support" | ||
1837 | depends on SMP | ||
1838 | select SYNC_R4K | ||
1839 | select SYS_SUPPORTS_SCHED_SMT | ||
1840 | select WEAK_ORDERING | ||
1841 | default n | ||
1842 | help | ||
1843 | This is a placeholder option for the GCMP work. It will need to | ||
1844 | be handled differently... | ||
1845 | |||
1814 | source "kernel/time/Kconfig" | 1846 | source "kernel/time/Kconfig" |
1815 | 1847 | ||
1816 | # | 1848 | # |
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index fd7124c1b75a..f18cf92650e3 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug | |||
@@ -73,14 +73,4 @@ config RUNTIME_DEBUG | |||
73 | include/asm-mips/debug.h for debuging macros. | 73 | include/asm-mips/debug.h for debuging macros. |
74 | If unsure, say N. | 74 | If unsure, say N. |
75 | 75 | ||
76 | config MIPS_UNCACHED | ||
77 | bool "Run uncached" | ||
78 | depends on DEBUG_KERNEL && !SMP && !SGI_IP27 | ||
79 | help | ||
80 | If you say Y here there kernel will disable all CPU caches. This will | ||
81 | reduce the system's performance dramatically but can help finding | ||
82 | otherwise hard to track bugs. It can also useful if you're doing | ||
83 | hardware debugging with a logic analyzer and need to see all traffic | ||
84 | on the bus. | ||
85 | |||
86 | endmenu | 76 | endmenu |
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 1c62381f5c23..69648d01acc0 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile | |||
@@ -410,21 +410,21 @@ load-$(CONFIG_CASIO_E55) += 0xffffffff80004000 | |||
410 | load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000 | 410 | load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000 |
411 | 411 | ||
412 | # | 412 | # |
413 | # Common Philips PNX8550 | 413 | # Common NXP PNX8550 |
414 | # | 414 | # |
415 | core-$(CONFIG_SOC_PNX8550) += arch/mips/philips/pnx8550/common/ | 415 | core-$(CONFIG_SOC_PNX8550) += arch/mips/nxp/pnx8550/common/ |
416 | cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550 | 416 | cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550 |
417 | 417 | ||
418 | # | 418 | # |
419 | # Philips PNX8550 JBS board | 419 | # NXP PNX8550 JBS board |
420 | # | 420 | # |
421 | libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/ | 421 | libs-$(CONFIG_PNX8550_JBS) += arch/mips/nxp/pnx8550/jbs/ |
422 | #cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550 | 422 | #cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550 |
423 | load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000 | 423 | load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000 |
424 | 424 | ||
425 | # Philips PNX8550 STB810 board | 425 | # NXP PNX8550 STB810 board |
426 | # | 426 | # |
427 | libs-$(CONFIG_PNX8550_STB810) += arch/mips/philips/pnx8550/stb810/ | 427 | libs-$(CONFIG_PNX8550_STB810) += arch/mips/nxp/pnx8550/stb810/ |
428 | load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000 | 428 | load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000 |
429 | 429 | ||
430 | # NEC EMMA2RH boards | 430 | # NEC EMMA2RH boards |
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c index 5c0d35d6e22a..8c93a05d7382 100644 --- a/arch/mips/au1000/common/cputable.c +++ b/arch/mips/au1000/common/cputable.c | |||
@@ -11,10 +11,7 @@ | |||
11 | * as published by the Free Software Foundation; either version | 11 | * as published by the Free Software Foundation; either version |
12 | * 2 of the License, or (at your option) any later version. | 12 | * 2 of the License, or (at your option) any later version. |
13 | */ | 13 | */ |
14 | #include <linux/string.h> | 14 | |
15 | #include <linux/sched.h> | ||
16 | #include <linux/threads.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/mach-au1x00/au1000.h> | 15 | #include <asm/mach-au1x00/au1000.h> |
19 | 16 | ||
20 | struct cpu_spec* cur_cpu_spec[NR_CPUS]; | 17 | struct cpu_spec* cur_cpu_spec[NR_CPUS]; |
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index 57f17b41098d..53377dfc0640 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c | |||
@@ -31,18 +31,12 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <linux/errno.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
37 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
38 | #include <linux/string.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
41 | #include <linux/module.h> | 37 | #include <linux/module.h> |
42 | #include <asm/mach-au1x00/au1000.h> | 38 | #include <asm/mach-au1x00/au1000.h> |
43 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | 39 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
44 | #include <asm/system.h> | ||
45 | |||
46 | 40 | ||
47 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) | 41 | #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) |
48 | 42 | ||
diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c index 79e0b0a51ace..eae1bb2ca26e 100644 --- a/arch/mips/au1000/common/dbg_io.c +++ b/arch/mips/au1000/common/dbg_io.c | |||
@@ -1,5 +1,4 @@ | |||
1 | 1 | ||
2 | #include <asm/io.h> | ||
3 | #include <asm/mach-au1x00/au1000.h> | 2 | #include <asm/mach-au1x00/au1000.h> |
4 | 3 | ||
5 | #ifdef CONFIG_KGDB | 4 | #ifdef CONFIG_KGDB |
@@ -55,8 +54,7 @@ typedef unsigned int uint32; | |||
55 | #define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) | 54 | #define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) |
56 | #define UART16550_WRITE(y, z) (au_writel(z&0xff, DEBUG_BASE + y)) | 55 | #define UART16550_WRITE(y, z) (au_writel(z&0xff, DEBUG_BASE + y)) |
57 | 56 | ||
58 | extern unsigned long get_au1x00_uart_baud_base(void); | 57 | extern unsigned long calc_clock(void); |
59 | extern unsigned long cal_r4koff(void); | ||
60 | 58 | ||
61 | void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) | 59 | void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) |
62 | { | 60 | { |
@@ -64,7 +62,7 @@ void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) | |||
64 | if (UART16550_READ(UART_MOD_CNTRL) != 0x3) { | 62 | if (UART16550_READ(UART_MOD_CNTRL) != 0x3) { |
65 | UART16550_WRITE(UART_MOD_CNTRL, 3); | 63 | UART16550_WRITE(UART_MOD_CNTRL, 3); |
66 | } | 64 | } |
67 | cal_r4koff(); | 65 | calc_clock(); |
68 | 66 | ||
69 | /* disable interrupts */ | 67 | /* disable interrupts */ |
70 | UART16550_WRITE(UART_IER, 0); | 68 | UART16550_WRITE(UART_IER, 0); |
diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c index c78260d4e837..95f69ea146e9 100644 --- a/arch/mips/au1000/common/dma.c +++ b/arch/mips/au1000/common/dma.c | |||
@@ -33,12 +33,9 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
35 | #include <linux/errno.h> | 35 | #include <linux/errno.h> |
36 | #include <linux/sched.h> | ||
37 | #include <linux/spinlock.h> | 36 | #include <linux/spinlock.h> |
38 | #include <linux/string.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
41 | #include <asm/system.h> | 38 | |
42 | #include <asm/mach-au1x00/au1000.h> | 39 | #include <asm/mach-au1x00/au1000.h> |
43 | #include <asm/mach-au1x00/au1000_dma.h> | 40 | #include <asm/mach-au1x00/au1000_dma.h> |
44 | 41 | ||
diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c index 0b658f1db4ce..525452589971 100644 --- a/arch/mips/au1000/common/gpio.c +++ b/arch/mips/au1000/common/gpio.c | |||
@@ -27,13 +27,8 @@ | |||
27 | * others have a second one : GPIO2 | 27 | * others have a second one : GPIO2 |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/module.h> | 30 | #include <linux/module.h> |
34 | 31 | ||
35 | #include <asm/addrspace.h> | ||
36 | |||
37 | #include <asm/mach-au1x00/au1000.h> | 32 | #include <asm/mach-au1x00/au1000.h> |
38 | #include <asm/gpio.h> | 33 | #include <asm/gpio.h> |
39 | 34 | ||
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 3c7714f057ac..f0626992fd75 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c | |||
@@ -1,7 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2001 MontaVista Software Inc. | 2 | * Copyright 2001, 2007-2008 MontaVista Software Inc. |
3 | * Author: MontaVista Software, Inc. | 3 | * Author: MontaVista Software, Inc. <source@mvista.com> |
4 | * ppopov@mvista.com or source@mvista.com | ||
5 | * | 4 | * |
6 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) | 5 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) |
7 | * | 6 | * |
@@ -27,7 +26,6 @@ | |||
27 | */ | 26 | */ |
28 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
29 | #include <linux/init.h> | 28 | #include <linux/init.h> |
30 | #include <linux/io.h> | ||
31 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
32 | #include <linux/irq.h> | 30 | #include <linux/irq.h> |
33 | 31 | ||
@@ -591,7 +589,7 @@ void __init arch_init_irq(void) | |||
591 | imp++; | 589 | imp++; |
592 | } | 590 | } |
593 | 591 | ||
594 | set_c0_status(ALLINTS); | 592 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); |
595 | 593 | ||
596 | /* Board specific IRQ initialization. | 594 | /* Board specific IRQ initialization. |
597 | */ | 595 | */ |
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c index ce771487567d..7e966b31e3e1 100644 --- a/arch/mips/au1000/common/pci.c +++ b/arch/mips/au1000/common/pci.c | |||
@@ -30,7 +30,7 @@ | |||
30 | * with this program; if not, write to the Free Software Foundation, Inc., | 30 | * with this program; if not, write to the Free Software Foundation, Inc., |
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 31 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
32 | */ | 32 | */ |
33 | #include <linux/types.h> | 33 | |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c index 39d681265297..31d2a2270878 100644 --- a/arch/mips/au1000/common/platform.c +++ b/arch/mips/au1000/common/platform.c | |||
@@ -3,18 +3,65 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> | 4 | * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> |
5 | * | 5 | * |
6 | * (C) Copyright Embedded Alley Solutions, Inc 2005 | ||
7 | * Author: Pantelis Antoniou <pantelis@embeddedalley.com> | ||
8 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | 9 | * This file is licensed under the terms of the GNU General Public |
7 | * License version 2. This program is licensed "as is" without any | 10 | * License version 2. This program is licensed "as is" without any |
8 | * warranty of any kind, whether express or implied. | 11 | * warranty of any kind, whether express or implied. |
9 | */ | 12 | */ |
10 | #include <linux/device.h> | 13 | |
11 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
12 | #include <linux/kernel.h> | 15 | #include <linux/serial_8250.h> |
13 | #include <linux/init.h> | 16 | #include <linux/init.h> |
14 | #include <linux/resource.h> | ||
15 | 17 | ||
16 | #include <asm/mach-au1x00/au1xxx.h> | 18 | #include <asm/mach-au1x00/au1xxx.h> |
17 | 19 | ||
20 | #define PORT(_base, _irq) \ | ||
21 | { \ | ||
22 | .iobase = _base, \ | ||
23 | .membase = (void __iomem *)_base,\ | ||
24 | .mapbase = CPHYSADDR(_base), \ | ||
25 | .irq = _irq, \ | ||
26 | .regshift = 2, \ | ||
27 | .iotype = UPIO_AU, \ | ||
28 | .flags = UPF_SKIP_TEST \ | ||
29 | } | ||
30 | |||
31 | static struct plat_serial8250_port au1x00_uart_data[] = { | ||
32 | #if defined(CONFIG_SERIAL_8250_AU1X00) | ||
33 | #if defined(CONFIG_SOC_AU1000) | ||
34 | PORT(UART0_ADDR, AU1000_UART0_INT), | ||
35 | PORT(UART1_ADDR, AU1000_UART1_INT), | ||
36 | PORT(UART2_ADDR, AU1000_UART2_INT), | ||
37 | PORT(UART3_ADDR, AU1000_UART3_INT), | ||
38 | #elif defined(CONFIG_SOC_AU1500) | ||
39 | PORT(UART0_ADDR, AU1500_UART0_INT), | ||
40 | PORT(UART3_ADDR, AU1500_UART3_INT), | ||
41 | #elif defined(CONFIG_SOC_AU1100) | ||
42 | PORT(UART0_ADDR, AU1100_UART0_INT), | ||
43 | PORT(UART1_ADDR, AU1100_UART1_INT), | ||
44 | PORT(UART3_ADDR, AU1100_UART3_INT), | ||
45 | #elif defined(CONFIG_SOC_AU1550) | ||
46 | PORT(UART0_ADDR, AU1550_UART0_INT), | ||
47 | PORT(UART1_ADDR, AU1550_UART1_INT), | ||
48 | PORT(UART3_ADDR, AU1550_UART3_INT), | ||
49 | #elif defined(CONFIG_SOC_AU1200) | ||
50 | PORT(UART0_ADDR, AU1200_UART0_INT), | ||
51 | PORT(UART1_ADDR, AU1200_UART1_INT), | ||
52 | #endif | ||
53 | #endif /* CONFIG_SERIAL_8250_AU1X00 */ | ||
54 | { }, | ||
55 | }; | ||
56 | |||
57 | static struct platform_device au1xx0_uart_device = { | ||
58 | .name = "serial8250", | ||
59 | .id = PLAT8250_DEV_AU1X00, | ||
60 | .dev = { | ||
61 | .platform_data = au1x00_uart_data, | ||
62 | }, | ||
63 | }; | ||
64 | |||
18 | /* OHCI (USB full speed host controller) */ | 65 | /* OHCI (USB full speed host controller) */ |
19 | static struct resource au1xxx_usb_ohci_resources[] = { | 66 | static struct resource au1xxx_usb_ohci_resources[] = { |
20 | [0] = { | 67 | [0] = { |
@@ -186,19 +233,6 @@ static struct resource au1200_lcd_resources[] = { | |||
186 | } | 233 | } |
187 | }; | 234 | }; |
188 | 235 | ||
189 | static struct resource au1200_ide0_resources[] = { | ||
190 | [0] = { | ||
191 | .start = AU1XXX_ATA_PHYS_ADDR, | ||
192 | .end = AU1XXX_ATA_PHYS_ADDR + AU1XXX_ATA_PHYS_LEN - 1, | ||
193 | .flags = IORESOURCE_MEM, | ||
194 | }, | ||
195 | [1] = { | ||
196 | .start = AU1XXX_ATA_INT, | ||
197 | .end = AU1XXX_ATA_INT, | ||
198 | .flags = IORESOURCE_IRQ, | ||
199 | } | ||
200 | }; | ||
201 | |||
202 | static u64 au1200_lcd_dmamask = ~(u32)0; | 236 | static u64 au1200_lcd_dmamask = ~(u32)0; |
203 | 237 | ||
204 | static struct platform_device au1200_lcd_device = { | 238 | static struct platform_device au1200_lcd_device = { |
@@ -212,20 +246,6 @@ static struct platform_device au1200_lcd_device = { | |||
212 | .resource = au1200_lcd_resources, | 246 | .resource = au1200_lcd_resources, |
213 | }; | 247 | }; |
214 | 248 | ||
215 | |||
216 | static u64 ide0_dmamask = ~(u32)0; | ||
217 | |||
218 | static struct platform_device au1200_ide0_device = { | ||
219 | .name = "au1200-ide", | ||
220 | .id = 0, | ||
221 | .dev = { | ||
222 | .dma_mask = &ide0_dmamask, | ||
223 | .coherent_dma_mask = 0xffffffff, | ||
224 | }, | ||
225 | .num_resources = ARRAY_SIZE(au1200_ide0_resources), | ||
226 | .resource = au1200_ide0_resources, | ||
227 | }; | ||
228 | |||
229 | static u64 au1xxx_mmc_dmamask = ~(u32)0; | 249 | static u64 au1xxx_mmc_dmamask = ~(u32)0; |
230 | 250 | ||
231 | static struct platform_device au1xxx_mmc_device = { | 251 | static struct platform_device au1xxx_mmc_device = { |
@@ -245,31 +265,6 @@ static struct platform_device au1x00_pcmcia_device = { | |||
245 | .id = 0, | 265 | .id = 0, |
246 | }; | 266 | }; |
247 | 267 | ||
248 | #ifdef CONFIG_MIPS_DB1200 | ||
249 | |||
250 | static struct resource smc91x_resources[] = { | ||
251 | [0] = { | ||
252 | .name = "smc91x-regs", | ||
253 | .start = AU1XXX_SMC91111_PHYS_ADDR, | ||
254 | .end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff, | ||
255 | .flags = IORESOURCE_MEM, | ||
256 | }, | ||
257 | [1] = { | ||
258 | .start = AU1XXX_SMC91111_IRQ, | ||
259 | .end = AU1XXX_SMC91111_IRQ, | ||
260 | .flags = IORESOURCE_IRQ, | ||
261 | }, | ||
262 | }; | ||
263 | |||
264 | static struct platform_device smc91x_device = { | ||
265 | .name = "smc91x", | ||
266 | .id = -1, | ||
267 | .num_resources = ARRAY_SIZE(smc91x_resources), | ||
268 | .resource = smc91x_resources, | ||
269 | }; | ||
270 | |||
271 | #endif | ||
272 | |||
273 | /* All Alchemy demoboards with I2C have this #define in their headers */ | 268 | /* All Alchemy demoboards with I2C have this #define in their headers */ |
274 | #ifdef SMBUS_PSC_BASE | 269 | #ifdef SMBUS_PSC_BASE |
275 | static struct resource pbdb_smbus_resources[] = { | 270 | static struct resource pbdb_smbus_resources[] = { |
@@ -289,6 +284,7 @@ static struct platform_device pbdb_smbus_device = { | |||
289 | #endif | 284 | #endif |
290 | 285 | ||
291 | static struct platform_device *au1xxx_platform_devices[] __initdata = { | 286 | static struct platform_device *au1xxx_platform_devices[] __initdata = { |
287 | &au1xx0_uart_device, | ||
292 | &au1xxx_usb_ohci_device, | 288 | &au1xxx_usb_ohci_device, |
293 | &au1x00_pcmcia_device, | 289 | &au1x00_pcmcia_device, |
294 | #ifdef CONFIG_FB_AU1100 | 290 | #ifdef CONFIG_FB_AU1100 |
@@ -299,12 +295,8 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { | |||
299 | &au1xxx_usb_gdt_device, | 295 | &au1xxx_usb_gdt_device, |
300 | &au1xxx_usb_otg_device, | 296 | &au1xxx_usb_otg_device, |
301 | &au1200_lcd_device, | 297 | &au1200_lcd_device, |
302 | &au1200_ide0_device, | ||
303 | &au1xxx_mmc_device, | 298 | &au1xxx_mmc_device, |
304 | #endif | 299 | #endif |
305 | #ifdef CONFIG_MIPS_DB1200 | ||
306 | &smc91x_device, | ||
307 | #endif | ||
308 | #ifdef SMBUS_PSC_BASE | 300 | #ifdef SMBUS_PSC_BASE |
309 | &pbdb_smbus_device, | 301 | &pbdb_smbus_device, |
310 | #endif | 302 | #endif |
@@ -312,6 +304,13 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { | |||
312 | 304 | ||
313 | int __init au1xxx_platform_init(void) | 305 | int __init au1xxx_platform_init(void) |
314 | { | 306 | { |
307 | unsigned int uartclk = get_au1x00_uart_baud_base() * 16; | ||
308 | int i; | ||
309 | |||
310 | /* Fill up uartclk. */ | ||
311 | for (i = 0; au1x00_uart_data[i].flags ; i++) | ||
312 | au1x00_uart_data[i].uartclk = uartclk; | ||
313 | |||
315 | return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); | 314 | return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); |
316 | } | 315 | } |
317 | 316 | ||
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 54047d69b820..812a5f8b7d26 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c | |||
@@ -29,17 +29,14 @@ | |||
29 | * with this program; if not, write to the Free Software Foundation, Inc., | 29 | * with this program; if not, write to the Free Software Foundation, Inc., |
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
31 | */ | 31 | */ |
32 | |||
32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
33 | #include <linux/pm.h> | 34 | #include <linux/pm.h> |
34 | #include <linux/pm_legacy.h> | 35 | #include <linux/pm_legacy.h> |
35 | #include <linux/slab.h> | ||
36 | #include <linux/sysctl.h> | 36 | #include <linux/sysctl.h> |
37 | #include <linux/jiffies.h> | 37 | #include <linux/jiffies.h> |
38 | 38 | ||
39 | #include <asm/string.h> | ||
40 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
41 | #include <asm/io.h> | ||
42 | #include <asm/system.h> | ||
43 | #include <asm/cacheflush.h> | 40 | #include <asm/cacheflush.h> |
44 | #include <asm/mach-au1x00/au1000.h> | 41 | #include <asm/mach-au1x00/au1000.h> |
45 | 42 | ||
@@ -47,17 +44,13 @@ | |||
47 | 44 | ||
48 | #define DEBUG 1 | 45 | #define DEBUG 1 |
49 | #ifdef DEBUG | 46 | #ifdef DEBUG |
50 | # define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) | 47 | # define DPRINTK(fmt, args...) printk("%s: " fmt, __func__, ## args) |
51 | #else | 48 | #else |
52 | # define DPRINTK(fmt, args...) | 49 | # define DPRINTK(fmt, args...) |
53 | #endif | 50 | #endif |
54 | 51 | ||
55 | static void au1000_calibrate_delay(void); | 52 | static void au1000_calibrate_delay(void); |
56 | 53 | ||
57 | extern void set_au1x00_speed(unsigned int new_freq); | ||
58 | extern unsigned int get_au1x00_speed(void); | ||
59 | extern unsigned long get_au1x00_uart_baud_base(void); | ||
60 | extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); | ||
61 | extern unsigned long save_local_and_disable(int controller); | 54 | extern unsigned long save_local_and_disable(int controller); |
62 | extern void restore_local_and_enable(int controller, unsigned long mask); | 55 | extern void restore_local_and_enable(int controller, unsigned long mask); |
63 | extern void local_enable_irq(unsigned int irq_nr); | 56 | extern void local_enable_irq(unsigned int irq_nr); |
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c index 90d70695aa60..f10af829e4ec 100644 --- a/arch/mips/au1000/common/prom.c +++ b/arch/mips/au1000/common/prom.c | |||
@@ -33,8 +33,8 @@ | |||
33 | * with this program; if not, write to the Free Software Foundation, Inc., | 33 | * with this program; if not, write to the Free Software Foundation, Inc., |
34 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 34 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
35 | */ | 35 | */ |
36 | |||
36 | #include <linux/module.h> | 37 | #include <linux/module.h> |
37 | #include <linux/kernel.h> | ||
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/string.h> | 39 | #include <linux/string.h> |
40 | 40 | ||
diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/au1000/common/puts.c index 2705829cd466..e34c67e89293 100644 --- a/arch/mips/au1000/common/puts.c +++ b/arch/mips/au1000/common/puts.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/types.h> | ||
32 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
33 | 32 | ||
34 | #define SERIAL_BASE UART_BASE | 33 | #define SERIAL_BASE UART_BASE |
diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/au1000/common/reset.c index b8638d293cf9..60cec537c745 100644 --- a/arch/mips/au1000/common/reset.c +++ b/arch/mips/au1000/common/reset.c | |||
@@ -27,13 +27,7 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | #include <linux/sched.h> | 30 | |
31 | #include <linux/mm.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/pgtable.h> | ||
34 | #include <asm/processor.h> | ||
35 | #include <asm/reboot.h> | ||
36 | #include <asm/system.h> | ||
37 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
38 | 32 | ||
39 | extern int au_sleep(void); | 33 | extern int au_sleep(void); |
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index 9e4ab80caab6..0e86f7a6b4a7 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c | |||
@@ -25,21 +25,14 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | |||
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
29 | #include <linux/sched.h> | ||
30 | #include <linux/ioport.h> | 30 | #include <linux/ioport.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/module.h> | 31 | #include <linux/module.h> |
35 | #include <linux/pm.h> | 32 | #include <linux/pm.h> |
36 | 33 | ||
37 | #include <asm/cpu.h> | ||
38 | #include <asm/bootinfo.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/mipsregs.h> | 34 | #include <asm/mipsregs.h> |
41 | #include <asm/reboot.h> | 35 | #include <asm/reboot.h> |
42 | #include <asm/pgtable.h> | ||
43 | #include <asm/time.h> | 36 | #include <asm/time.h> |
44 | 37 | ||
45 | #include <au1000.h> | 38 | #include <au1000.h> |
@@ -49,8 +42,6 @@ extern void __init board_setup(void); | |||
49 | extern void au1000_restart(char *); | 42 | extern void au1000_restart(char *); |
50 | extern void au1000_halt(void); | 43 | extern void au1000_halt(void); |
51 | extern void au1000_power_off(void); | 44 | extern void au1000_power_off(void); |
52 | extern void au1x_time_init(void); | ||
53 | extern void au1x_timer_setup(struct irqaction *irq); | ||
54 | extern void set_cpuspec(void); | 45 | extern void set_cpuspec(void); |
55 | 46 | ||
56 | void __init plat_mem_setup(void) | 47 | void __init plat_mem_setup(void) |
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S index 683d9da84b66..4b3cf021a454 100644 --- a/arch/mips/au1000/common/sleeper.S +++ b/arch/mips/au1000/common/sleeper.S | |||
@@ -9,9 +9,9 @@ | |||
9 | * Free Software Foundation; either version 2 of the License, or (at your | 9 | * Free Software Foundation; either version 2 of the License, or (at your |
10 | * option) any later version. | 10 | * option) any later version. |
11 | */ | 11 | */ |
12 | |||
12 | #include <asm/asm.h> | 13 | #include <asm/asm.h> |
13 | #include <asm/mipsregs.h> | 14 | #include <asm/mipsregs.h> |
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/regdef.h> | 15 | #include <asm/regdef.h> |
16 | #include <asm/stackframe.h> | 16 | #include <asm/stackframe.h> |
17 | 17 | ||
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index e122bbc6cd88..bdb6d73b26fb 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com | 3 | * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com> |
4 | * Copied and modified Carsten Langgaard's time.c | 4 | * Copied and modified Carsten Langgaard's time.c |
5 | * | 5 | * |
6 | * Carsten Langgaard, carstenl@mips.com | 6 | * Carsten Langgaard, carstenl@mips.com |
@@ -34,23 +34,13 @@ | |||
34 | 34 | ||
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/kernel_stat.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/spinlock.h> | 37 | #include <linux/spinlock.h> |
40 | #include <linux/hardirq.h> | ||
41 | 38 | ||
42 | #include <asm/compiler.h> | ||
43 | #include <asm/mipsregs.h> | 39 | #include <asm/mipsregs.h> |
44 | #include <asm/time.h> | 40 | #include <asm/time.h> |
45 | #include <asm/div64.h> | ||
46 | #include <asm/mach-au1x00/au1000.h> | 41 | #include <asm/mach-au1x00/au1000.h> |
47 | 42 | ||
48 | #include <linux/mc146818rtc.h> | 43 | static int no_au1xxx_32khz; |
49 | #include <linux/timex.h> | ||
50 | |||
51 | static unsigned long r4k_offset; /* Amount to increment compare reg each time */ | ||
52 | static unsigned long r4k_cur; /* What counter should be at next timer irq */ | ||
53 | int no_au1xxx_32khz; | ||
54 | extern int allow_au1k_wait; /* default off for CP0 Counter */ | 44 | extern int allow_au1k_wait; /* default off for CP0 Counter */ |
55 | 45 | ||
56 | #ifdef CONFIG_PM | 46 | #ifdef CONFIG_PM |
@@ -184,7 +174,7 @@ wakeup_counter0_set(int ticks) | |||
184 | * "wait" is enabled, and we need to detect if the 32KHz isn't present | 174 | * "wait" is enabled, and we need to detect if the 32KHz isn't present |
185 | * but requested......got it? :-) -- Dan | 175 | * but requested......got it? :-) -- Dan |
186 | */ | 176 | */ |
187 | unsigned long cal_r4koff(void) | 177 | unsigned long calc_clock(void) |
188 | { | 178 | { |
189 | unsigned long cpu_speed; | 179 | unsigned long cpu_speed; |
190 | unsigned long flags; | 180 | unsigned long flags; |
@@ -229,19 +219,13 @@ unsigned long cal_r4koff(void) | |||
229 | // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) | 219 | // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) |
230 | set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); | 220 | set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); |
231 | spin_unlock_irqrestore(&time_lock, flags); | 221 | spin_unlock_irqrestore(&time_lock, flags); |
232 | return (cpu_speed / HZ); | 222 | return cpu_speed; |
233 | } | 223 | } |
234 | 224 | ||
235 | void __init plat_time_init(void) | 225 | void __init plat_time_init(void) |
236 | { | 226 | { |
237 | unsigned int est_freq; | 227 | unsigned int est_freq = calc_clock(); |
238 | |||
239 | printk("calculating r4koff... "); | ||
240 | r4k_offset = cal_r4koff(); | ||
241 | printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); | ||
242 | 228 | ||
243 | //est_freq = 2*r4k_offset*HZ; | ||
244 | est_freq = r4k_offset*HZ; | ||
245 | est_freq += 5000; /* round */ | 229 | est_freq += 5000; /* round */ |
246 | est_freq -= est_freq%10000; | 230 | est_freq -= est_freq%10000; |
247 | printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, | 231 | printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, |
@@ -249,9 +233,6 @@ void __init plat_time_init(void) | |||
249 | set_au1x00_speed(est_freq); | 233 | set_au1x00_speed(est_freq); |
250 | set_au1x00_lcd_clock(); // program the LCD clock | 234 | set_au1x00_lcd_clock(); // program the LCD clock |
251 | 235 | ||
252 | r4k_cur = (read_c0_count() + r4k_offset); | ||
253 | write_c0_compare(r4k_cur); | ||
254 | |||
255 | #ifdef CONFIG_PM | 236 | #ifdef CONFIG_PM |
256 | /* | 237 | /* |
257 | * setup counter 0, since it keeps ticking after a | 238 | * setup counter 0, since it keeps ticking after a |
@@ -265,12 +246,8 @@ void __init plat_time_init(void) | |||
265 | * Check to ensure we really have a 32KHz oscillator before | 246 | * Check to ensure we really have a 32KHz oscillator before |
266 | * we do this. | 247 | * we do this. |
267 | */ | 248 | */ |
268 | if (no_au1xxx_32khz) { | 249 | if (no_au1xxx_32khz) |
269 | printk("WARNING: no 32KHz clock found.\n"); | 250 | printk("WARNING: no 32KHz clock found.\n"); |
270 | |||
271 | /* Ensure we get CPO_COUNTER interrupts. */ | ||
272 | set_c0_status(IE_IRQ5); | ||
273 | } | ||
274 | else { | 251 | else { |
275 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); | 252 | while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); |
276 | au_writel(0, SYS_TOYWRITE); | 253 | au_writel(0, SYS_TOYWRITE); |
diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c index 99eafeada518..b7dcbad5c586 100644 --- a/arch/mips/au1000/db1x00/board_setup.c +++ b/arch/mips/au1000/db1x00/board_setup.c | |||
@@ -27,20 +27,9 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/sched.h> | 32 | |
32 | #include <linux/ioport.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/console.h> | ||
35 | #include <linux/mc146818rtc.h> | ||
36 | #include <linux/delay.h> | ||
37 | |||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/bootinfo.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/mipsregs.h> | ||
42 | #include <asm/reboot.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mach-au1x00/au1000.h> | 33 | #include <asm/mach-au1x00/au1000.h> |
45 | #include <asm/mach-db1x00/db1x00.h> | 34 | #include <asm/mach-db1x00/db1x00.h> |
46 | 35 | ||
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c index e822c123eab8..d3b967caf70c 100644 --- a/arch/mips/au1000/db1x00/init.c +++ b/arch/mips/au1000/db1x00/init.c | |||
@@ -28,13 +28,8 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/bootmem.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
36 | 32 | ||
37 | #include <asm/addrspace.h> | ||
38 | #include <asm/bootinfo.h> | 33 | #include <asm/bootinfo.h> |
39 | 34 | ||
40 | #include <prom.h> | 35 | #include <prom.h> |
diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/au1000/db1x00/irqmap.c index 09cea03411b0..eaa50c7b6341 100644 --- a/arch/mips/au1000/db1x00/irqmap.c +++ b/arch/mips/au1000/db1x00/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | #ifdef CONFIG_MIPS_DB1500 | 33 | #ifdef CONFIG_MIPS_DB1500 |
diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c index 310d5dff89fc..5736354829c6 100644 --- a/arch/mips/au1000/mtx-1/board_setup.c +++ b/arch/mips/au1000/mtx-1/board_setup.c | |||
@@ -28,19 +28,9 @@ | |||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | 28 | * with this program; if not, write to the Free Software Foundation, Inc., |
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 29 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
30 | */ | 30 | */ |
31 | |||
31 | #include <linux/init.h> | 32 | #include <linux/init.h> |
32 | #include <linux/sched.h> | ||
33 | #include <linux/ioport.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/console.h> | ||
36 | #include <linux/delay.h> | ||
37 | 33 | ||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/bootinfo.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/mipsregs.h> | ||
42 | #include <asm/reboot.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mach-au1x00/au1000.h> | 34 | #include <asm/mach-au1x00/au1000.h> |
45 | 35 | ||
46 | extern int (*board_pci_idsel)(unsigned int devsel, int assert); | 36 | extern int (*board_pci_idsel)(unsigned int devsel, int assert); |
diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c index e700fd312a24..c015cbce1cca 100644 --- a/arch/mips/au1000/mtx-1/init.c +++ b/arch/mips/au1000/mtx-1/init.c | |||
@@ -28,14 +28,10 @@ | |||
28 | * with this program; if not, write to the Free Software Foundation, Inc., | 28 | * with this program; if not, write to the Free Software Foundation, Inc., |
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 29 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
30 | */ | 30 | */ |
31 | #include <linux/string.h> | 31 | |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/sched.h> | ||
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
35 | #include <linux/mm.h> | ||
36 | #include <linux/bootmem.h> | ||
37 | 34 | ||
38 | #include <asm/addrspace.h> | ||
39 | #include <asm/bootinfo.h> | 35 | #include <asm/bootinfo.h> |
40 | 36 | ||
41 | #include <prom.h> | 37 | #include <prom.h> |
diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/au1000/mtx-1/irqmap.c index 49c612aeddcf..78d70c42c9db 100644 --- a/arch/mips/au1000/mtx-1/irqmap.c +++ b/arch/mips/au1000/mtx-1/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | char irq_tab_alchemy[][5] __initdata = { | 33 | char irq_tab_alchemy[][5] __initdata = { |
diff --git a/arch/mips/au1000/mtx-1/platform.c b/arch/mips/au1000/mtx-1/platform.c index ce8637b3afa9..a7edbf0829ac 100644 --- a/arch/mips/au1000/mtx-1/platform.c +++ b/arch/mips/au1000/mtx-1/platform.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/types.h> | ||
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
24 | #include <linux/leds.h> | 23 | #include <linux/leds.h> |
25 | #include <linux/gpio_keys.h> | 24 | #include <linux/gpio_keys.h> |
diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c index 5198c4f98b43..33f15acc1b17 100644 --- a/arch/mips/au1000/pb1000/board_setup.c +++ b/arch/mips/au1000/pb1000/board_setup.c | |||
@@ -23,19 +23,10 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | |||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
32 | 29 | ||
33 | #include <asm/cpu.h> | ||
34 | #include <asm/bootinfo.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/mipsregs.h> | ||
37 | #include <asm/reboot.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | 30 | #include <asm/mach-au1x00/au1000.h> |
40 | #include <asm/mach-pb1x00/pb1000.h> | 31 | #include <asm/mach-pb1x00/pb1000.h> |
41 | 32 | ||
diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c index 2515b9fb24af..549447df71d6 100644 --- a/arch/mips/au1000/pb1000/init.c +++ b/arch/mips/au1000/pb1000/init.c | |||
@@ -26,14 +26,10 @@ | |||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | 26 | * with this program; if not, write to the Free Software Foundation, Inc., |
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 27 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
28 | */ | 28 | */ |
29 | |||
29 | #include <linux/init.h> | 30 | #include <linux/init.h> |
30 | #include <linux/mm.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/bootmem.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
35 | 32 | ||
36 | #include <asm/addrspace.h> | ||
37 | #include <asm/bootinfo.h> | 33 | #include <asm/bootinfo.h> |
38 | 34 | ||
39 | #include <prom.h> | 35 | #include <prom.h> |
diff --git a/arch/mips/au1000/pb1000/irqmap.c b/arch/mips/au1000/pb1000/irqmap.c index 88e354508204..b3d56b0af321 100644 --- a/arch/mips/au1000/pb1000/irqmap.c +++ b/arch/mips/au1000/pb1000/irqmap.c | |||
@@ -25,26 +25,10 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 31 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 32 | #include <asm/mach-au1x00/au1000.h> |
49 | 33 | ||
50 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { | 34 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { |
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index 42874a6b31d1..656164c8e9ca 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c | |||
@@ -23,19 +23,10 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | |||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
32 | 29 | ||
33 | #include <asm/cpu.h> | ||
34 | #include <asm/bootinfo.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/mipsregs.h> | ||
37 | #include <asm/reboot.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | 30 | #include <asm/mach-au1x00/au1000.h> |
40 | #include <asm/mach-pb1x00/pb1100.h> | 31 | #include <asm/mach-pb1x00/pb1100.h> |
41 | 32 | ||
diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c index 490c3801c275..c91344648ed3 100644 --- a/arch/mips/au1000/pb1100/init.c +++ b/arch/mips/au1000/pb1100/init.c | |||
@@ -27,14 +27,10 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/bootmem.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
36 | 33 | ||
37 | #include <asm/addrspace.h> | ||
38 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
39 | 35 | ||
40 | #include <prom.h> | 36 | #include <prom.h> |
diff --git a/arch/mips/au1000/pb1100/irqmap.c b/arch/mips/au1000/pb1100/irqmap.c index 880456bf8c11..b5021e3d477f 100644 --- a/arch/mips/au1000/pb1100/irqmap.c +++ b/arch/mips/au1000/pb1100/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { | 33 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { |
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile index 970b1b1d5cda..4fe02ea65a60 100644 --- a/arch/mips/au1000/pb1200/Makefile +++ b/arch/mips/au1000/pb1200/Makefile | |||
@@ -3,5 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | lib-y := init.o board_setup.o irqmap.o | 5 | lib-y := init.o board_setup.o irqmap.o |
6 | obj-y += platform.o | ||
6 | 7 | ||
7 | EXTRA_CFLAGS += -Werror | 8 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c index b98bebfa87c6..4493a792cc4c 100644 --- a/arch/mips/au1000/pb1200/board_setup.c +++ b/arch/mips/au1000/pb1200/board_setup.c | |||
@@ -23,27 +23,11 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | |||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/mc146818rtc.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #if defined(CONFIG_BLK_DEV_IDE_AU1XXX) | ||
35 | #include <linux/ide.h> | ||
36 | #endif | ||
37 | |||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/bootinfo.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/mipsregs.h> | ||
42 | #include <asm/reboot.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | 29 | ||
45 | #include <au1000.h> | 30 | #include <au1000.h> |
46 | #include <au1xxx_dbdma.h> | ||
47 | #include <prom.h> | 31 | #include <prom.h> |
48 | 32 | ||
49 | #ifdef CONFIG_MIPS_PB1200 | 33 | #ifdef CONFIG_MIPS_PB1200 |
@@ -52,8 +36,6 @@ | |||
52 | 36 | ||
53 | #ifdef CONFIG_MIPS_DB1200 | 37 | #ifdef CONFIG_MIPS_DB1200 |
54 | #include <asm/mach-db1x00/db1200.h> | 38 | #include <asm/mach-db1x00/db1200.h> |
55 | #define PB1200_ETH_INT DB1200_ETH_INT | ||
56 | #define PB1200_IDE_INT DB1200_IDE_INT | ||
57 | #endif | 39 | #endif |
58 | 40 | ||
59 | extern void _board_init_irq(void); | 41 | extern void _board_init_irq(void); |
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c index 069ed45f04f2..72af5500660b 100644 --- a/arch/mips/au1000/pb1200/init.c +++ b/arch/mips/au1000/pb1200/init.c | |||
@@ -27,14 +27,10 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/bootmem.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
36 | 33 | ||
37 | #include <asm/addrspace.h> | ||
38 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
39 | 35 | ||
40 | #include <prom.h> | 36 | #include <prom.h> |
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index 8fcd0df86f93..e61eb8e0b76b 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c | |||
@@ -22,26 +22,10 @@ | |||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | 22 | * with this program; if not, write to the Free Software Foundation, Inc., |
23 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | */ | 24 | */ |
25 | #include <linux/errno.h> | 25 | |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/irq.h> | ||
28 | #include <linux/kernel_stat.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/signal.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
34 | #include <linux/ioport.h> | 28 | |
35 | #include <linux/timex.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/random.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/bitops.h> | ||
40 | |||
41 | #include <asm/bootinfo.h> | ||
42 | #include <asm/io.h> | ||
43 | #include <asm/mipsregs.h> | ||
44 | #include <asm/system.h> | ||
45 | #include <asm/mach-au1x00/au1000.h> | 29 | #include <asm/mach-au1x00/au1000.h> |
46 | 30 | ||
47 | #ifdef CONFIG_MIPS_PB1200 | 31 | #ifdef CONFIG_MIPS_PB1200 |
diff --git a/arch/mips/au1000/pb1200/platform.c b/arch/mips/au1000/pb1200/platform.c new file mode 100644 index 000000000000..5930110b9b6d --- /dev/null +++ b/arch/mips/au1000/pb1200/platform.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Pb1200/DBAu1200 board platform device registration | ||
3 | * | ||
4 | * Copyright (C) 2008 MontaVista Software Inc. <source@mvista.com> | ||
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 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
24 | #include <asm/mach-au1x00/au1xxx.h> | ||
25 | |||
26 | static struct resource ide_resources[] = { | ||
27 | [0] = { | ||
28 | .start = IDE_PHYS_ADDR, | ||
29 | .end = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1, | ||
30 | .flags = IORESOURCE_MEM | ||
31 | }, | ||
32 | [1] = { | ||
33 | .start = IDE_INT, | ||
34 | .end = IDE_INT, | ||
35 | .flags = IORESOURCE_IRQ | ||
36 | } | ||
37 | }; | ||
38 | |||
39 | static u64 ide_dmamask = ~(u32)0; | ||
40 | |||
41 | static struct platform_device ide_device = { | ||
42 | .name = "au1200-ide", | ||
43 | .id = 0, | ||
44 | .dev = { | ||
45 | .dma_mask = &ide_dmamask, | ||
46 | .coherent_dma_mask = 0xffffffff, | ||
47 | }, | ||
48 | .num_resources = ARRAY_SIZE(ide_resources), | ||
49 | .resource = ide_resources | ||
50 | }; | ||
51 | |||
52 | static struct resource smc91c111_resources[] = { | ||
53 | [0] = { | ||
54 | .name = "smc91x-regs", | ||
55 | .start = SMC91C111_PHYS_ADDR, | ||
56 | .end = SMC91C111_PHYS_ADDR + 0xf, | ||
57 | .flags = IORESOURCE_MEM | ||
58 | }, | ||
59 | [1] = { | ||
60 | .start = SMC91C111_INT, | ||
61 | .end = SMC91C111_INT, | ||
62 | .flags = IORESOURCE_IRQ | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | static struct platform_device smc91c111_device = { | ||
67 | .name = "smc91x", | ||
68 | .id = -1, | ||
69 | .num_resources = ARRAY_SIZE(smc91c111_resources), | ||
70 | .resource = smc91c111_resources | ||
71 | }; | ||
72 | |||
73 | static struct platform_device *board_platform_devices[] __initdata = { | ||
74 | &ide_device, | ||
75 | &smc91c111_device | ||
76 | }; | ||
77 | |||
78 | static int __init board_register_devices(void) | ||
79 | { | ||
80 | return platform_add_devices(board_platform_devices, | ||
81 | ARRAY_SIZE(board_platform_devices)); | ||
82 | } | ||
83 | |||
84 | arch_initcall(board_register_devices); | ||
diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c index 5446836869d6..24c652e8ec4b 100644 --- a/arch/mips/au1000/pb1500/board_setup.c +++ b/arch/mips/au1000/pb1500/board_setup.c | |||
@@ -23,19 +23,10 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | |||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
32 | 29 | ||
33 | #include <asm/cpu.h> | ||
34 | #include <asm/bootinfo.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/mipsregs.h> | ||
37 | #include <asm/reboot.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | 30 | #include <asm/mach-au1x00/au1000.h> |
40 | #include <asm/mach-pb1x00/pb1500.h> | 31 | #include <asm/mach-pb1x00/pb1500.h> |
41 | 32 | ||
diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c index db558c967048..488507c07db9 100644 --- a/arch/mips/au1000/pb1500/init.c +++ b/arch/mips/au1000/pb1500/init.c | |||
@@ -27,14 +27,10 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/bootmem.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
36 | 33 | ||
37 | #include <asm/addrspace.h> | ||
38 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
39 | 35 | ||
40 | #include <prom.h> | 36 | #include <prom.h> |
diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/au1000/pb1500/irqmap.c index 810f695e24bb..4817ab44d07f 100644 --- a/arch/mips/au1000/pb1500/irqmap.c +++ b/arch/mips/au1000/pb1500/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | char irq_tab_alchemy[][5] __initdata = { | 33 | char irq_tab_alchemy[][5] __initdata = { |
diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/au1000/pb1550/board_setup.c index e3cfb0d73180..45d60872b565 100644 --- a/arch/mips/au1000/pb1550/board_setup.c +++ b/arch/mips/au1000/pb1550/board_setup.c | |||
@@ -27,20 +27,9 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/sched.h> | ||
32 | #include <linux/ioport.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/console.h> | ||
35 | #include <linux/mc146818rtc.h> | ||
36 | #include <linux/delay.h> | ||
37 | 32 | ||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/bootinfo.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/mipsregs.h> | ||
42 | #include <asm/reboot.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mach-au1x00/au1000.h> | 33 | #include <asm/mach-au1x00/au1000.h> |
45 | #include <asm/mach-pb1x00/pb1550.h> | 34 | #include <asm/mach-pb1x00/pb1550.h> |
46 | 35 | ||
diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c index b716363ea564..f6b2fc587980 100644 --- a/arch/mips/au1000/pb1550/init.c +++ b/arch/mips/au1000/pb1550/init.c | |||
@@ -27,14 +27,10 @@ | |||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 27 | * with this program; if not, write to the Free Software Foundation, Inc., |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 28 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | */ | 29 | */ |
30 | |||
30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/bootmem.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
36 | 33 | ||
37 | #include <asm/addrspace.h> | ||
38 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
39 | 35 | ||
40 | #include <prom.h> | 36 | #include <prom.h> |
diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/au1000/pb1550/irqmap.c index 56becab28e5d..e1dac37af08a 100644 --- a/arch/mips/au1000/pb1550/irqmap.c +++ b/arch/mips/au1000/pb1550/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | char irq_tab_alchemy[][5] __initdata = { | 33 | char irq_tab_alchemy[][5] __initdata = { |
diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c index b2e413e597a8..79d1798621bf 100644 --- a/arch/mips/au1000/xxs1500/board_setup.c +++ b/arch/mips/au1000/xxs1500/board_setup.c | |||
@@ -23,19 +23,10 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | |||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
32 | 29 | ||
33 | #include <asm/cpu.h> | ||
34 | #include <asm/bootinfo.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/mipsregs.h> | ||
37 | #include <asm/reboot.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/mach-au1x00/au1000.h> | 30 | #include <asm/mach-au1x00/au1000.h> |
40 | 31 | ||
41 | void board_reset(void) | 32 | void board_reset(void) |
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c index 7e6878c1b0a5..24fc6e132dc0 100644 --- a/arch/mips/au1000/xxs1500/init.c +++ b/arch/mips/au1000/xxs1500/init.c | |||
@@ -26,14 +26,10 @@ | |||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | 26 | * with this program; if not, write to the Free Software Foundation, Inc., |
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 27 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
28 | */ | 28 | */ |
29 | |||
29 | #include <linux/init.h> | 30 | #include <linux/init.h> |
30 | #include <linux/mm.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/bootmem.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
35 | 32 | ||
36 | #include <asm/addrspace.h> | ||
37 | #include <asm/bootinfo.h> | 33 | #include <asm/bootinfo.h> |
38 | 34 | ||
39 | #include <prom.h> | 35 | #include <prom.h> |
diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/au1000/xxs1500/irqmap.c index a343da134334..dd6e3d1eb4d4 100644 --- a/arch/mips/au1000/xxs1500/irqmap.c +++ b/arch/mips/au1000/xxs1500/irqmap.c | |||
@@ -25,26 +25,9 @@ | |||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | 25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/errno.h> | 28 | |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/irq.h> | ||
31 | #include <linux/kernel_stat.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/signal.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/timex.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/random.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/bitops.h> | ||
43 | 30 | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/mipsregs.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/mach-au1x00/au1000.h> | 31 | #include <asm/mach-au1x00/au1000.h> |
49 | 32 | ||
50 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { | 33 | struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { |
diff --git a/arch/mips/basler/excite/excite_procfs.c b/arch/mips/basler/excite/excite_procfs.c index 9ee67a95f6b9..08923e6825b5 100644 --- a/arch/mips/basler/excite/excite_procfs.c +++ b/arch/mips/basler/excite/excite_procfs.c | |||
@@ -18,8 +18,9 @@ | |||
18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | #include <linux/module.h> | |
22 | #include <linux/proc_fs.h> | 22 | #include <linux/proc_fs.h> |
23 | #include <linux/seq_file.h> | ||
23 | #include <linux/stat.h> | 24 | #include <linux/stat.h> |
24 | #include <asm/page.h> | 25 | #include <asm/page.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -28,14 +29,25 @@ | |||
28 | 29 | ||
29 | #include <excite.h> | 30 | #include <excite.h> |
30 | 31 | ||
31 | static int excite_get_unit_id(char *buf, char **addr, off_t offs, int size) | 32 | static int excite_unit_id_proc_show(struct seq_file *m, void *v) |
32 | { | 33 | { |
33 | const int len = snprintf(buf, PAGE_SIZE, "%06x", unit_id); | 34 | seq_printf(m, "%06x", unit_id); |
34 | const int w = len - offs; | 35 | return 0; |
35 | *addr = buf + offs; | ||
36 | return w < size ? w : size; | ||
37 | } | 36 | } |
38 | 37 | ||
38 | static int excite_unit_id_proc_open(struct inode *inode, struct file *file) | ||
39 | { | ||
40 | return single_open(file, excite_unit_id_proc_show, NULL); | ||
41 | } | ||
42 | |||
43 | static const struct file_operations excite_unit_id_proc_fops = { | ||
44 | .owner = THIS_MODULE, | ||
45 | .open = excite_unit_id_proc_open, | ||
46 | .read = seq_read, | ||
47 | .llseek = seq_lseek, | ||
48 | .release = single_release, | ||
49 | }; | ||
50 | |||
39 | static int | 51 | static int |
40 | excite_bootrom_read(char *page, char **start, off_t off, int count, | 52 | excite_bootrom_read(char *page, char **start, off_t off, int count, |
41 | int *eof, void *data) | 53 | int *eof, void *data) |
@@ -65,12 +77,12 @@ excite_bootrom_read(char *page, char **start, off_t off, int count, | |||
65 | void excite_procfs_init(void) | 77 | void excite_procfs_init(void) |
66 | { | 78 | { |
67 | /* Create & populate /proc/excite */ | 79 | /* Create & populate /proc/excite */ |
68 | struct proc_dir_entry * const pdir = proc_mkdir("excite", &proc_root); | 80 | struct proc_dir_entry * const pdir = proc_mkdir("excite", NULL); |
69 | if (pdir) { | 81 | if (pdir) { |
70 | struct proc_dir_entry * e; | 82 | struct proc_dir_entry * e; |
71 | 83 | ||
72 | e = create_proc_info_entry("unit_id", S_IRUGO, pdir, | 84 | e = proc_create("unit_id", S_IRUGO, pdir, |
73 | excite_get_unit_id); | 85 | &excite_unit_id_proc_fops); |
74 | if (e) e->size = 6; | 86 | if (e) e->size = 6; |
75 | 87 | ||
76 | e = create_proc_read_entry("bootrom", S_IRUGO, pdir, | 88 | e = create_proc_read_entry("bootrom", S_IRUGO, pdir, |
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 6db0bdaefb27..4f6bce99d5cf 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig | |||
@@ -641,7 +641,6 @@ CONFIG_CROSSCOMPILE=y | |||
641 | CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp" | 641 | CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp" |
642 | # CONFIG_DEBUG_STACK_USAGE is not set | 642 | # CONFIG_DEBUG_STACK_USAGE is not set |
643 | # CONFIG_RUNTIME_DEBUG is not set | 643 | # CONFIG_RUNTIME_DEBUG is not set |
644 | # CONFIG_MIPS_UNCACHED is not set | ||
645 | 644 | ||
646 | # | 645 | # |
647 | # Security options | 646 | # Security options |
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 518a60892b78..780c7fc24b82 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig | |||
@@ -1223,7 +1223,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" | |||
1223 | # CONFIG_KGDB is not set | 1223 | # CONFIG_KGDB is not set |
1224 | CONFIG_SYS_SUPPORTS_KGDB=y | 1224 | CONFIG_SYS_SUPPORTS_KGDB=y |
1225 | # CONFIG_RUNTIME_DEBUG is not set | 1225 | # CONFIG_RUNTIME_DEBUG is not set |
1226 | # CONFIG_MIPS_UNCACHED is not set | ||
1227 | 1226 | ||
1228 | # | 1227 | # |
1229 | # Security options | 1228 | # Security options |
diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig index 68351eb81bc8..267f21ed1d0f 100644 --- a/arch/mips/configs/pnx8550-stb810_defconfig +++ b/arch/mips/configs/pnx8550-stb810_defconfig | |||
@@ -1213,7 +1213,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp" | |||
1213 | # CONFIG_KGDB is not set | 1213 | # CONFIG_KGDB is not set |
1214 | CONFIG_SYS_SUPPORTS_KGDB=y | 1214 | CONFIG_SYS_SUPPORTS_KGDB=y |
1215 | # CONFIG_RUNTIME_DEBUG is not set | 1215 | # CONFIG_RUNTIME_DEBUG is not set |
1216 | # CONFIG_MIPS_UNCACHED is not set | ||
1217 | 1216 | ||
1218 | # | 1217 | # |
1219 | # Security options | 1218 | # Security options |
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 60349062595a..3965fda94a89 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c | |||
@@ -9,30 +9,15 @@ | |||
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | #include <linux/bcd.h> | 11 | #include <linux/bcd.h> |
12 | #include <linux/errno.h> | ||
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/mc146818rtc.h> | 13 | #include <linux/mc146818rtc.h> |
17 | #include <linux/mm.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/param.h> | 14 | #include <linux/param.h> |
20 | #include <linux/sched.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include <asm/bootinfo.h> | ||
26 | #include <asm/cpu.h> | ||
27 | #include <asm/io.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/mipsregs.h> | ||
30 | #include <asm/sections.h> | ||
31 | #include <asm/time.h> | ||
32 | 15 | ||
16 | #include <asm/cpu-features.h> | ||
17 | #include <asm/ds1287.h> | ||
18 | #include <asm/time.h> | ||
33 | #include <asm/dec/interrupts.h> | 19 | #include <asm/dec/interrupts.h> |
34 | #include <asm/dec/ioasic.h> | 20 | #include <asm/dec/ioasic.h> |
35 | #include <asm/dec/ioasic_addrs.h> | ||
36 | #include <asm/dec/machtype.h> | 21 | #include <asm/dec/machtype.h> |
37 | 22 | ||
38 | unsigned long read_persistent_clock(void) | 23 | unsigned long read_persistent_clock(void) |
@@ -139,42 +124,32 @@ int rtc_mips_set_mmss(unsigned long nowtime) | |||
139 | return retval; | 124 | return retval; |
140 | } | 125 | } |
141 | 126 | ||
142 | static int dec_timer_state(void) | 127 | void __init plat_time_init(void) |
143 | { | 128 | { |
144 | return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; | 129 | u32 start, end; |
145 | } | 130 | int i = HZ / 10; |
146 | 131 | ||
147 | static void dec_timer_ack(void) | 132 | /* Set up the rate of periodic DS1287 interrupts. */ |
148 | { | 133 | ds1287_set_base_clock(HZ); |
149 | CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */ | ||
150 | } | ||
151 | |||
152 | static cycle_t dec_ioasic_hpt_read(void) | ||
153 | { | ||
154 | /* | ||
155 | * The free-running counter is 32-bit which is good for about | ||
156 | * 2 minutes, 50 seconds at possible count rates of up to 25MHz. | ||
157 | */ | ||
158 | return ioasic_read(IO_REG_FCTR); | ||
159 | } | ||
160 | 134 | ||
135 | if (cpu_has_counter) { | ||
136 | while (!ds1287_timer_state()) | ||
137 | ; | ||
161 | 138 | ||
162 | void __init plat_time_init(void) | 139 | start = read_c0_count(); |
163 | { | ||
164 | mips_timer_ack = dec_timer_ack; | ||
165 | 140 | ||
166 | if (!cpu_has_counter && IOASIC) | 141 | while (i--) |
167 | /* For pre-R4k systems we use the I/O ASIC's counter. */ | 142 | while (!ds1287_timer_state()) |
168 | clocksource_mips.read = dec_ioasic_hpt_read; | 143 | ; |
169 | 144 | ||
170 | /* Set up the rate of periodic DS1287 interrupts. */ | 145 | end = read_c0_count(); |
171 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A); | ||
172 | } | ||
173 | 146 | ||
174 | void __init plat_timer_setup(struct irqaction *irq) | 147 | mips_hpt_frequency = (end - start) * 10; |
175 | { | 148 | printk(KERN_INFO "MIPS counter frequency %dHz\n", |
176 | setup_irq(dec_interrupt[DEC_IRQ_RTC], irq); | 149 | mips_hpt_frequency); |
150 | } else if (IOASIC) | ||
151 | /* For pre-R4k systems we use the I/O ASIC's counter. */ | ||
152 | dec_ioasic_clocksource_init(); | ||
177 | 153 | ||
178 | /* Enable periodic DS1287 interrupts. */ | 154 | ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); |
179 | CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B); | ||
180 | } | 155 | } |
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index c886d804d303..f39c444e42d4 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c | |||
@@ -36,11 +36,13 @@ | |||
36 | #include <linux/pm.h> | 36 | #include <linux/pm.h> |
37 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
38 | #include <linux/clk.h> | 38 | #include <linux/clk.h> |
39 | #include <linux/gpio.h> | ||
39 | #ifdef CONFIG_SERIAL_TXX9 | 40 | #ifdef CONFIG_SERIAL_TXX9 |
40 | #include <linux/serial_core.h> | 41 | #include <linux/serial_core.h> |
41 | #endif | 42 | #endif |
42 | 43 | ||
43 | #include <asm/txx9tmr.h> | 44 | #include <asm/txx9tmr.h> |
45 | #include <asm/txx9pio.h> | ||
44 | #include <asm/reboot.h> | 46 | #include <asm/reboot.h> |
45 | #include <asm/jmr3927/jmr3927.h> | 47 | #include <asm/jmr3927/jmr3927.h> |
46 | #include <asm/mipsregs.h> | 48 | #include <asm/mipsregs.h> |
@@ -340,9 +342,12 @@ static void __init tx3927_setup(void) | |||
340 | 342 | ||
341 | /* PIO */ | 343 | /* PIO */ |
342 | /* PIO[15:12] connected to LEDs */ | 344 | /* PIO[15:12] connected to LEDs */ |
343 | tx3927_pioptr->dir = 0x0000f000; | 345 | __raw_writel(0x0000f000, &tx3927_pioptr->dir); |
344 | tx3927_pioptr->maskcpu = 0; | 346 | __raw_writel(0, &tx3927_pioptr->maskcpu); |
345 | tx3927_pioptr->maskext = 0; | 347 | __raw_writel(0, &tx3927_pioptr->maskext); |
348 | txx9_gpio_init(TX3927_PIO_REG, 0, 16); | ||
349 | gpio_request(11, "dipsw1"); | ||
350 | gpio_request(10, "dipsw2"); | ||
346 | { | 351 | { |
347 | unsigned int conf; | 352 | unsigned int conf; |
348 | 353 | ||
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 6fcdb6fda2e2..45545be3eb86 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -10,12 +10,15 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ | |||
10 | 10 | ||
11 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o | 11 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o |
12 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o | 12 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o |
13 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o | ||
13 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o | 14 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o |
14 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o | 15 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o |
15 | obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o | 16 | obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o |
16 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o | 17 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o |
18 | obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o | ||
17 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o | 19 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o |
18 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o | 20 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o |
21 | obj-$(CONFIG_SYNC_R4K) += sync-r4k.o | ||
19 | 22 | ||
20 | binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ | 23 | binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ |
21 | irix5sys.o sysirix.o | 24 | irix5sys.o sysirix.o |
@@ -50,6 +53,8 @@ obj-$(CONFIG_MIPS_MT) += mips-mt.o | |||
50 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o | 53 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o |
51 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o | 54 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o |
52 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o | 55 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o |
56 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o | ||
57 | obj-$(CONFIG_CPU_MIPSR2) += spram.o | ||
53 | 58 | ||
54 | obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o | 59 | obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o |
55 | obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o | 60 | obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o |
@@ -62,6 +67,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o | |||
62 | obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o | 67 | obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o |
63 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o | 68 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o |
64 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o | 69 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o |
70 | obj-$(CONFIG_IRQ_GIC) += irq-gic.o | ||
65 | 71 | ||
66 | obj-$(CONFIG_32BIT) += scall32-o32.o | 72 | obj-$(CONFIG_32BIT) += scall32-o32.o |
67 | obj-$(CONFIG_64BIT) += scall64-64.o | 73 | obj-$(CONFIG_64BIT) += scall64-64.o |
@@ -77,6 +83,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o | |||
77 | 83 | ||
78 | obj-$(CONFIG_I8253) += i8253.o | 84 | obj-$(CONFIG_I8253) += i8253.o |
79 | 85 | ||
86 | obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o | ||
87 | |||
80 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 88 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
81 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 89 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
82 | 90 | ||
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ca136298acdc..72942226fcdd 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c | |||
@@ -13,327 +13,285 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | 16 | #include <linux/kbuild.h> | |
17 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
19 | 19 | ||
20 | #define text(t) __asm__("\n@@@" t) | ||
21 | #define _offset(type, member) (&(((type *)NULL)->member)) | ||
22 | #define offset(string, ptr, member) \ | ||
23 | __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member))) | ||
24 | #define constant(string, member) \ | ||
25 | __asm__("\n@@@" string "%X0" : : "ri" (member)) | ||
26 | #define size(string, size) \ | ||
27 | __asm__("\n@@@" string "%0" : : "i" (sizeof(size))) | ||
28 | #define linefeed text("") | ||
29 | |||
30 | void output_ptreg_defines(void) | 20 | void output_ptreg_defines(void) |
31 | { | 21 | { |
32 | text("/* MIPS pt_regs offsets. */"); | 22 | COMMENT("MIPS pt_regs offsets."); |
33 | offset("#define PT_R0 ", struct pt_regs, regs[0]); | 23 | OFFSET(PT_R0, pt_regs, regs[0]); |
34 | offset("#define PT_R1 ", struct pt_regs, regs[1]); | 24 | OFFSET(PT_R1, pt_regs, regs[1]); |
35 | offset("#define PT_R2 ", struct pt_regs, regs[2]); | 25 | OFFSET(PT_R2, pt_regs, regs[2]); |
36 | offset("#define PT_R3 ", struct pt_regs, regs[3]); | 26 | OFFSET(PT_R3, pt_regs, regs[3]); |
37 | offset("#define PT_R4 ", struct pt_regs, regs[4]); | 27 | OFFSET(PT_R4, pt_regs, regs[4]); |
38 | offset("#define PT_R5 ", struct pt_regs, regs[5]); | 28 | OFFSET(PT_R5, pt_regs, regs[5]); |
39 | offset("#define PT_R6 ", struct pt_regs, regs[6]); | 29 | OFFSET(PT_R6, pt_regs, regs[6]); |
40 | offset("#define PT_R7 ", struct pt_regs, regs[7]); | 30 | OFFSET(PT_R7, pt_regs, regs[7]); |
41 | offset("#define PT_R8 ", struct pt_regs, regs[8]); | 31 | OFFSET(PT_R8, pt_regs, regs[8]); |
42 | offset("#define PT_R9 ", struct pt_regs, regs[9]); | 32 | OFFSET(PT_R9, pt_regs, regs[9]); |
43 | offset("#define PT_R10 ", struct pt_regs, regs[10]); | 33 | OFFSET(PT_R10, pt_regs, regs[10]); |
44 | offset("#define PT_R11 ", struct pt_regs, regs[11]); | 34 | OFFSET(PT_R11, pt_regs, regs[11]); |
45 | offset("#define PT_R12 ", struct pt_regs, regs[12]); | 35 | OFFSET(PT_R12, pt_regs, regs[12]); |
46 | offset("#define PT_R13 ", struct pt_regs, regs[13]); | 36 | OFFSET(PT_R13, pt_regs, regs[13]); |
47 | offset("#define PT_R14 ", struct pt_regs, regs[14]); | 37 | OFFSET(PT_R14, pt_regs, regs[14]); |
48 | offset("#define PT_R15 ", struct pt_regs, regs[15]); | 38 | OFFSET(PT_R15, pt_regs, regs[15]); |
49 | offset("#define PT_R16 ", struct pt_regs, regs[16]); | 39 | OFFSET(PT_R16, pt_regs, regs[16]); |
50 | offset("#define PT_R17 ", struct pt_regs, regs[17]); | 40 | OFFSET(PT_R17, pt_regs, regs[17]); |
51 | offset("#define PT_R18 ", struct pt_regs, regs[18]); | 41 | OFFSET(PT_R18, pt_regs, regs[18]); |
52 | offset("#define PT_R19 ", struct pt_regs, regs[19]); | 42 | OFFSET(PT_R19, pt_regs, regs[19]); |
53 | offset("#define PT_R20 ", struct pt_regs, regs[20]); | 43 | OFFSET(PT_R20, pt_regs, regs[20]); |
54 | offset("#define PT_R21 ", struct pt_regs, regs[21]); | 44 | OFFSET(PT_R21, pt_regs, regs[21]); |
55 | offset("#define PT_R22 ", struct pt_regs, regs[22]); | 45 | OFFSET(PT_R22, pt_regs, regs[22]); |
56 | offset("#define PT_R23 ", struct pt_regs, regs[23]); | 46 | OFFSET(PT_R23, pt_regs, regs[23]); |
57 | offset("#define PT_R24 ", struct pt_regs, regs[24]); | 47 | OFFSET(PT_R24, pt_regs, regs[24]); |
58 | offset("#define PT_R25 ", struct pt_regs, regs[25]); | 48 | OFFSET(PT_R25, pt_regs, regs[25]); |
59 | offset("#define PT_R26 ", struct pt_regs, regs[26]); | 49 | OFFSET(PT_R26, pt_regs, regs[26]); |
60 | offset("#define PT_R27 ", struct pt_regs, regs[27]); | 50 | OFFSET(PT_R27, pt_regs, regs[27]); |
61 | offset("#define PT_R28 ", struct pt_regs, regs[28]); | 51 | OFFSET(PT_R28, pt_regs, regs[28]); |
62 | offset("#define PT_R29 ", struct pt_regs, regs[29]); | 52 | OFFSET(PT_R29, pt_regs, regs[29]); |
63 | offset("#define PT_R30 ", struct pt_regs, regs[30]); | 53 | OFFSET(PT_R30, pt_regs, regs[30]); |
64 | offset("#define PT_R31 ", struct pt_regs, regs[31]); | 54 | OFFSET(PT_R31, pt_regs, regs[31]); |
65 | offset("#define PT_LO ", struct pt_regs, lo); | 55 | OFFSET(PT_LO, pt_regs, lo); |
66 | offset("#define PT_HI ", struct pt_regs, hi); | 56 | OFFSET(PT_HI, pt_regs, hi); |
67 | #ifdef CONFIG_CPU_HAS_SMARTMIPS | 57 | #ifdef CONFIG_CPU_HAS_SMARTMIPS |
68 | offset("#define PT_ACX ", struct pt_regs, acx); | 58 | OFFSET(PT_ACX, pt_regs, acx); |
69 | #endif | 59 | #endif |
70 | offset("#define PT_EPC ", struct pt_regs, cp0_epc); | 60 | OFFSET(PT_EPC, pt_regs, cp0_epc); |
71 | offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr); | 61 | OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr); |
72 | offset("#define PT_STATUS ", struct pt_regs, cp0_status); | 62 | OFFSET(PT_STATUS, pt_regs, cp0_status); |
73 | offset("#define PT_CAUSE ", struct pt_regs, cp0_cause); | 63 | OFFSET(PT_CAUSE, pt_regs, cp0_cause); |
74 | #ifdef CONFIG_MIPS_MT_SMTC | 64 | #ifdef CONFIG_MIPS_MT_SMTC |
75 | offset("#define PT_TCSTATUS ", struct pt_regs, cp0_tcstatus); | 65 | OFFSET(PT_TCSTATUS, pt_regs, cp0_tcstatus); |
76 | #endif /* CONFIG_MIPS_MT_SMTC */ | 66 | #endif /* CONFIG_MIPS_MT_SMTC */ |
77 | size("#define PT_SIZE ", struct pt_regs); | 67 | DEFINE(PT_SIZE, sizeof(struct pt_regs)); |
78 | linefeed; | 68 | BLANK(); |
79 | } | 69 | } |
80 | 70 | ||
81 | void output_task_defines(void) | 71 | void output_task_defines(void) |
82 | { | 72 | { |
83 | text("/* MIPS task_struct offsets. */"); | 73 | COMMENT("MIPS task_struct offsets."); |
84 | offset("#define TASK_STATE ", struct task_struct, state); | 74 | OFFSET(TASK_STATE, task_struct, state); |
85 | offset("#define TASK_THREAD_INFO ", struct task_struct, stack); | 75 | OFFSET(TASK_THREAD_INFO, task_struct, stack); |
86 | offset("#define TASK_FLAGS ", struct task_struct, flags); | 76 | OFFSET(TASK_FLAGS, task_struct, flags); |
87 | offset("#define TASK_MM ", struct task_struct, mm); | 77 | OFFSET(TASK_MM, task_struct, mm); |
88 | offset("#define TASK_PID ", struct task_struct, pid); | 78 | OFFSET(TASK_PID, task_struct, pid); |
89 | size( "#define TASK_STRUCT_SIZE ", struct task_struct); | 79 | DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); |
90 | linefeed; | 80 | BLANK(); |
91 | } | 81 | } |
92 | 82 | ||
93 | void output_thread_info_defines(void) | 83 | void output_thread_info_defines(void) |
94 | { | 84 | { |
95 | text("/* MIPS thread_info offsets. */"); | 85 | COMMENT("MIPS thread_info offsets."); |
96 | offset("#define TI_TASK ", struct thread_info, task); | 86 | OFFSET(TI_TASK, thread_info, task); |
97 | offset("#define TI_EXEC_DOMAIN ", struct thread_info, exec_domain); | 87 | OFFSET(TI_EXEC_DOMAIN, thread_info, exec_domain); |
98 | offset("#define TI_FLAGS ", struct thread_info, flags); | 88 | OFFSET(TI_FLAGS, thread_info, flags); |
99 | offset("#define TI_TP_VALUE ", struct thread_info, tp_value); | 89 | OFFSET(TI_TP_VALUE, thread_info, tp_value); |
100 | offset("#define TI_CPU ", struct thread_info, cpu); | 90 | OFFSET(TI_CPU, thread_info, cpu); |
101 | offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count); | 91 | OFFSET(TI_PRE_COUNT, thread_info, preempt_count); |
102 | offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); | 92 | OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit); |
103 | offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); | 93 | OFFSET(TI_RESTART_BLOCK, thread_info, restart_block); |
104 | offset("#define TI_REGS ", struct thread_info, regs); | 94 | OFFSET(TI_REGS, thread_info, regs); |
105 | constant("#define _THREAD_SIZE ", THREAD_SIZE); | 95 | DEFINE(_THREAD_SIZE, THREAD_SIZE); |
106 | constant("#define _THREAD_MASK ", THREAD_MASK); | 96 | DEFINE(_THREAD_MASK, THREAD_MASK); |
107 | linefeed; | 97 | BLANK(); |
108 | } | 98 | } |
109 | 99 | ||
110 | void output_thread_defines(void) | 100 | void output_thread_defines(void) |
111 | { | 101 | { |
112 | text("/* MIPS specific thread_struct offsets. */"); | 102 | COMMENT("MIPS specific thread_struct offsets."); |
113 | offset("#define THREAD_REG16 ", struct task_struct, thread.reg16); | 103 | OFFSET(THREAD_REG16, task_struct, thread.reg16); |
114 | offset("#define THREAD_REG17 ", struct task_struct, thread.reg17); | 104 | OFFSET(THREAD_REG17, task_struct, thread.reg17); |
115 | offset("#define THREAD_REG18 ", struct task_struct, thread.reg18); | 105 | OFFSET(THREAD_REG18, task_struct, thread.reg18); |
116 | offset("#define THREAD_REG19 ", struct task_struct, thread.reg19); | 106 | OFFSET(THREAD_REG19, task_struct, thread.reg19); |
117 | offset("#define THREAD_REG20 ", struct task_struct, thread.reg20); | 107 | OFFSET(THREAD_REG20, task_struct, thread.reg20); |
118 | offset("#define THREAD_REG21 ", struct task_struct, thread.reg21); | 108 | OFFSET(THREAD_REG21, task_struct, thread.reg21); |
119 | offset("#define THREAD_REG22 ", struct task_struct, thread.reg22); | 109 | OFFSET(THREAD_REG22, task_struct, thread.reg22); |
120 | offset("#define THREAD_REG23 ", struct task_struct, thread.reg23); | 110 | OFFSET(THREAD_REG23, task_struct, thread.reg23); |
121 | offset("#define THREAD_REG29 ", struct task_struct, thread.reg29); | 111 | OFFSET(THREAD_REG29, task_struct, thread.reg29); |
122 | offset("#define THREAD_REG30 ", struct task_struct, thread.reg30); | 112 | OFFSET(THREAD_REG30, task_struct, thread.reg30); |
123 | offset("#define THREAD_REG31 ", struct task_struct, thread.reg31); | 113 | OFFSET(THREAD_REG31, task_struct, thread.reg31); |
124 | offset("#define THREAD_STATUS ", struct task_struct, | 114 | OFFSET(THREAD_STATUS, task_struct, |
125 | thread.cp0_status); | 115 | thread.cp0_status); |
126 | offset("#define THREAD_FPU ", struct task_struct, thread.fpu); | 116 | OFFSET(THREAD_FPU, task_struct, thread.fpu); |
127 | 117 | ||
128 | offset("#define THREAD_BVADDR ", struct task_struct, \ | 118 | OFFSET(THREAD_BVADDR, task_struct, \ |
129 | thread.cp0_badvaddr); | 119 | thread.cp0_badvaddr); |
130 | offset("#define THREAD_BUADDR ", struct task_struct, \ | 120 | OFFSET(THREAD_BUADDR, task_struct, \ |
131 | thread.cp0_baduaddr); | 121 | thread.cp0_baduaddr); |
132 | offset("#define THREAD_ECODE ", struct task_struct, \ | 122 | OFFSET(THREAD_ECODE, task_struct, \ |
133 | thread.error_code); | 123 | thread.error_code); |
134 | offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no); | 124 | OFFSET(THREAD_TRAPNO, task_struct, thread.trap_no); |
135 | offset("#define THREAD_TRAMP ", struct task_struct, \ | 125 | OFFSET(THREAD_TRAMP, task_struct, \ |
136 | thread.irix_trampoline); | 126 | thread.irix_trampoline); |
137 | offset("#define THREAD_OLDCTX ", struct task_struct, \ | 127 | OFFSET(THREAD_OLDCTX, task_struct, \ |
138 | thread.irix_oldctx); | 128 | thread.irix_oldctx); |
139 | linefeed; | 129 | BLANK(); |
140 | } | 130 | } |
141 | 131 | ||
142 | void output_thread_fpu_defines(void) | 132 | void output_thread_fpu_defines(void) |
143 | { | 133 | { |
144 | offset("#define THREAD_FPR0 ", | 134 | OFFSET(THREAD_FPR0, task_struct, thread.fpu.fpr[0]); |
145 | struct task_struct, thread.fpu.fpr[0]); | 135 | OFFSET(THREAD_FPR1, task_struct, thread.fpu.fpr[1]); |
146 | offset("#define THREAD_FPR1 ", | 136 | OFFSET(THREAD_FPR2, task_struct, thread.fpu.fpr[2]); |
147 | struct task_struct, thread.fpu.fpr[1]); | 137 | OFFSET(THREAD_FPR3, task_struct, thread.fpu.fpr[3]); |
148 | offset("#define THREAD_FPR2 ", | 138 | OFFSET(THREAD_FPR4, task_struct, thread.fpu.fpr[4]); |
149 | struct task_struct, thread.fpu.fpr[2]); | 139 | OFFSET(THREAD_FPR5, task_struct, thread.fpu.fpr[5]); |
150 | offset("#define THREAD_FPR3 ", | 140 | OFFSET(THREAD_FPR6, task_struct, thread.fpu.fpr[6]); |
151 | struct task_struct, thread.fpu.fpr[3]); | 141 | OFFSET(THREAD_FPR7, task_struct, thread.fpu.fpr[7]); |
152 | offset("#define THREAD_FPR4 ", | 142 | OFFSET(THREAD_FPR8, task_struct, thread.fpu.fpr[8]); |
153 | struct task_struct, thread.fpu.fpr[4]); | 143 | OFFSET(THREAD_FPR9, task_struct, thread.fpu.fpr[9]); |
154 | offset("#define THREAD_FPR5 ", | 144 | OFFSET(THREAD_FPR10, task_struct, thread.fpu.fpr[10]); |
155 | struct task_struct, thread.fpu.fpr[5]); | 145 | OFFSET(THREAD_FPR11, task_struct, thread.fpu.fpr[11]); |
156 | offset("#define THREAD_FPR6 ", | 146 | OFFSET(THREAD_FPR12, task_struct, thread.fpu.fpr[12]); |
157 | struct task_struct, thread.fpu.fpr[6]); | 147 | OFFSET(THREAD_FPR13, task_struct, thread.fpu.fpr[13]); |
158 | offset("#define THREAD_FPR7 ", | 148 | OFFSET(THREAD_FPR14, task_struct, thread.fpu.fpr[14]); |
159 | struct task_struct, thread.fpu.fpr[7]); | 149 | OFFSET(THREAD_FPR15, task_struct, thread.fpu.fpr[15]); |
160 | offset("#define THREAD_FPR8 ", | 150 | OFFSET(THREAD_FPR16, task_struct, thread.fpu.fpr[16]); |
161 | struct task_struct, thread.fpu.fpr[8]); | 151 | OFFSET(THREAD_FPR17, task_struct, thread.fpu.fpr[17]); |
162 | offset("#define THREAD_FPR9 ", | 152 | OFFSET(THREAD_FPR18, task_struct, thread.fpu.fpr[18]); |
163 | struct task_struct, thread.fpu.fpr[9]); | 153 | OFFSET(THREAD_FPR19, task_struct, thread.fpu.fpr[19]); |
164 | offset("#define THREAD_FPR10 ", | 154 | OFFSET(THREAD_FPR20, task_struct, thread.fpu.fpr[20]); |
165 | struct task_struct, thread.fpu.fpr[10]); | 155 | OFFSET(THREAD_FPR21, task_struct, thread.fpu.fpr[21]); |
166 | offset("#define THREAD_FPR11 ", | 156 | OFFSET(THREAD_FPR22, task_struct, thread.fpu.fpr[22]); |
167 | struct task_struct, thread.fpu.fpr[11]); | 157 | OFFSET(THREAD_FPR23, task_struct, thread.fpu.fpr[23]); |
168 | offset("#define THREAD_FPR12 ", | 158 | OFFSET(THREAD_FPR24, task_struct, thread.fpu.fpr[24]); |
169 | struct task_struct, thread.fpu.fpr[12]); | 159 | OFFSET(THREAD_FPR25, task_struct, thread.fpu.fpr[25]); |
170 | offset("#define THREAD_FPR13 ", | 160 | OFFSET(THREAD_FPR26, task_struct, thread.fpu.fpr[26]); |
171 | struct task_struct, thread.fpu.fpr[13]); | 161 | OFFSET(THREAD_FPR27, task_struct, thread.fpu.fpr[27]); |
172 | offset("#define THREAD_FPR14 ", | 162 | OFFSET(THREAD_FPR28, task_struct, thread.fpu.fpr[28]); |
173 | struct task_struct, thread.fpu.fpr[14]); | 163 | OFFSET(THREAD_FPR29, task_struct, thread.fpu.fpr[29]); |
174 | offset("#define THREAD_FPR15 ", | 164 | OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]); |
175 | struct task_struct, thread.fpu.fpr[15]); | 165 | OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]); |
176 | offset("#define THREAD_FPR16 ", | ||
177 | struct task_struct, thread.fpu.fpr[16]); | ||
178 | offset("#define THREAD_FPR17 ", | ||
179 | struct task_struct, thread.fpu.fpr[17]); | ||
180 | offset("#define THREAD_FPR18 ", | ||
181 | struct task_struct, thread.fpu.fpr[18]); | ||
182 | offset("#define THREAD_FPR19 ", | ||
183 | struct task_struct, thread.fpu.fpr[19]); | ||
184 | offset("#define THREAD_FPR20 ", | ||
185 | struct task_struct, thread.fpu.fpr[20]); | ||
186 | offset("#define THREAD_FPR21 ", | ||
187 | struct task_struct, thread.fpu.fpr[21]); | ||
188 | offset("#define THREAD_FPR22 ", | ||
189 | struct task_struct, thread.fpu.fpr[22]); | ||
190 | offset("#define THREAD_FPR23 ", | ||
191 | struct task_struct, thread.fpu.fpr[23]); | ||
192 | offset("#define THREAD_FPR24 ", | ||
193 | struct task_struct, thread.fpu.fpr[24]); | ||
194 | offset("#define THREAD_FPR25 ", | ||
195 | struct task_struct, thread.fpu.fpr[25]); | ||
196 | offset("#define THREAD_FPR26 ", | ||
197 | struct task_struct, thread.fpu.fpr[26]); | ||
198 | offset("#define THREAD_FPR27 ", | ||
199 | struct task_struct, thread.fpu.fpr[27]); | ||
200 | offset("#define THREAD_FPR28 ", | ||
201 | struct task_struct, thread.fpu.fpr[28]); | ||
202 | offset("#define THREAD_FPR29 ", | ||
203 | struct task_struct, thread.fpu.fpr[29]); | ||
204 | offset("#define THREAD_FPR30 ", | ||
205 | struct task_struct, thread.fpu.fpr[30]); | ||
206 | offset("#define THREAD_FPR31 ", | ||
207 | struct task_struct, thread.fpu.fpr[31]); | ||
208 | 166 | ||
209 | offset("#define THREAD_FCR31 ", | 167 | OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31); |
210 | struct task_struct, thread.fpu.fcr31); | 168 | BLANK(); |
211 | linefeed; | ||
212 | } | 169 | } |
213 | 170 | ||
214 | void output_mm_defines(void) | 171 | void output_mm_defines(void) |
215 | { | 172 | { |
216 | text("/* Size of struct page */"); | 173 | COMMENT("Size of struct page"); |
217 | size("#define STRUCT_PAGE_SIZE ", struct page); | 174 | DEFINE(STRUCT_PAGE_SIZE, sizeof(struct page)); |
218 | linefeed; | 175 | BLANK(); |
219 | text("/* Linux mm_struct offsets. */"); | 176 | COMMENT("Linux mm_struct offsets."); |
220 | offset("#define MM_USERS ", struct mm_struct, mm_users); | 177 | OFFSET(MM_USERS, mm_struct, mm_users); |
221 | offset("#define MM_PGD ", struct mm_struct, pgd); | 178 | OFFSET(MM_PGD, mm_struct, pgd); |
222 | offset("#define MM_CONTEXT ", struct mm_struct, context); | 179 | OFFSET(MM_CONTEXT, mm_struct, context); |
223 | linefeed; | 180 | BLANK(); |
224 | constant("#define _PAGE_SIZE ", PAGE_SIZE); | 181 | DEFINE(_PAGE_SIZE, PAGE_SIZE); |
225 | constant("#define _PAGE_SHIFT ", PAGE_SHIFT); | 182 | DEFINE(_PAGE_SHIFT, PAGE_SHIFT); |
226 | linefeed; | 183 | BLANK(); |
227 | constant("#define _PGD_T_SIZE ", sizeof(pgd_t)); | 184 | DEFINE(_PGD_T_SIZE, sizeof(pgd_t)); |
228 | constant("#define _PMD_T_SIZE ", sizeof(pmd_t)); | 185 | DEFINE(_PMD_T_SIZE, sizeof(pmd_t)); |
229 | constant("#define _PTE_T_SIZE ", sizeof(pte_t)); | 186 | DEFINE(_PTE_T_SIZE, sizeof(pte_t)); |
230 | linefeed; | 187 | BLANK(); |
231 | constant("#define _PGD_T_LOG2 ", PGD_T_LOG2); | 188 | DEFINE(_PGD_T_LOG2, PGD_T_LOG2); |
232 | constant("#define _PMD_T_LOG2 ", PMD_T_LOG2); | 189 | DEFINE(_PMD_T_LOG2, PMD_T_LOG2); |
233 | constant("#define _PTE_T_LOG2 ", PTE_T_LOG2); | 190 | DEFINE(_PTE_T_LOG2, PTE_T_LOG2); |
234 | linefeed; | 191 | BLANK(); |
235 | constant("#define _PGD_ORDER ", PGD_ORDER); | 192 | DEFINE(_PGD_ORDER, PGD_ORDER); |
236 | constant("#define _PMD_ORDER ", PMD_ORDER); | 193 | DEFINE(_PMD_ORDER, PMD_ORDER); |
237 | constant("#define _PTE_ORDER ", PTE_ORDER); | 194 | DEFINE(_PTE_ORDER, PTE_ORDER); |
238 | linefeed; | 195 | BLANK(); |
239 | constant("#define _PMD_SHIFT ", PMD_SHIFT); | 196 | DEFINE(_PMD_SHIFT, PMD_SHIFT); |
240 | constant("#define _PGDIR_SHIFT ", PGDIR_SHIFT); | 197 | DEFINE(_PGDIR_SHIFT, PGDIR_SHIFT); |
241 | linefeed; | 198 | BLANK(); |
242 | constant("#define _PTRS_PER_PGD ", PTRS_PER_PGD); | 199 | DEFINE(_PTRS_PER_PGD, PTRS_PER_PGD); |
243 | constant("#define _PTRS_PER_PMD ", PTRS_PER_PMD); | 200 | DEFINE(_PTRS_PER_PMD, PTRS_PER_PMD); |
244 | constant("#define _PTRS_PER_PTE ", PTRS_PER_PTE); | 201 | DEFINE(_PTRS_PER_PTE, PTRS_PER_PTE); |
245 | linefeed; | 202 | BLANK(); |
246 | } | 203 | } |
247 | 204 | ||
248 | #ifdef CONFIG_32BIT | 205 | #ifdef CONFIG_32BIT |
249 | void output_sc_defines(void) | 206 | void output_sc_defines(void) |
250 | { | 207 | { |
251 | text("/* Linux sigcontext offsets. */"); | 208 | COMMENT("Linux sigcontext offsets."); |
252 | offset("#define SC_REGS ", struct sigcontext, sc_regs); | 209 | OFFSET(SC_REGS, sigcontext, sc_regs); |
253 | offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); | 210 | OFFSET(SC_FPREGS, sigcontext, sc_fpregs); |
254 | offset("#define SC_ACX ", struct sigcontext, sc_acx); | 211 | OFFSET(SC_ACX, sigcontext, sc_acx); |
255 | offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); | 212 | OFFSET(SC_MDHI, sigcontext, sc_mdhi); |
256 | offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); | 213 | OFFSET(SC_MDLO, sigcontext, sc_mdlo); |
257 | offset("#define SC_PC ", struct sigcontext, sc_pc); | 214 | OFFSET(SC_PC, sigcontext, sc_pc); |
258 | offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); | 215 | OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr); |
259 | offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); | 216 | OFFSET(SC_FPC_EIR, sigcontext, sc_fpc_eir); |
260 | offset("#define SC_HI1 ", struct sigcontext, sc_hi1); | 217 | OFFSET(SC_HI1, sigcontext, sc_hi1); |
261 | offset("#define SC_LO1 ", struct sigcontext, sc_lo1); | 218 | OFFSET(SC_LO1, sigcontext, sc_lo1); |
262 | offset("#define SC_HI2 ", struct sigcontext, sc_hi2); | 219 | OFFSET(SC_HI2, sigcontext, sc_hi2); |
263 | offset("#define SC_LO2 ", struct sigcontext, sc_lo2); | 220 | OFFSET(SC_LO2, sigcontext, sc_lo2); |
264 | offset("#define SC_HI3 ", struct sigcontext, sc_hi3); | 221 | OFFSET(SC_HI3, sigcontext, sc_hi3); |
265 | offset("#define SC_LO3 ", struct sigcontext, sc_lo3); | 222 | OFFSET(SC_LO3, sigcontext, sc_lo3); |
266 | linefeed; | 223 | BLANK(); |
267 | } | 224 | } |
268 | #endif | 225 | #endif |
269 | 226 | ||
270 | #ifdef CONFIG_64BIT | 227 | #ifdef CONFIG_64BIT |
271 | void output_sc_defines(void) | 228 | void output_sc_defines(void) |
272 | { | 229 | { |
273 | text("/* Linux sigcontext offsets. */"); | 230 | COMMENT("Linux sigcontext offsets."); |
274 | offset("#define SC_REGS ", struct sigcontext, sc_regs); | 231 | OFFSET(SC_REGS, sigcontext, sc_regs); |
275 | offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); | 232 | OFFSET(SC_FPREGS, sigcontext, sc_fpregs); |
276 | offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); | 233 | OFFSET(SC_MDHI, sigcontext, sc_mdhi); |
277 | offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); | 234 | OFFSET(SC_MDLO, sigcontext, sc_mdlo); |
278 | offset("#define SC_PC ", struct sigcontext, sc_pc); | 235 | OFFSET(SC_PC, sigcontext, sc_pc); |
279 | offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); | 236 | OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr); |
280 | linefeed; | 237 | BLANK(); |
281 | } | 238 | } |
282 | #endif | 239 | #endif |
283 | 240 | ||
284 | #ifdef CONFIG_MIPS32_COMPAT | 241 | #ifdef CONFIG_MIPS32_COMPAT |
285 | void output_sc32_defines(void) | 242 | void output_sc32_defines(void) |
286 | { | 243 | { |
287 | text("/* Linux 32-bit sigcontext offsets. */"); | 244 | COMMENT("Linux 32-bit sigcontext offsets."); |
288 | offset("#define SC32_FPREGS ", struct sigcontext32, sc_fpregs); | 245 | OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs); |
289 | offset("#define SC32_FPC_CSR ", struct sigcontext32, sc_fpc_csr); | 246 | OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr); |
290 | offset("#define SC32_FPC_EIR ", struct sigcontext32, sc_fpc_eir); | 247 | OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir); |
291 | linefeed; | 248 | BLANK(); |
292 | } | 249 | } |
293 | #endif | 250 | #endif |
294 | 251 | ||
295 | void output_signal_defined(void) | 252 | void output_signal_defined(void) |
296 | { | 253 | { |
297 | text("/* Linux signal numbers. */"); | 254 | COMMENT("Linux signal numbers."); |
298 | constant("#define _SIGHUP ", SIGHUP); | 255 | DEFINE(_SIGHUP, SIGHUP); |
299 | constant("#define _SIGINT ", SIGINT); | 256 | DEFINE(_SIGINT, SIGINT); |
300 | constant("#define _SIGQUIT ", SIGQUIT); | 257 | DEFINE(_SIGQUIT, SIGQUIT); |
301 | constant("#define _SIGILL ", SIGILL); | 258 | DEFINE(_SIGILL, SIGILL); |
302 | constant("#define _SIGTRAP ", SIGTRAP); | 259 | DEFINE(_SIGTRAP, SIGTRAP); |
303 | constant("#define _SIGIOT ", SIGIOT); | 260 | DEFINE(_SIGIOT, SIGIOT); |
304 | constant("#define _SIGABRT ", SIGABRT); | 261 | DEFINE(_SIGABRT, SIGABRT); |
305 | constant("#define _SIGEMT ", SIGEMT); | 262 | DEFINE(_SIGEMT, SIGEMT); |
306 | constant("#define _SIGFPE ", SIGFPE); | 263 | DEFINE(_SIGFPE, SIGFPE); |
307 | constant("#define _SIGKILL ", SIGKILL); | 264 | DEFINE(_SIGKILL, SIGKILL); |
308 | constant("#define _SIGBUS ", SIGBUS); | 265 | DEFINE(_SIGBUS, SIGBUS); |
309 | constant("#define _SIGSEGV ", SIGSEGV); | 266 | DEFINE(_SIGSEGV, SIGSEGV); |
310 | constant("#define _SIGSYS ", SIGSYS); | 267 | DEFINE(_SIGSYS, SIGSYS); |
311 | constant("#define _SIGPIPE ", SIGPIPE); | 268 | DEFINE(_SIGPIPE, SIGPIPE); |
312 | constant("#define _SIGALRM ", SIGALRM); | 269 | DEFINE(_SIGALRM, SIGALRM); |
313 | constant("#define _SIGTERM ", SIGTERM); | 270 | DEFINE(_SIGTERM, SIGTERM); |
314 | constant("#define _SIGUSR1 ", SIGUSR1); | 271 | DEFINE(_SIGUSR1, SIGUSR1); |
315 | constant("#define _SIGUSR2 ", SIGUSR2); | 272 | DEFINE(_SIGUSR2, SIGUSR2); |
316 | constant("#define _SIGCHLD ", SIGCHLD); | 273 | DEFINE(_SIGCHLD, SIGCHLD); |
317 | constant("#define _SIGPWR ", SIGPWR); | 274 | DEFINE(_SIGPWR, SIGPWR); |
318 | constant("#define _SIGWINCH ", SIGWINCH); | 275 | DEFINE(_SIGWINCH, SIGWINCH); |
319 | constant("#define _SIGURG ", SIGURG); | 276 | DEFINE(_SIGURG, SIGURG); |
320 | constant("#define _SIGIO ", SIGIO); | 277 | DEFINE(_SIGIO, SIGIO); |
321 | constant("#define _SIGSTOP ", SIGSTOP); | 278 | DEFINE(_SIGSTOP, SIGSTOP); |
322 | constant("#define _SIGTSTP ", SIGTSTP); | 279 | DEFINE(_SIGTSTP, SIGTSTP); |
323 | constant("#define _SIGCONT ", SIGCONT); | 280 | DEFINE(_SIGCONT, SIGCONT); |
324 | constant("#define _SIGTTIN ", SIGTTIN); | 281 | DEFINE(_SIGTTIN, SIGTTIN); |
325 | constant("#define _SIGTTOU ", SIGTTOU); | 282 | DEFINE(_SIGTTOU, SIGTTOU); |
326 | constant("#define _SIGVTALRM ", SIGVTALRM); | 283 | DEFINE(_SIGVTALRM, SIGVTALRM); |
327 | constant("#define _SIGPROF ", SIGPROF); | 284 | DEFINE(_SIGPROF, SIGPROF); |
328 | constant("#define _SIGXCPU ", SIGXCPU); | 285 | DEFINE(_SIGXCPU, SIGXCPU); |
329 | constant("#define _SIGXFSZ ", SIGXFSZ); | 286 | DEFINE(_SIGXFSZ, SIGXFSZ); |
330 | linefeed; | 287 | BLANK(); |
331 | } | 288 | } |
332 | 289 | ||
333 | void output_irq_cpustat_t_defines(void) | 290 | void output_irq_cpustat_t_defines(void) |
334 | { | 291 | { |
335 | text("/* Linux irq_cpustat_t offsets. */"); | 292 | COMMENT("Linux irq_cpustat_t offsets."); |
336 | offset("#define IC_SOFTIRQ_PENDING ", irq_cpustat_t, __softirq_pending); | 293 | DEFINE(IC_SOFTIRQ_PENDING, |
337 | size("#define IC_IRQ_CPUSTAT_T ", irq_cpustat_t); | 294 | offsetof(irq_cpustat_t, __softirq_pending)); |
338 | linefeed; | 295 | DEFINE(IC_IRQ_CPUSTAT_T, sizeof(irq_cpustat_t)); |
296 | BLANK(); | ||
339 | } | 297 | } |
diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c new file mode 100644 index 000000000000..df4acb68bfb5 --- /dev/null +++ b/arch/mips/kernel/cevt-ds1287.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * DS1287 clockevent driver | ||
3 | * | ||
4 | * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> | ||
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 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | #include <linux/clockchips.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/mc146818rtc.h> | ||
24 | |||
25 | #include <asm/time.h> | ||
26 | |||
27 | int ds1287_timer_state(void) | ||
28 | { | ||
29 | return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; | ||
30 | } | ||
31 | |||
32 | int ds1287_set_base_clock(unsigned int hz) | ||
33 | { | ||
34 | u8 rate; | ||
35 | |||
36 | switch (hz) { | ||
37 | case 128: | ||
38 | rate = 0x9; | ||
39 | break; | ||
40 | case 256: | ||
41 | rate = 0x8; | ||
42 | break; | ||
43 | case 1024: | ||
44 | rate = 0x6; | ||
45 | break; | ||
46 | default: | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
50 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A); | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int ds1287_set_next_event(unsigned long delta, | ||
56 | struct clock_event_device *evt) | ||
57 | { | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | static void ds1287_set_mode(enum clock_event_mode mode, | ||
62 | struct clock_event_device *evt) | ||
63 | { | ||
64 | u8 val; | ||
65 | |||
66 | spin_lock(&rtc_lock); | ||
67 | |||
68 | val = CMOS_READ(RTC_REG_B); | ||
69 | |||
70 | switch (mode) { | ||
71 | case CLOCK_EVT_MODE_PERIODIC: | ||
72 | val |= RTC_PIE; | ||
73 | break; | ||
74 | default: | ||
75 | val &= ~RTC_PIE; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | CMOS_WRITE(val, RTC_REG_B); | ||
80 | |||
81 | spin_unlock(&rtc_lock); | ||
82 | } | ||
83 | |||
84 | static void ds1287_event_handler(struct clock_event_device *dev) | ||
85 | { | ||
86 | } | ||
87 | |||
88 | static struct clock_event_device ds1287_clockevent = { | ||
89 | .name = "ds1287", | ||
90 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
91 | .cpumask = CPU_MASK_CPU0, | ||
92 | .set_next_event = ds1287_set_next_event, | ||
93 | .set_mode = ds1287_set_mode, | ||
94 | .event_handler = ds1287_event_handler, | ||
95 | }; | ||
96 | |||
97 | static irqreturn_t ds1287_interrupt(int irq, void *dev_id) | ||
98 | { | ||
99 | struct clock_event_device *cd = &ds1287_clockevent; | ||
100 | |||
101 | /* Ack the RTC interrupt. */ | ||
102 | CMOS_READ(RTC_REG_C); | ||
103 | |||
104 | cd->event_handler(cd); | ||
105 | |||
106 | return IRQ_HANDLED; | ||
107 | } | ||
108 | |||
109 | static struct irqaction ds1287_irqaction = { | ||
110 | .handler = ds1287_interrupt, | ||
111 | .flags = IRQF_DISABLED | IRQF_PERCPU, | ||
112 | .name = "ds1287", | ||
113 | }; | ||
114 | |||
115 | int __init ds1287_clockevent_init(int irq) | ||
116 | { | ||
117 | struct clock_event_device *cd; | ||
118 | |||
119 | cd = &ds1287_clockevent; | ||
120 | cd->rating = 100; | ||
121 | cd->irq = irq; | ||
122 | clockevent_set_clock(cd, 32768); | ||
123 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | ||
124 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | ||
125 | |||
126 | clockevents_register_device(&ds1287_clockevent); | ||
127 | |||
128 | return setup_irq(irq, &ds1287_irqaction); | ||
129 | } | ||
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index c36772631fe0..6e2f58520afb 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c | |||
@@ -25,8 +25,6 @@ | |||
25 | #include <asm/gt64120.h> | 25 | #include <asm/gt64120.h> |
26 | #include <asm/time.h> | 26 | #include <asm/time.h> |
27 | 27 | ||
28 | #include <irq.h> | ||
29 | |||
30 | static DEFINE_SPINLOCK(gt641xx_timer_lock); | 28 | static DEFINE_SPINLOCK(gt641xx_timer_lock); |
31 | static unsigned int gt641xx_base_clock; | 29 | static unsigned int gt641xx_base_clock; |
32 | 30 | ||
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 89c3304cb93c..335a6ae3d594 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -169,6 +169,7 @@ static inline void check_wait(void) | |||
169 | 169 | ||
170 | case CPU_24K: | 170 | case CPU_24K: |
171 | case CPU_34K: | 171 | case CPU_34K: |
172 | case CPU_1004K: | ||
172 | cpu_wait = r4k_wait; | 173 | cpu_wait = r4k_wait; |
173 | if (read_c0_config7() & MIPS_CONF7_WII) | 174 | if (read_c0_config7() & MIPS_CONF7_WII) |
174 | cpu_wait = r4k_wait_irqoff; | 175 | cpu_wait = r4k_wait_irqoff; |
@@ -675,6 +676,12 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c) | |||
675 | return; | 676 | return; |
676 | } | 677 | } |
677 | 678 | ||
679 | #ifdef CONFIG_CPU_MIPSR2 | ||
680 | extern void spram_config(void); | ||
681 | #else | ||
682 | static inline void spram_config(void) {} | ||
683 | #endif | ||
684 | |||
678 | static inline void cpu_probe_mips(struct cpuinfo_mips *c) | 685 | static inline void cpu_probe_mips(struct cpuinfo_mips *c) |
679 | { | 686 | { |
680 | decode_configs(c); | 687 | decode_configs(c); |
@@ -711,7 +718,12 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) | |||
711 | case PRID_IMP_74K: | 718 | case PRID_IMP_74K: |
712 | c->cputype = CPU_74K; | 719 | c->cputype = CPU_74K; |
713 | break; | 720 | break; |
721 | case PRID_IMP_1004K: | ||
722 | c->cputype = CPU_1004K; | ||
723 | break; | ||
714 | } | 724 | } |
725 | |||
726 | spram_config(); | ||
715 | } | 727 | } |
716 | 728 | ||
717 | static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) | 729 | static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) |
@@ -778,7 +790,7 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) | |||
778 | } | 790 | } |
779 | } | 791 | } |
780 | 792 | ||
781 | static inline void cpu_probe_philips(struct cpuinfo_mips *c) | 793 | static inline void cpu_probe_nxp(struct cpuinfo_mips *c) |
782 | { | 794 | { |
783 | decode_configs(c); | 795 | decode_configs(c); |
784 | switch (c->processor_id & 0xff00) { | 796 | switch (c->processor_id & 0xff00) { |
@@ -787,7 +799,7 @@ static inline void cpu_probe_philips(struct cpuinfo_mips *c) | |||
787 | c->isa_level = MIPS_CPU_ISA_M32R1; | 799 | c->isa_level = MIPS_CPU_ISA_M32R1; |
788 | break; | 800 | break; |
789 | default: | 801 | default: |
790 | panic("Unknown Philips Core!"); /* REVISIT: die? */ | 802 | panic("Unknown NXP Core!"); /* REVISIT: die? */ |
791 | break; | 803 | break; |
792 | } | 804 | } |
793 | } | 805 | } |
@@ -876,6 +888,7 @@ static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c) | |||
876 | case CPU_24K: name = "MIPS 24K"; break; | 888 | case CPU_24K: name = "MIPS 24K"; break; |
877 | case CPU_25KF: name = "MIPS 25Kf"; break; | 889 | case CPU_25KF: name = "MIPS 25Kf"; break; |
878 | case CPU_34K: name = "MIPS 34K"; break; | 890 | case CPU_34K: name = "MIPS 34K"; break; |
891 | case CPU_1004K: name = "MIPS 1004K"; break; | ||
879 | case CPU_74K: name = "MIPS 74K"; break; | 892 | case CPU_74K: name = "MIPS 74K"; break; |
880 | case CPU_VR4111: name = "NEC VR4111"; break; | 893 | case CPU_VR4111: name = "NEC VR4111"; break; |
881 | case CPU_VR4121: name = "NEC VR4121"; break; | 894 | case CPU_VR4121: name = "NEC VR4121"; break; |
@@ -925,8 +938,8 @@ __cpuinit void cpu_probe(void) | |||
925 | case PRID_COMP_SANDCRAFT: | 938 | case PRID_COMP_SANDCRAFT: |
926 | cpu_probe_sandcraft(c); | 939 | cpu_probe_sandcraft(c); |
927 | break; | 940 | break; |
928 | case PRID_COMP_PHILIPS: | 941 | case PRID_COMP_NXP: |
929 | cpu_probe_philips(c); | 942 | cpu_probe_nxp(c); |
930 | break; | 943 | break; |
931 | default: | 944 | default: |
932 | c->cputype = CPU_UNKNOWN; | 945 | c->cputype = CPU_UNKNOWN; |
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c new file mode 100644 index 000000000000..1d5f63cf8997 --- /dev/null +++ b/arch/mips/kernel/csrc-ioasic.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * DEC I/O ASIC's counter clocksource | ||
3 | * | ||
4 | * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> | ||
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 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | #include <linux/clocksource.h> | ||
21 | #include <linux/init.h> | ||
22 | |||
23 | #include <asm/ds1287.h> | ||
24 | #include <asm/time.h> | ||
25 | #include <asm/dec/ioasic.h> | ||
26 | #include <asm/dec/ioasic_addrs.h> | ||
27 | |||
28 | static cycle_t dec_ioasic_hpt_read(void) | ||
29 | { | ||
30 | return ioasic_read(IO_REG_FCTR); | ||
31 | } | ||
32 | |||
33 | static struct clocksource clocksource_dec = { | ||
34 | .name = "dec-ioasic", | ||
35 | .read = dec_ioasic_hpt_read, | ||
36 | .mask = CLOCKSOURCE_MASK(32), | ||
37 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
38 | }; | ||
39 | |||
40 | void __init dec_ioasic_clocksource_init(void) | ||
41 | { | ||
42 | unsigned int freq; | ||
43 | u32 start, end; | ||
44 | int i = HZ / 10; | ||
45 | |||
46 | |||
47 | while (!ds1287_timer_state()) | ||
48 | ; | ||
49 | |||
50 | start = dec_ioasic_hpt_read(); | ||
51 | |||
52 | while (i--) | ||
53 | while (!ds1287_timer_state()) | ||
54 | ; | ||
55 | |||
56 | end = dec_ioasic_hpt_read(); | ||
57 | |||
58 | freq = (end - start) * 10; | ||
59 | printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); | ||
60 | |||
61 | clocksource_dec.rating = 200 + freq / 10000000; | ||
62 | clocksource_set_clock(&clocksource_dec, freq); | ||
63 | |||
64 | clocksource_register(&clocksource_dec); | ||
65 | } | ||
diff --git a/arch/mips/kernel/gpio_txx9.c b/arch/mips/kernel/gpio_txx9.c new file mode 100644 index 000000000000..b1436a857998 --- /dev/null +++ b/arch/mips/kernel/gpio_txx9.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * A gpio chip driver for TXx9 SoCs | ||
3 | * | ||
4 | * Copyright (C) 2008 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <asm/txx9pio.h> | ||
17 | |||
18 | static DEFINE_SPINLOCK(txx9_gpio_lock); | ||
19 | |||
20 | static struct txx9_pio_reg __iomem *txx9_pioptr; | ||
21 | |||
22 | static int txx9_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||
23 | { | ||
24 | return __raw_readl(&txx9_pioptr->din) & (1 << offset); | ||
25 | } | ||
26 | |||
27 | static void txx9_gpio_set_raw(unsigned int offset, int value) | ||
28 | { | ||
29 | u32 val; | ||
30 | val = __raw_readl(&txx9_pioptr->dout); | ||
31 | if (value) | ||
32 | val |= 1 << offset; | ||
33 | else | ||
34 | val &= ~(1 << offset); | ||
35 | __raw_writel(val, &txx9_pioptr->dout); | ||
36 | } | ||
37 | |||
38 | static void txx9_gpio_set(struct gpio_chip *chip, unsigned int offset, | ||
39 | int value) | ||
40 | { | ||
41 | unsigned long flags; | ||
42 | spin_lock_irqsave(&txx9_gpio_lock, flags); | ||
43 | txx9_gpio_set_raw(offset, value); | ||
44 | mmiowb(); | ||
45 | spin_unlock_irqrestore(&txx9_gpio_lock, flags); | ||
46 | } | ||
47 | |||
48 | static int txx9_gpio_dir_in(struct gpio_chip *chip, unsigned int offset) | ||
49 | { | ||
50 | spin_lock_irq(&txx9_gpio_lock); | ||
51 | __raw_writel(__raw_readl(&txx9_pioptr->dir) & ~(1 << offset), | ||
52 | &txx9_pioptr->dir); | ||
53 | mmiowb(); | ||
54 | spin_unlock_irq(&txx9_gpio_lock); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int txx9_gpio_dir_out(struct gpio_chip *chip, unsigned int offset, | ||
59 | int value) | ||
60 | { | ||
61 | spin_lock_irq(&txx9_gpio_lock); | ||
62 | txx9_gpio_set_raw(offset, value); | ||
63 | __raw_writel(__raw_readl(&txx9_pioptr->dir) | (1 << offset), | ||
64 | &txx9_pioptr->dir); | ||
65 | mmiowb(); | ||
66 | spin_unlock_irq(&txx9_gpio_lock); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static struct gpio_chip txx9_gpio_chip = { | ||
71 | .get = txx9_gpio_get, | ||
72 | .set = txx9_gpio_set, | ||
73 | .direction_input = txx9_gpio_dir_in, | ||
74 | .direction_output = txx9_gpio_dir_out, | ||
75 | .label = "TXx9", | ||
76 | }; | ||
77 | |||
78 | int __init txx9_gpio_init(unsigned long baseaddr, | ||
79 | unsigned int base, unsigned int num) | ||
80 | { | ||
81 | txx9_pioptr = ioremap(baseaddr, sizeof(struct txx9_pio_reg)); | ||
82 | if (!txx9_pioptr) | ||
83 | return -ENODEV; | ||
84 | txx9_gpio_chip.base = base; | ||
85 | txx9_gpio_chip.ngpio = num; | ||
86 | return gpiochip_add(&txx9_gpio_chip); | ||
87 | } | ||
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c new file mode 100644 index 000000000000..f0a4bb19e096 --- /dev/null +++ b/arch/mips/kernel/irq-gic.c | |||
@@ -0,0 +1,295 @@ | |||
1 | #undef DEBUG | ||
2 | |||
3 | #include <linux/bitmap.h> | ||
4 | #include <linux/init.h> | ||
5 | |||
6 | #include <asm/io.h> | ||
7 | #include <asm/gic.h> | ||
8 | #include <asm/gcmpregs.h> | ||
9 | #include <asm/mips-boards/maltaint.h> | ||
10 | #include <asm/irq.h> | ||
11 | #include <linux/hardirq.h> | ||
12 | #include <asm-generic/bitops/find.h> | ||
13 | |||
14 | |||
15 | static unsigned long _gic_base; | ||
16 | static unsigned int _irqbase, _mapsize, numvpes, numintrs; | ||
17 | static struct gic_intr_map *_intrmap; | ||
18 | |||
19 | static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; | ||
20 | static struct gic_pending_regs pending_regs[NR_CPUS]; | ||
21 | static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | ||
22 | |||
23 | #define gic_wedgeb2bok 0 /* | ||
24 | * Can GIC handle b2b writes to wedge register? | ||
25 | */ | ||
26 | #if gic_wedgeb2bok == 0 | ||
27 | static DEFINE_SPINLOCK(gic_wedgeb2b_lock); | ||
28 | #endif | ||
29 | |||
30 | void gic_send_ipi(unsigned int intr) | ||
31 | { | ||
32 | #if gic_wedgeb2bok == 0 | ||
33 | unsigned long flags; | ||
34 | #endif | ||
35 | pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__, | ||
36 | read_c0_status()); | ||
37 | if (!gic_wedgeb2bok) | ||
38 | spin_lock_irqsave(&gic_wedgeb2b_lock, flags); | ||
39 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); | ||
40 | if (!gic_wedgeb2bok) { | ||
41 | (void) GIC_REG(SHARED, GIC_SH_CONFIG); | ||
42 | spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | /* This is Malta specific and needs to be exported */ | ||
47 | static void vpe_local_setup(unsigned int numvpes) | ||
48 | { | ||
49 | int i; | ||
50 | unsigned long timer_interrupt = 5, perf_interrupt = 5; | ||
51 | unsigned int vpe_ctl; | ||
52 | |||
53 | /* | ||
54 | * Setup the default performance counter timer interrupts | ||
55 | * for all VPEs | ||
56 | */ | ||
57 | for (i = 0; i < numvpes; i++) { | ||
58 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
59 | |||
60 | /* Are Interrupts locally routable? */ | ||
61 | GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); | ||
62 | if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) | ||
63 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), | ||
64 | GIC_MAP_TO_PIN_MSK | timer_interrupt); | ||
65 | |||
66 | if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) | ||
67 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), | ||
68 | GIC_MAP_TO_PIN_MSK | perf_interrupt); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | unsigned int gic_get_int(void) | ||
73 | { | ||
74 | unsigned int i; | ||
75 | unsigned long *pending, *intrmask, *pcpu_mask; | ||
76 | unsigned long *pending_abs, *intrmask_abs; | ||
77 | |||
78 | /* Get per-cpu bitmaps */ | ||
79 | pending = pending_regs[smp_processor_id()].pending; | ||
80 | intrmask = intrmask_regs[smp_processor_id()].intrmask; | ||
81 | pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; | ||
82 | |||
83 | pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, | ||
84 | GIC_SH_PEND_31_0_OFS); | ||
85 | intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, | ||
86 | GIC_SH_MASK_31_0_OFS); | ||
87 | |||
88 | for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) { | ||
89 | GICREAD(*pending_abs, pending[i]); | ||
90 | GICREAD(*intrmask_abs, intrmask[i]); | ||
91 | pending_abs++; | ||
92 | intrmask_abs++; | ||
93 | } | ||
94 | |||
95 | bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); | ||
96 | bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); | ||
97 | |||
98 | i = find_first_bit(pending, GIC_NUM_INTRS); | ||
99 | |||
100 | pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i); | ||
101 | |||
102 | return i; | ||
103 | } | ||
104 | |||
105 | static unsigned int gic_irq_startup(unsigned int irq) | ||
106 | { | ||
107 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
108 | irq -= _irqbase; | ||
109 | /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ | ||
110 | GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))), | ||
111 | 1 << (irq % 32)); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void gic_irq_ack(unsigned int irq) | ||
116 | { | ||
117 | #if gic_wedgeb2bok == 0 | ||
118 | unsigned long flags; | ||
119 | #endif | ||
120 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
121 | irq -= _irqbase; | ||
122 | GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))), | ||
123 | 1 << (irq % 32)); | ||
124 | |||
125 | if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) { | ||
126 | if (!gic_wedgeb2bok) | ||
127 | spin_lock_irqsave(&gic_wedgeb2b_lock, flags); | ||
128 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); | ||
129 | if (!gic_wedgeb2bok) { | ||
130 | (void) GIC_REG(SHARED, GIC_SH_CONFIG); | ||
131 | spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static void gic_mask_irq(unsigned int irq) | ||
137 | { | ||
138 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
139 | irq -= _irqbase; | ||
140 | /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ | ||
141 | GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))), | ||
142 | 1 << (irq % 32)); | ||
143 | } | ||
144 | |||
145 | static void gic_unmask_irq(unsigned int irq) | ||
146 | { | ||
147 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
148 | irq -= _irqbase; | ||
149 | /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */ | ||
150 | GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))), | ||
151 | 1 << (irq % 32)); | ||
152 | } | ||
153 | |||
154 | #ifdef CONFIG_SMP | ||
155 | |||
156 | static DEFINE_SPINLOCK(gic_lock); | ||
157 | |||
158 | static void gic_set_affinity(unsigned int irq, cpumask_t cpumask) | ||
159 | { | ||
160 | cpumask_t tmp = CPU_MASK_NONE; | ||
161 | unsigned long flags; | ||
162 | int i; | ||
163 | |||
164 | pr_debug(KERN_DEBUG "%s called\n", __func__); | ||
165 | irq -= _irqbase; | ||
166 | |||
167 | cpus_and(tmp, cpumask, cpu_online_map); | ||
168 | if (cpus_empty(tmp)) | ||
169 | return; | ||
170 | |||
171 | /* Assumption : cpumask refers to a single CPU */ | ||
172 | spin_lock_irqsave(&gic_lock, flags); | ||
173 | for (;;) { | ||
174 | /* Re-route this IRQ */ | ||
175 | GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp)); | ||
176 | |||
177 | /* | ||
178 | * FIXME: assumption that _intrmap is ordered and has no holes | ||
179 | */ | ||
180 | |||
181 | /* Update the intr_map */ | ||
182 | _intrmap[irq].cpunum = first_cpu(tmp); | ||
183 | |||
184 | /* Update the pcpu_masks */ | ||
185 | for (i = 0; i < NR_CPUS; i++) | ||
186 | clear_bit(irq, pcpu_masks[i].pcpu_mask); | ||
187 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); | ||
188 | |||
189 | } | ||
190 | irq_desc[irq].affinity = cpumask; | ||
191 | spin_unlock_irqrestore(&gic_lock, flags); | ||
192 | |||
193 | } | ||
194 | #endif | ||
195 | |||
196 | static struct irq_chip gic_irq_controller = { | ||
197 | .name = "MIPS GIC", | ||
198 | .startup = gic_irq_startup, | ||
199 | .ack = gic_irq_ack, | ||
200 | .mask = gic_mask_irq, | ||
201 | .mask_ack = gic_mask_irq, | ||
202 | .unmask = gic_unmask_irq, | ||
203 | .eoi = gic_unmask_irq, | ||
204 | #ifdef CONFIG_SMP | ||
205 | .set_affinity = gic_set_affinity, | ||
206 | #endif | ||
207 | }; | ||
208 | |||
209 | static void __init setup_intr(unsigned int intr, unsigned int cpu, | ||
210 | unsigned int pin, unsigned int polarity, unsigned int trigtype) | ||
211 | { | ||
212 | /* Setup Intr to Pin mapping */ | ||
213 | if (pin & GIC_MAP_TO_NMI_MSK) { | ||
214 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); | ||
215 | /* FIXME: hack to route NMI to all cpu's */ | ||
216 | for (cpu = 0; cpu < NR_CPUS; cpu += 32) { | ||
217 | GICWRITE(GIC_REG_ADDR(SHARED, | ||
218 | GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)), | ||
219 | 0xffffffff); | ||
220 | } | ||
221 | } else { | ||
222 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), | ||
223 | GIC_MAP_TO_PIN_MSK | pin); | ||
224 | /* Setup Intr to CPU mapping */ | ||
225 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); | ||
226 | } | ||
227 | |||
228 | /* Setup Intr Polarity */ | ||
229 | GIC_SET_POLARITY(intr, polarity); | ||
230 | |||
231 | /* Setup Intr Trigger Type */ | ||
232 | GIC_SET_TRIGGER(intr, trigtype); | ||
233 | |||
234 | /* Init Intr Masks */ | ||
235 | GIC_SET_INTR_MASK(intr, 0); | ||
236 | } | ||
237 | |||
238 | static void __init gic_basic_init(void) | ||
239 | { | ||
240 | unsigned int i, cpu; | ||
241 | |||
242 | /* Setup defaults */ | ||
243 | for (i = 0; i < GIC_NUM_INTRS; i++) { | ||
244 | GIC_SET_POLARITY(i, GIC_POL_POS); | ||
245 | GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); | ||
246 | GIC_SET_INTR_MASK(i, 0); | ||
247 | } | ||
248 | |||
249 | /* Setup specifics */ | ||
250 | for (i = 0; i < _mapsize; i++) { | ||
251 | cpu = _intrmap[i].cpunum; | ||
252 | if (cpu == X) | ||
253 | continue; | ||
254 | |||
255 | setup_intr(_intrmap[i].intrnum, | ||
256 | _intrmap[i].cpunum, | ||
257 | _intrmap[i].pin, | ||
258 | _intrmap[i].polarity, | ||
259 | _intrmap[i].trigtype); | ||
260 | /* Initialise per-cpu Interrupt software masks */ | ||
261 | if (_intrmap[i].ipiflag) | ||
262 | set_bit(_intrmap[i].intrnum, pcpu_masks[cpu].pcpu_mask); | ||
263 | } | ||
264 | |||
265 | vpe_local_setup(numvpes); | ||
266 | |||
267 | for (i = _irqbase; i < (_irqbase + numintrs); i++) | ||
268 | set_irq_chip(i, &gic_irq_controller); | ||
269 | } | ||
270 | |||
271 | void __init gic_init(unsigned long gic_base_addr, | ||
272 | unsigned long gic_addrspace_size, | ||
273 | struct gic_intr_map *intr_map, unsigned int intr_map_size, | ||
274 | unsigned int irqbase) | ||
275 | { | ||
276 | unsigned int gicconfig; | ||
277 | |||
278 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, | ||
279 | gic_addrspace_size); | ||
280 | _irqbase = irqbase; | ||
281 | _intrmap = intr_map; | ||
282 | _mapsize = intr_map_size; | ||
283 | |||
284 | GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); | ||
285 | numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> | ||
286 | GIC_SH_CONFIG_NUMINTRS_SHF; | ||
287 | numintrs = ((numintrs + 1) * 8); | ||
288 | |||
289 | numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> | ||
290 | GIC_SH_CONFIG_NUMVPES_SHF; | ||
291 | |||
292 | pr_debug("%s called\n", __func__); | ||
293 | |||
294 | gic_basic_init(); | ||
295 | } | ||
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 4edc7e451d91..963c16d266ab 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
19 | #include <asm/msc01_ic.h> | 19 | #include <asm/msc01_ic.h> |
20 | #include <asm/traps.h> | ||
20 | 21 | ||
21 | static unsigned long _icctrl_msc; | 22 | static unsigned long _icctrl_msc; |
22 | #define MSC01_IC_REG_BASE _icctrl_msc | 23 | #define MSC01_IC_REG_BASE _icctrl_msc |
@@ -98,14 +99,13 @@ void ll_msc_irq(void) | |||
98 | } | 99 | } |
99 | } | 100 | } |
100 | 101 | ||
101 | void | 102 | static void msc_bind_eic_interrupt(int irq, int set) |
102 | msc_bind_eic_interrupt(unsigned int irq, unsigned int set) | ||
103 | { | 103 | { |
104 | MSCIC_WRITE(MSC01_IC_RAMW, | 104 | MSCIC_WRITE(MSC01_IC_RAMW, |
105 | (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); | 105 | (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); |
106 | } | 106 | } |
107 | 107 | ||
108 | struct irq_chip msc_levelirq_type = { | 108 | static struct irq_chip msc_levelirq_type = { |
109 | .name = "SOC-it-Level", | 109 | .name = "SOC-it-Level", |
110 | .ack = level_mask_and_ack_msc_irq, | 110 | .ack = level_mask_and_ack_msc_irq, |
111 | .mask = mask_msc_irq, | 111 | .mask = mask_msc_irq, |
@@ -115,7 +115,7 @@ struct irq_chip msc_levelirq_type = { | |||
115 | .end = end_msc_irq, | 115 | .end = end_msc_irq, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | struct irq_chip msc_edgeirq_type = { | 118 | static struct irq_chip msc_edgeirq_type = { |
119 | .name = "SOC-it-Edge", | 119 | .name = "SOC-it-Edge", |
120 | .ack = edge_mask_and_ack_msc_irq, | 120 | .ack = edge_mask_and_ack_msc_irq, |
121 | .mask = mask_msc_irq, | 121 | .mask = mask_msc_irq, |
@@ -128,8 +128,6 @@ struct irq_chip msc_edgeirq_type = { | |||
128 | 128 | ||
129 | void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) | 129 | void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) |
130 | { | 130 | { |
131 | extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); | ||
132 | |||
133 | _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); | 131 | _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); |
134 | 132 | ||
135 | /* Reset interrupt controller - initialises all registers to 0 */ | 133 | /* Reset interrupt controller - initialises all registers to 0 */ |
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index c0faabd52010..6c8e8c4246f7 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h | |||
@@ -14,7 +14,7 @@ | |||
14 | /* #define DEBUG_SIG */ | 14 | /* #define DEBUG_SIG */ |
15 | 15 | ||
16 | #ifdef DEBUG_SIG | 16 | #ifdef DEBUG_SIG |
17 | # define DEBUGP(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) | 17 | # define DEBUGP(fmt, args...) printk("%s: " fmt, __func__, ##args) |
18 | #else | 18 | #else |
19 | # define DEBUGP(fmt, args...) | 19 | # define DEBUGP(fmt, args...) |
20 | #endif | 20 | #endif |
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c new file mode 100644 index 000000000000..ca476c4f62a5 --- /dev/null +++ b/arch/mips/kernel/smp-cmp.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * This program is free software; you can distribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License (Version 2) as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
7 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
8 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
9 | * for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License along | ||
12 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
13 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
14 | * | ||
15 | * Copyright (C) 2007 MIPS Technologies, Inc. | ||
16 | * Chris Dearman (chris@mips.com) | ||
17 | */ | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/cpumask.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/compiler.h> | ||
26 | |||
27 | #include <asm/atomic.h> | ||
28 | #include <asm/cacheflush.h> | ||
29 | #include <asm/cpu.h> | ||
30 | #include <asm/processor.h> | ||
31 | #include <asm/system.h> | ||
32 | #include <asm/hardirq.h> | ||
33 | #include <asm/mmu_context.h> | ||
34 | #include <asm/smp.h> | ||
35 | #include <asm/time.h> | ||
36 | #include <asm/mipsregs.h> | ||
37 | #include <asm/mipsmtregs.h> | ||
38 | #include <asm/mips_mt.h> | ||
39 | |||
40 | /* | ||
41 | * Crude manipulation of the CPU masks to control which | ||
42 | * which CPU's are brought online during initialisation | ||
43 | * | ||
44 | * Beware... this needs to be called after CPU discovery | ||
45 | * but before CPU bringup | ||
46 | */ | ||
47 | static int __init allowcpus(char *str) | ||
48 | { | ||
49 | cpumask_t cpu_allow_map; | ||
50 | char buf[256]; | ||
51 | int len; | ||
52 | |||
53 | cpus_clear(cpu_allow_map); | ||
54 | if (cpulist_parse(str, cpu_allow_map) == 0) { | ||
55 | cpu_set(0, cpu_allow_map); | ||
56 | cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map); | ||
57 | len = cpulist_scnprintf(buf, sizeof(buf)-1, cpu_possible_map); | ||
58 | buf[len] = '\0'; | ||
59 | pr_debug("Allowable CPUs: %s\n", buf); | ||
60 | return 1; | ||
61 | } else | ||
62 | return 0; | ||
63 | } | ||
64 | __setup("allowcpus=", allowcpus); | ||
65 | |||
66 | static void ipi_call_function(unsigned int cpu) | ||
67 | { | ||
68 | unsigned int action = 0; | ||
69 | |||
70 | pr_debug("CPU%d: %s cpu %d status %08x\n", | ||
71 | smp_processor_id(), __func__, cpu, read_c0_status()); | ||
72 | |||
73 | switch (cpu) { | ||
74 | case 0: | ||
75 | action = GIC_IPI_EXT_INTR_CALLFNC_VPE0; | ||
76 | break; | ||
77 | case 1: | ||
78 | action = GIC_IPI_EXT_INTR_CALLFNC_VPE1; | ||
79 | break; | ||
80 | case 2: | ||
81 | action = GIC_IPI_EXT_INTR_CALLFNC_VPE2; | ||
82 | break; | ||
83 | case 3: | ||
84 | action = GIC_IPI_EXT_INTR_CALLFNC_VPE3; | ||
85 | break; | ||
86 | } | ||
87 | gic_send_ipi(action); | ||
88 | } | ||
89 | |||
90 | |||
91 | static void ipi_resched(unsigned int cpu) | ||
92 | { | ||
93 | unsigned int action = 0; | ||
94 | |||
95 | pr_debug("CPU%d: %s cpu %d status %08x\n", | ||
96 | smp_processor_id(), __func__, cpu, read_c0_status()); | ||
97 | |||
98 | switch (cpu) { | ||
99 | case 0: | ||
100 | action = GIC_IPI_EXT_INTR_RESCHED_VPE0; | ||
101 | break; | ||
102 | case 1: | ||
103 | action = GIC_IPI_EXT_INTR_RESCHED_VPE1; | ||
104 | break; | ||
105 | case 2: | ||
106 | action = GIC_IPI_EXT_INTR_RESCHED_VPE2; | ||
107 | break; | ||
108 | case 3: | ||
109 | action = GIC_IPI_EXT_INTR_RESCHED_VPE3; | ||
110 | break; | ||
111 | } | ||
112 | gic_send_ipi(action); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * FIXME: This isn't restricted to CMP | ||
117 | * The SMVP kernel could use GIC interrupts if available | ||
118 | */ | ||
119 | void cmp_send_ipi_single(int cpu, unsigned int action) | ||
120 | { | ||
121 | unsigned long flags; | ||
122 | |||
123 | local_irq_save(flags); | ||
124 | |||
125 | switch (action) { | ||
126 | case SMP_CALL_FUNCTION: | ||
127 | ipi_call_function(cpu); | ||
128 | break; | ||
129 | |||
130 | case SMP_RESCHEDULE_YOURSELF: | ||
131 | ipi_resched(cpu); | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | local_irq_restore(flags); | ||
136 | } | ||
137 | |||
138 | static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action) | ||
139 | { | ||
140 | unsigned int i; | ||
141 | |||
142 | for_each_cpu_mask(i, mask) | ||
143 | cmp_send_ipi_single(i, action); | ||
144 | } | ||
145 | |||
146 | static void cmp_init_secondary(void) | ||
147 | { | ||
148 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
149 | |||
150 | /* Assume GIC is present */ | ||
151 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | | ||
152 | STATUSF_IP7); | ||
153 | |||
154 | /* Enable per-cpu interrupts: platform specific */ | ||
155 | |||
156 | c->core = (read_c0_ebase() >> 1) & 0xff; | ||
157 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) | ||
158 | c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE; | ||
159 | #endif | ||
160 | #ifdef CONFIG_MIPS_MT_SMTC | ||
161 | c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC; | ||
162 | #endif | ||
163 | } | ||
164 | |||
165 | static void cmp_smp_finish(void) | ||
166 | { | ||
167 | pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); | ||
168 | |||
169 | /* CDFIXME: remove this? */ | ||
170 | write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); | ||
171 | |||
172 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
173 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ | ||
174 | if (cpu_has_fpu) | ||
175 | cpu_set(smp_processor_id(), mt_fpu_cpumask); | ||
176 | #endif /* CONFIG_MIPS_MT_FPAFF */ | ||
177 | |||
178 | local_irq_enable(); | ||
179 | } | ||
180 | |||
181 | static void cmp_cpus_done(void) | ||
182 | { | ||
183 | pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Setup the PC, SP, and GP of a secondary processor and start it running | ||
188 | * smp_bootstrap is the place to resume from | ||
189 | * __KSTK_TOS(idle) is apparently the stack pointer | ||
190 | * (unsigned long)idle->thread_info the gp | ||
191 | */ | ||
192 | static void cmp_boot_secondary(int cpu, struct task_struct *idle) | ||
193 | { | ||
194 | struct thread_info *gp = task_thread_info(idle); | ||
195 | unsigned long sp = __KSTK_TOS(idle); | ||
196 | unsigned long pc = (unsigned long)&smp_bootstrap; | ||
197 | unsigned long a0 = 0; | ||
198 | |||
199 | pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), | ||
200 | __func__, cpu); | ||
201 | |||
202 | #if 0 | ||
203 | /* Needed? */ | ||
204 | flush_icache_range((unsigned long)gp, | ||
205 | (unsigned long)(gp + sizeof(struct thread_info))); | ||
206 | #endif | ||
207 | |||
208 | amon_cpu_start(cpu, pc, sp, gp, a0); | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Common setup before any secondaries are started | ||
213 | */ | ||
214 | void __init cmp_smp_setup(void) | ||
215 | { | ||
216 | int i; | ||
217 | int ncpu = 0; | ||
218 | |||
219 | pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); | ||
220 | |||
221 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
222 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ | ||
223 | if (cpu_has_fpu) | ||
224 | cpu_set(0, mt_fpu_cpumask); | ||
225 | #endif /* CONFIG_MIPS_MT_FPAFF */ | ||
226 | |||
227 | for (i = 1; i < NR_CPUS; i++) { | ||
228 | if (amon_cpu_avail(i)) { | ||
229 | cpu_set(i, phys_cpu_present_map); | ||
230 | __cpu_number_map[i] = ++ncpu; | ||
231 | __cpu_logical_map[ncpu] = i; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (cpu_has_mipsmt) { | ||
236 | unsigned int nvpe, mvpconf0 = read_c0_mvpconf0(); | ||
237 | |||
238 | nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; | ||
239 | smp_num_siblings = nvpe; | ||
240 | } | ||
241 | pr_info("Detected %i available secondary CPU(s)\n", ncpu); | ||
242 | } | ||
243 | |||
244 | void __init cmp_prepare_cpus(unsigned int max_cpus) | ||
245 | { | ||
246 | pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", | ||
247 | smp_processor_id(), __func__, max_cpus); | ||
248 | |||
249 | /* | ||
250 | * FIXME: some of these options are per-system, some per-core and | ||
251 | * some per-cpu | ||
252 | */ | ||
253 | mips_mt_set_cpuoptions(); | ||
254 | } | ||
255 | |||
256 | struct plat_smp_ops cmp_smp_ops = { | ||
257 | .send_ipi_single = cmp_send_ipi_single, | ||
258 | .send_ipi_mask = cmp_send_ipi_mask, | ||
259 | .init_secondary = cmp_init_secondary, | ||
260 | .smp_finish = cmp_smp_finish, | ||
261 | .cpus_done = cmp_cpus_done, | ||
262 | .boot_secondary = cmp_boot_secondary, | ||
263 | .smp_setup = cmp_smp_setup, | ||
264 | .prepare_cpus = cmp_prepare_cpus, | ||
265 | }; | ||
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 89e6f6aa5166..87a1816c1f45 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
@@ -36,110 +36,7 @@ | |||
36 | #include <asm/mipsmtregs.h> | 36 | #include <asm/mipsmtregs.h> |
37 | #include <asm/mips_mt.h> | 37 | #include <asm/mips_mt.h> |
38 | 38 | ||
39 | #define MIPS_CPU_IPI_RESCHED_IRQ 0 | 39 | static void __init smvp_copy_vpe_config(void) |
40 | #define MIPS_CPU_IPI_CALL_IRQ 1 | ||
41 | |||
42 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | ||
43 | |||
44 | #if 0 | ||
45 | static void dump_mtregisters(int vpe, int tc) | ||
46 | { | ||
47 | printk("vpe %d tc %d\n", vpe, tc); | ||
48 | |||
49 | settc(tc); | ||
50 | |||
51 | printk(" c0 status 0x%lx\n", read_vpe_c0_status()); | ||
52 | printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol()); | ||
53 | printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0()); | ||
54 | printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus()); | ||
55 | printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart()); | ||
56 | printk(" tcbind 0x%lx\n", read_tc_c0_tcbind()); | ||
57 | printk(" tchalt 0x%lx\n", read_tc_c0_tchalt()); | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | void __init sanitize_tlb_entries(void) | ||
62 | { | ||
63 | int i, tlbsiz; | ||
64 | unsigned long mvpconf0, ncpu; | ||
65 | |||
66 | if (!cpu_has_mipsmt) | ||
67 | return; | ||
68 | |||
69 | /* Enable VPC */ | ||
70 | set_c0_mvpcontrol(MVPCONTROL_VPC); | ||
71 | |||
72 | back_to_back_c0_hazard(); | ||
73 | |||
74 | /* Disable TLB sharing */ | ||
75 | clear_c0_mvpcontrol(MVPCONTROL_STLB); | ||
76 | |||
77 | mvpconf0 = read_c0_mvpconf0(); | ||
78 | |||
79 | printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0, | ||
80 | (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT, | ||
81 | (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT); | ||
82 | |||
83 | tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT; | ||
84 | ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; | ||
85 | |||
86 | printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu); | ||
87 | |||
88 | if (tlbsiz > 0) { | ||
89 | /* share them out across the vpe's */ | ||
90 | tlbsiz /= ncpu; | ||
91 | |||
92 | printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz); | ||
93 | |||
94 | for (i = 0; i < ncpu; i++) { | ||
95 | settc(i); | ||
96 | |||
97 | if (i == 0) | ||
98 | write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25)); | ||
99 | else | ||
100 | write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) | | ||
101 | (tlbsiz << 25)); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | ||
106 | } | ||
107 | |||
108 | static void ipi_resched_dispatch(void) | ||
109 | { | ||
110 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | ||
111 | } | ||
112 | |||
113 | static void ipi_call_dispatch(void) | ||
114 | { | ||
115 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | ||
116 | } | ||
117 | |||
118 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
119 | { | ||
120 | return IRQ_HANDLED; | ||
121 | } | ||
122 | |||
123 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
124 | { | ||
125 | smp_call_function_interrupt(); | ||
126 | |||
127 | return IRQ_HANDLED; | ||
128 | } | ||
129 | |||
130 | static struct irqaction irq_resched = { | ||
131 | .handler = ipi_resched_interrupt, | ||
132 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
133 | .name = "IPI_resched" | ||
134 | }; | ||
135 | |||
136 | static struct irqaction irq_call = { | ||
137 | .handler = ipi_call_interrupt, | ||
138 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
139 | .name = "IPI_call" | ||
140 | }; | ||
141 | |||
142 | static void __init smp_copy_vpe_config(void) | ||
143 | { | 40 | { |
144 | write_vpe_c0_status( | 41 | write_vpe_c0_status( |
145 | (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); | 42 | (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); |
@@ -156,7 +53,7 @@ static void __init smp_copy_vpe_config(void) | |||
156 | write_vpe_c0_count(read_c0_count()); | 53 | write_vpe_c0_count(read_c0_count()); |
157 | } | 54 | } |
158 | 55 | ||
159 | static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, | 56 | static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0, |
160 | unsigned int ncpu) | 57 | unsigned int ncpu) |
161 | { | 58 | { |
162 | if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) | 59 | if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) |
@@ -182,12 +79,12 @@ static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, | |||
182 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); | 79 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); |
183 | 80 | ||
184 | if (tc != 0) | 81 | if (tc != 0) |
185 | smp_copy_vpe_config(); | 82 | smvp_copy_vpe_config(); |
186 | 83 | ||
187 | return ncpu; | 84 | return ncpu; |
188 | } | 85 | } |
189 | 86 | ||
190 | static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) | 87 | static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0) |
191 | { | 88 | { |
192 | unsigned long tmp; | 89 | unsigned long tmp; |
193 | 90 | ||
@@ -254,15 +151,20 @@ static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action) | |||
254 | 151 | ||
255 | static void __cpuinit vsmp_init_secondary(void) | 152 | static void __cpuinit vsmp_init_secondary(void) |
256 | { | 153 | { |
257 | /* Enable per-cpu interrupts */ | 154 | extern int gic_present; |
258 | 155 | ||
259 | /* This is Malta specific: IPI,performance and timer inetrrupts */ | 156 | /* This is Malta specific: IPI,performance and timer inetrrupts */ |
260 | write_c0_status((read_c0_status() & ~ST0_IM ) | | 157 | if (gic_present) |
261 | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); | 158 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | |
159 | STATUSF_IP6 | STATUSF_IP7); | ||
160 | else | ||
161 | change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 | | ||
162 | STATUSF_IP6 | STATUSF_IP7); | ||
262 | } | 163 | } |
263 | 164 | ||
264 | static void __cpuinit vsmp_smp_finish(void) | 165 | static void __cpuinit vsmp_smp_finish(void) |
265 | { | 166 | { |
167 | /* CDFIXME: remove this? */ | ||
266 | write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); | 168 | write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); |
267 | 169 | ||
268 | #ifdef CONFIG_MIPS_MT_FPAFF | 170 | #ifdef CONFIG_MIPS_MT_FPAFF |
@@ -323,7 +225,7 @@ static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle) | |||
323 | /* | 225 | /* |
324 | * Common setup before any secondaries are started | 226 | * Common setup before any secondaries are started |
325 | * Make sure all CPU's are in a sensible state before we boot any of the | 227 | * Make sure all CPU's are in a sensible state before we boot any of the |
326 | * secondarys | 228 | * secondaries |
327 | */ | 229 | */ |
328 | static void __init vsmp_smp_setup(void) | 230 | static void __init vsmp_smp_setup(void) |
329 | { | 231 | { |
@@ -356,8 +258,8 @@ static void __init vsmp_smp_setup(void) | |||
356 | for (tc = 0; tc <= ntc; tc++) { | 258 | for (tc = 0; tc <= ntc; tc++) { |
357 | settc(tc); | 259 | settc(tc); |
358 | 260 | ||
359 | smp_tc_init(tc, mvpconf0); | 261 | smvp_tc_init(tc, mvpconf0); |
360 | ncpu = smp_vpe_init(tc, mvpconf0, ncpu); | 262 | ncpu = smvp_vpe_init(tc, mvpconf0, ncpu); |
361 | } | 263 | } |
362 | 264 | ||
363 | /* Release config state */ | 265 | /* Release config state */ |
@@ -371,21 +273,6 @@ static void __init vsmp_smp_setup(void) | |||
371 | static void __init vsmp_prepare_cpus(unsigned int max_cpus) | 273 | static void __init vsmp_prepare_cpus(unsigned int max_cpus) |
372 | { | 274 | { |
373 | mips_mt_set_cpuoptions(); | 275 | mips_mt_set_cpuoptions(); |
374 | |||
375 | /* set up ipi interrupts */ | ||
376 | if (cpu_has_vint) { | ||
377 | set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); | ||
378 | set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); | ||
379 | } | ||
380 | |||
381 | cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; | ||
382 | cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; | ||
383 | |||
384 | setup_irq(cpu_ipi_resched_irq, &irq_resched); | ||
385 | setup_irq(cpu_ipi_call_irq, &irq_call); | ||
386 | |||
387 | set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); | ||
388 | set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); | ||
389 | } | 276 | } |
390 | 277 | ||
391 | struct plat_smp_ops vsmp_smp_ops = { | 278 | struct plat_smp_ops vsmp_smp_ops = { |
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 9d41dab90a80..33780cc61ce9 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
36 | #include <asm/cpu.h> | 36 | #include <asm/cpu.h> |
37 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
38 | #include <asm/r4k-timer.h> | ||
38 | #include <asm/system.h> | 39 | #include <asm/system.h> |
39 | #include <asm/mmu_context.h> | 40 | #include <asm/mmu_context.h> |
40 | #include <asm/time.h> | 41 | #include <asm/time.h> |
@@ -125,6 +126,8 @@ asmlinkage __cpuinit void start_secondary(void) | |||
125 | 126 | ||
126 | cpu_set(cpu, cpu_callin_map); | 127 | cpu_set(cpu, cpu_callin_map); |
127 | 128 | ||
129 | synchronise_count_slave(); | ||
130 | |||
128 | cpu_idle(); | 131 | cpu_idle(); |
129 | } | 132 | } |
130 | 133 | ||
@@ -287,6 +290,7 @@ void smp_send_stop(void) | |||
287 | void __init smp_cpus_done(unsigned int max_cpus) | 290 | void __init smp_cpus_done(unsigned int max_cpus) |
288 | { | 291 | { |
289 | mp_ops->cpus_done(); | 292 | mp_ops->cpus_done(); |
293 | synchronise_count_master(); | ||
290 | } | 294 | } |
291 | 295 | ||
292 | /* called from main before smp_init() */ | 296 | /* called from main before smp_init() */ |
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index b42e71c71119..3e863186cd22 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
@@ -174,14 +174,6 @@ static int clock_hang_reported[NR_CPUS]; | |||
174 | 174 | ||
175 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | 175 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ |
176 | 176 | ||
177 | /* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */ | ||
178 | |||
179 | void __init sanitize_tlb_entries(void) | ||
180 | { | ||
181 | printk("Deprecated sanitize_tlb_entries() invoked\n"); | ||
182 | } | ||
183 | |||
184 | |||
185 | /* | 177 | /* |
186 | * Configure shared TLB - VPC configuration bit must be set by caller | 178 | * Configure shared TLB - VPC configuration bit must be set by caller |
187 | */ | 179 | */ |
@@ -339,7 +331,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu) | |||
339 | /* In general, all TCs should have the same cpu_data indications */ | 331 | /* In general, all TCs should have the same cpu_data indications */ |
340 | memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); | 332 | memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); |
341 | /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ | 333 | /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ |
342 | if (cpu_data[0].cputype == CPU_34K) | 334 | if (cpu_data[0].cputype == CPU_34K || |
335 | cpu_data[0].cputype == CPU_1004K) | ||
343 | cpu_data[cpu].options &= ~MIPS_CPU_FPU; | 336 | cpu_data[cpu].options &= ~MIPS_CPU_FPU; |
344 | cpu_data[cpu].vpe_id = vpe; | 337 | cpu_data[cpu].vpe_id = vpe; |
345 | cpu_data[cpu].tc_id = tc; | 338 | cpu_data[cpu].tc_id = tc; |
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c new file mode 100644 index 000000000000..6ddb507a87ef --- /dev/null +++ b/arch/mips/kernel/spram.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * MIPS SPRAM support | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * Copyright (C) 2007, 2008 MIPS Technologies, Inc. | ||
10 | */ | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/ptrace.h> | ||
14 | #include <linux/stddef.h> | ||
15 | |||
16 | #include <asm/cpu.h> | ||
17 | #include <asm/fpu.h> | ||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/system.h> | ||
20 | #include <asm/r4kcache.h> | ||
21 | #include <asm/hazards.h> | ||
22 | |||
23 | /* | ||
24 | * These definitions are correct for the 24K/34K/74K SPRAM sample | ||
25 | * implementation. The 4KS interpreted the tags differently... | ||
26 | */ | ||
27 | #define SPRAM_TAG0_ENABLE 0x00000080 | ||
28 | #define SPRAM_TAG0_PA_MASK 0xfffff000 | ||
29 | #define SPRAM_TAG1_SIZE_MASK 0xfffff000 | ||
30 | |||
31 | #define SPRAM_TAG_STRIDE 8 | ||
32 | |||
33 | #define ERRCTL_SPRAM (1 << 28) | ||
34 | |||
35 | /* errctl access */ | ||
36 | #define read_c0_errctl(x) read_c0_ecc(x) | ||
37 | #define write_c0_errctl(x) write_c0_ecc(x) | ||
38 | |||
39 | /* | ||
40 | * Different semantics to the set_c0_* function built by __BUILD_SET_C0 | ||
41 | */ | ||
42 | static __cpuinit unsigned int bis_c0_errctl(unsigned int set) | ||
43 | { | ||
44 | unsigned int res; | ||
45 | res = read_c0_errctl(); | ||
46 | write_c0_errctl(res | set); | ||
47 | return res; | ||
48 | } | ||
49 | |||
50 | static __cpuinit void ispram_store_tag(unsigned int offset, unsigned int data) | ||
51 | { | ||
52 | unsigned int errctl; | ||
53 | |||
54 | /* enable SPRAM tag access */ | ||
55 | errctl = bis_c0_errctl(ERRCTL_SPRAM); | ||
56 | ehb(); | ||
57 | |||
58 | write_c0_taglo(data); | ||
59 | ehb(); | ||
60 | |||
61 | cache_op(Index_Store_Tag_I, CKSEG0|offset); | ||
62 | ehb(); | ||
63 | |||
64 | write_c0_errctl(errctl); | ||
65 | ehb(); | ||
66 | } | ||
67 | |||
68 | |||
69 | static __cpuinit unsigned int ispram_load_tag(unsigned int offset) | ||
70 | { | ||
71 | unsigned int data; | ||
72 | unsigned int errctl; | ||
73 | |||
74 | /* enable SPRAM tag access */ | ||
75 | errctl = bis_c0_errctl(ERRCTL_SPRAM); | ||
76 | ehb(); | ||
77 | cache_op(Index_Load_Tag_I, CKSEG0 | offset); | ||
78 | ehb(); | ||
79 | data = read_c0_taglo(); | ||
80 | ehb(); | ||
81 | write_c0_errctl(errctl); | ||
82 | ehb(); | ||
83 | |||
84 | return data; | ||
85 | } | ||
86 | |||
87 | static __cpuinit void dspram_store_tag(unsigned int offset, unsigned int data) | ||
88 | { | ||
89 | unsigned int errctl; | ||
90 | |||
91 | /* enable SPRAM tag access */ | ||
92 | errctl = bis_c0_errctl(ERRCTL_SPRAM); | ||
93 | ehb(); | ||
94 | write_c0_dtaglo(data); | ||
95 | ehb(); | ||
96 | cache_op(Index_Store_Tag_D, CKSEG0 | offset); | ||
97 | ehb(); | ||
98 | write_c0_errctl(errctl); | ||
99 | ehb(); | ||
100 | } | ||
101 | |||
102 | |||
103 | static __cpuinit unsigned int dspram_load_tag(unsigned int offset) | ||
104 | { | ||
105 | unsigned int data; | ||
106 | unsigned int errctl; | ||
107 | |||
108 | errctl = bis_c0_errctl(ERRCTL_SPRAM); | ||
109 | ehb(); | ||
110 | cache_op(Index_Load_Tag_D, CKSEG0 | offset); | ||
111 | ehb(); | ||
112 | data = read_c0_dtaglo(); | ||
113 | ehb(); | ||
114 | write_c0_errctl(errctl); | ||
115 | ehb(); | ||
116 | |||
117 | return data; | ||
118 | } | ||
119 | |||
120 | static __cpuinit void probe_spram(char *type, | ||
121 | unsigned int base, | ||
122 | unsigned int (*read)(unsigned int), | ||
123 | void (*write)(unsigned int, unsigned int)) | ||
124 | { | ||
125 | unsigned int firstsize = 0, lastsize = 0; | ||
126 | unsigned int firstpa = 0, lastpa = 0, pa = 0; | ||
127 | unsigned int offset = 0; | ||
128 | unsigned int size, tag0, tag1; | ||
129 | unsigned int enabled; | ||
130 | int i; | ||
131 | |||
132 | /* | ||
133 | * The limit is arbitrary but avoids the loop running away if | ||
134 | * the SPRAM tags are implemented differently | ||
135 | */ | ||
136 | |||
137 | for (i = 0; i < 8; i++) { | ||
138 | tag0 = read(offset); | ||
139 | tag1 = read(offset+SPRAM_TAG_STRIDE); | ||
140 | pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", | ||
141 | type, i, tag0, tag1); | ||
142 | |||
143 | size = tag1 & SPRAM_TAG1_SIZE_MASK; | ||
144 | |||
145 | if (size == 0) | ||
146 | break; | ||
147 | |||
148 | if (i != 0) { | ||
149 | /* tags may repeat... */ | ||
150 | if ((pa == firstpa && size == firstsize) || | ||
151 | (pa == lastpa && size == lastsize)) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | /* Align base with size */ | ||
156 | base = (base + size - 1) & ~(size-1); | ||
157 | |||
158 | /* reprogram the base address base address and enable */ | ||
159 | tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; | ||
160 | write(offset, tag0); | ||
161 | |||
162 | base += size; | ||
163 | |||
164 | /* reread the tag */ | ||
165 | tag0 = read(offset); | ||
166 | pa = tag0 & SPRAM_TAG0_PA_MASK; | ||
167 | enabled = tag0 & SPRAM_TAG0_ENABLE; | ||
168 | |||
169 | if (i == 0) { | ||
170 | firstpa = pa; | ||
171 | firstsize = size; | ||
172 | } | ||
173 | |||
174 | lastpa = pa; | ||
175 | lastsize = size; | ||
176 | |||
177 | if (strcmp(type, "DSPRAM") == 0) { | ||
178 | unsigned int *vp = (unsigned int *)(CKSEG1 | pa); | ||
179 | unsigned int v; | ||
180 | #define TDAT 0x5a5aa5a5 | ||
181 | vp[0] = TDAT; | ||
182 | vp[1] = ~TDAT; | ||
183 | |||
184 | mb(); | ||
185 | |||
186 | v = vp[0]; | ||
187 | if (v != TDAT) | ||
188 | printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", | ||
189 | vp, TDAT, v); | ||
190 | v = vp[1]; | ||
191 | if (v != ~TDAT) | ||
192 | printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", | ||
193 | vp+1, ~TDAT, v); | ||
194 | } | ||
195 | |||
196 | pr_info("%s%d: PA=%08x,Size=%08x%s\n", | ||
197 | type, i, pa, size, enabled ? ",enabled" : ""); | ||
198 | offset += 2 * SPRAM_TAG_STRIDE; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | __cpuinit void spram_config(void) | ||
203 | { | ||
204 | struct cpuinfo_mips *c = ¤t_cpu_data; | ||
205 | unsigned int config0; | ||
206 | |||
207 | switch (c->cputype) { | ||
208 | case CPU_24K: | ||
209 | case CPU_34K: | ||
210 | case CPU_74K: | ||
211 | config0 = read_c0_config(); | ||
212 | /* FIXME: addresses are Malta specific */ | ||
213 | if (config0 & (1<<24)) { | ||
214 | probe_spram("ISPRAM", 0x1c000000, | ||
215 | &ispram_load_tag, &ispram_store_tag); | ||
216 | } | ||
217 | if (config0 & (1<<23)) | ||
218 | probe_spram("DSPRAM", 0x1c100000, | ||
219 | &dspram_load_tag, &dspram_store_tag); | ||
220 | } | ||
221 | } | ||
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c new file mode 100644 index 000000000000..9021108eb9c1 --- /dev/null +++ b/arch/mips/kernel/sync-r4k.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Count register synchronisation. | ||
3 | * | ||
4 | * All CPUs will have their count registers synchronised to the CPU0 expirelo | ||
5 | * value. This can cause a small timewarp for CPU0. All other CPU's should | ||
6 | * not have done anything significant (but they may have had interrupts | ||
7 | * enabled briefly - prom_smp_finish() should not be responsible for enabling | ||
8 | * interrupts...) | ||
9 | * | ||
10 | * FIXME: broken for SMTC | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/irqflags.h> | ||
16 | #include <linux/r4k-timer.h> | ||
17 | |||
18 | #include <asm/atomic.h> | ||
19 | #include <asm/barrier.h> | ||
20 | #include <asm/cpumask.h> | ||
21 | #include <asm/mipsregs.h> | ||
22 | |||
23 | static atomic_t __initdata count_start_flag = ATOMIC_INIT(0); | ||
24 | static atomic_t __initdata count_count_start = ATOMIC_INIT(0); | ||
25 | static atomic_t __initdata count_count_stop = ATOMIC_INIT(0); | ||
26 | |||
27 | #define COUNTON 100 | ||
28 | #define NR_LOOPS 5 | ||
29 | |||
30 | void __init synchronise_count_master(void) | ||
31 | { | ||
32 | int i; | ||
33 | unsigned long flags; | ||
34 | unsigned int initcount; | ||
35 | int nslaves; | ||
36 | |||
37 | #ifdef CONFIG_MIPS_MT_SMTC | ||
38 | /* | ||
39 | * SMTC needs to synchronise per VPE, not per CPU | ||
40 | * ignore for now | ||
41 | */ | ||
42 | return; | ||
43 | #endif | ||
44 | |||
45 | pr_info("Checking COUNT synchronization across %u CPUs: ", | ||
46 | num_online_cpus()); | ||
47 | |||
48 | local_irq_save(flags); | ||
49 | |||
50 | /* | ||
51 | * Notify the slaves that it's time to start | ||
52 | */ | ||
53 | atomic_set(&count_start_flag, 1); | ||
54 | smp_wmb(); | ||
55 | |||
56 | /* Count will be initialised to expirelo for all CPU's */ | ||
57 | initcount = expirelo; | ||
58 | |||
59 | /* | ||
60 | * We loop a few times to get a primed instruction cache, | ||
61 | * then the last pass is more or less synchronised and | ||
62 | * the master and slaves each set their cycle counters to a known | ||
63 | * value all at once. This reduces the chance of having random offsets | ||
64 | * between the processors, and guarantees that the maximum | ||
65 | * delay between the cycle counters is never bigger than | ||
66 | * the latency of information-passing (cachelines) between | ||
67 | * two CPUs. | ||
68 | */ | ||
69 | |||
70 | nslaves = num_online_cpus()-1; | ||
71 | for (i = 0; i < NR_LOOPS; i++) { | ||
72 | /* slaves loop on '!= ncpus' */ | ||
73 | while (atomic_read(&count_count_start) != nslaves) | ||
74 | mb(); | ||
75 | atomic_set(&count_count_stop, 0); | ||
76 | smp_wmb(); | ||
77 | |||
78 | /* this lets the slaves write their count register */ | ||
79 | atomic_inc(&count_count_start); | ||
80 | |||
81 | /* | ||
82 | * Everyone initialises count in the last loop: | ||
83 | */ | ||
84 | if (i == NR_LOOPS-1) | ||
85 | write_c0_count(initcount); | ||
86 | |||
87 | /* | ||
88 | * Wait for all slaves to leave the synchronization point: | ||
89 | */ | ||
90 | while (atomic_read(&count_count_stop) != nslaves) | ||
91 | mb(); | ||
92 | atomic_set(&count_count_start, 0); | ||
93 | smp_wmb(); | ||
94 | atomic_inc(&count_count_stop); | ||
95 | } | ||
96 | /* Arrange for an interrupt in a short while */ | ||
97 | write_c0_compare(read_c0_count() + COUNTON); | ||
98 | |||
99 | local_irq_restore(flags); | ||
100 | |||
101 | /* | ||
102 | * i386 code reported the skew here, but the | ||
103 | * count registers were almost certainly out of sync | ||
104 | * so no point in alarming people | ||
105 | */ | ||
106 | printk("done.\n"); | ||
107 | } | ||
108 | |||
109 | void __init synchronise_count_slave(void) | ||
110 | { | ||
111 | int i; | ||
112 | unsigned long flags; | ||
113 | unsigned int initcount; | ||
114 | int ncpus; | ||
115 | |||
116 | #ifdef CONFIG_MIPS_MT_SMTC | ||
117 | /* | ||
118 | * SMTC needs to synchronise per VPE, not per CPU | ||
119 | * ignore for now | ||
120 | */ | ||
121 | return; | ||
122 | #endif | ||
123 | |||
124 | local_irq_save(flags); | ||
125 | |||
126 | /* | ||
127 | * Not every cpu is online at the time this gets called, | ||
128 | * so we first wait for the master to say everyone is ready | ||
129 | */ | ||
130 | |||
131 | while (!atomic_read(&count_start_flag)) | ||
132 | mb(); | ||
133 | |||
134 | /* Count will be initialised to expirelo for all CPU's */ | ||
135 | initcount = expirelo; | ||
136 | |||
137 | ncpus = num_online_cpus(); | ||
138 | for (i = 0; i < NR_LOOPS; i++) { | ||
139 | atomic_inc(&count_count_start); | ||
140 | while (atomic_read(&count_count_start) != ncpus) | ||
141 | mb(); | ||
142 | |||
143 | /* | ||
144 | * Everyone initialises count in the last loop: | ||
145 | */ | ||
146 | if (i == NR_LOOPS-1) | ||
147 | write_c0_count(initcount); | ||
148 | |||
149 | atomic_inc(&count_count_stop); | ||
150 | while (atomic_read(&count_count_stop) != ncpus) | ||
151 | mb(); | ||
152 | } | ||
153 | /* Arrange for an interrupt in a short while */ | ||
154 | write_c0_compare(read_c0_count() + COUNTON); | ||
155 | |||
156 | local_irq_restore(flags); | ||
157 | } | ||
158 | #undef NR_LOOPS | ||
159 | #endif | ||
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index b45a7093ca2d..1f467d534642 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -38,7 +38,6 @@ int __weak rtc_mips_set_time(unsigned long sec) | |||
38 | { | 38 | { |
39 | return 0; | 39 | return 0; |
40 | } | 40 | } |
41 | EXPORT_SYMBOL(rtc_mips_set_time); | ||
42 | 41 | ||
43 | int __weak rtc_mips_set_mmss(unsigned long nowtime) | 42 | int __weak rtc_mips_set_mmss(unsigned long nowtime) |
44 | { | 43 | { |
@@ -50,13 +49,11 @@ int update_persistent_clock(struct timespec now) | |||
50 | return rtc_mips_set_mmss(now.tv_sec); | 49 | return rtc_mips_set_mmss(now.tv_sec); |
51 | } | 50 | } |
52 | 51 | ||
53 | int null_perf_irq(void) | 52 | static int null_perf_irq(void) |
54 | { | 53 | { |
55 | return 0; | 54 | return 0; |
56 | } | 55 | } |
57 | 56 | ||
58 | EXPORT_SYMBOL(null_perf_irq); | ||
59 | |||
60 | int (*perf_irq)(void) = null_perf_irq; | 57 | int (*perf_irq)(void) = null_perf_irq; |
61 | 58 | ||
62 | EXPORT_SYMBOL(perf_irq); | 59 | EXPORT_SYMBOL(perf_irq); |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 984c0d0a7b4d..cb8b0e2c7954 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kallsyms.h> | 22 | #include <linux/kallsyms.h> |
23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/ptrace.h> | ||
25 | 26 | ||
26 | #include <asm/bootinfo.h> | 27 | #include <asm/bootinfo.h> |
27 | #include <asm/branch.h> | 28 | #include <asm/branch.h> |
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset); | |||
80 | 81 | ||
81 | static void show_raw_backtrace(unsigned long reg29) | 82 | static void show_raw_backtrace(unsigned long reg29) |
82 | { | 83 | { |
83 | unsigned long *sp = (unsigned long *)reg29; | 84 | unsigned long *sp = (unsigned long *)(reg29 & ~3); |
84 | unsigned long addr; | 85 | unsigned long addr; |
85 | 86 | ||
86 | printk("Call Trace:"); | 87 | printk("Call Trace:"); |
87 | #ifdef CONFIG_KALLSYMS | 88 | #ifdef CONFIG_KALLSYMS |
88 | printk("\n"); | 89 | printk("\n"); |
89 | #endif | 90 | #endif |
90 | while (!kstack_end(sp)) { | 91 | #define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000) |
91 | addr = *sp++; | 92 | if (IS_KVA01(sp)) { |
92 | if (__kernel_text_address(addr)) | 93 | while (!kstack_end(sp)) { |
93 | print_ip_sym(addr); | 94 | addr = *sp++; |
95 | if (__kernel_text_address(addr)) | ||
96 | print_ip_sym(addr); | ||
97 | } | ||
98 | printk("\n"); | ||
94 | } | 99 | } |
95 | printk("\n"); | ||
96 | } | 100 | } |
97 | 101 | ||
98 | #ifdef CONFIG_KALLSYMS | 102 | #ifdef CONFIG_KALLSYMS |
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack); | |||
192 | static void show_code(unsigned int __user *pc) | 196 | static void show_code(unsigned int __user *pc) |
193 | { | 197 | { |
194 | long i; | 198 | long i; |
199 | unsigned short __user *pc16 = NULL; | ||
195 | 200 | ||
196 | printk("\nCode:"); | 201 | printk("\nCode:"); |
197 | 202 | ||
203 | if ((unsigned long)pc & 1) | ||
204 | pc16 = (unsigned short __user *)((unsigned long)pc & ~1); | ||
198 | for(i = -3 ; i < 6 ; i++) { | 205 | for(i = -3 ; i < 6 ; i++) { |
199 | unsigned int insn; | 206 | unsigned int insn; |
200 | if (__get_user(insn, pc + i)) { | 207 | if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) { |
201 | printk(" (Bad address in epc)\n"); | 208 | printk(" (Bad address in epc)\n"); |
202 | break; | 209 | break; |
203 | } | 210 | } |
204 | printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>')); | 211 | printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>')); |
205 | } | 212 | } |
206 | } | 213 | } |
207 | 214 | ||
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs) | |||
311 | 318 | ||
312 | void show_registers(const struct pt_regs *regs) | 319 | void show_registers(const struct pt_regs *regs) |
313 | { | 320 | { |
321 | const int field = 2 * sizeof(unsigned long); | ||
322 | |||
314 | __show_regs(regs); | 323 | __show_regs(regs); |
315 | print_modules(); | 324 | print_modules(); |
316 | printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", | 325 | printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n", |
317 | current->comm, task_pid_nr(current), current_thread_info(), current); | 326 | current->comm, current->pid, current_thread_info(), current, |
327 | field, current_thread_info()->tp_value); | ||
328 | if (cpu_has_userlocal) { | ||
329 | unsigned long tls; | ||
330 | |||
331 | tls = read_c0_userlocal(); | ||
332 | if (tls != current_thread_info()->tp_value) | ||
333 | printk("*HwTLS: %0*lx\n", field, tls); | ||
334 | } | ||
335 | |||
318 | show_stacktrace(current, regs); | 336 | show_stacktrace(current, regs); |
319 | show_code((unsigned int __user *) regs->cp0_epc); | 337 | show_code((unsigned int __user *) regs->cp0_epc); |
320 | printk("\n"); | 338 | printk("\n"); |
@@ -657,35 +675,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
657 | force_sig_info(SIGFPE, &info, current); | 675 | force_sig_info(SIGFPE, &info, current); |
658 | } | 676 | } |
659 | 677 | ||
660 | asmlinkage void do_bp(struct pt_regs *regs) | 678 | static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, |
679 | const char *str) | ||
661 | { | 680 | { |
662 | unsigned int opcode, bcode; | ||
663 | siginfo_t info; | 681 | siginfo_t info; |
664 | 682 | char b[40]; | |
665 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | ||
666 | goto out_sigsegv; | ||
667 | |||
668 | /* | ||
669 | * There is the ancient bug in the MIPS assemblers that the break | ||
670 | * code starts left to bit 16 instead to bit 6 in the opcode. | ||
671 | * Gas is bug-compatible, but not always, grrr... | ||
672 | * We handle both cases with a simple heuristics. --macro | ||
673 | */ | ||
674 | bcode = ((opcode >> 6) & ((1 << 20) - 1)); | ||
675 | if (bcode < (1 << 10)) | ||
676 | bcode <<= 10; | ||
677 | 683 | ||
678 | /* | 684 | /* |
679 | * (A short test says that IRIX 5.3 sends SIGTRAP for all break | 685 | * A short test says that IRIX 5.3 sends SIGTRAP for all trap |
680 | * insns, even for break codes that indicate arithmetic failures. | 686 | * insns, even for trap and break codes that indicate arithmetic |
681 | * Weird ...) | 687 | * failures. Weird ... |
682 | * But should we continue the brokenness??? --macro | 688 | * But should we continue the brokenness??? --macro |
683 | */ | 689 | */ |
684 | switch (bcode) { | 690 | switch (code) { |
685 | case BRK_OVERFLOW << 10: | 691 | case BRK_OVERFLOW: |
686 | case BRK_DIVZERO << 10: | 692 | case BRK_DIVZERO: |
687 | die_if_kernel("Break instruction in kernel code", regs); | 693 | scnprintf(b, sizeof(b), "%s instruction in kernel code", str); |
688 | if (bcode == (BRK_DIVZERO << 10)) | 694 | die_if_kernel(b, regs); |
695 | if (code == BRK_DIVZERO) | ||
689 | info.si_code = FPE_INTDIV; | 696 | info.si_code = FPE_INTDIV; |
690 | else | 697 | else |
691 | info.si_code = FPE_INTOVF; | 698 | info.si_code = FPE_INTOVF; |
@@ -695,12 +702,34 @@ asmlinkage void do_bp(struct pt_regs *regs) | |||
695 | force_sig_info(SIGFPE, &info, current); | 702 | force_sig_info(SIGFPE, &info, current); |
696 | break; | 703 | break; |
697 | case BRK_BUG: | 704 | case BRK_BUG: |
698 | die("Kernel bug detected", regs); | 705 | die_if_kernel("Kernel bug detected", regs); |
706 | force_sig(SIGTRAP, current); | ||
699 | break; | 707 | break; |
700 | default: | 708 | default: |
701 | die_if_kernel("Break instruction in kernel code", regs); | 709 | scnprintf(b, sizeof(b), "%s instruction in kernel code", str); |
710 | die_if_kernel(b, regs); | ||
702 | force_sig(SIGTRAP, current); | 711 | force_sig(SIGTRAP, current); |
703 | } | 712 | } |
713 | } | ||
714 | |||
715 | asmlinkage void do_bp(struct pt_regs *regs) | ||
716 | { | ||
717 | unsigned int opcode, bcode; | ||
718 | |||
719 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | ||
720 | goto out_sigsegv; | ||
721 | |||
722 | /* | ||
723 | * There is the ancient bug in the MIPS assemblers that the break | ||
724 | * code starts left to bit 16 instead to bit 6 in the opcode. | ||
725 | * Gas is bug-compatible, but not always, grrr... | ||
726 | * We handle both cases with a simple heuristics. --macro | ||
727 | */ | ||
728 | bcode = ((opcode >> 6) & ((1 << 20) - 1)); | ||
729 | if (bcode >= (1 << 10)) | ||
730 | bcode >>= 10; | ||
731 | |||
732 | do_trap_or_bp(regs, bcode, "Break"); | ||
704 | return; | 733 | return; |
705 | 734 | ||
706 | out_sigsegv: | 735 | out_sigsegv: |
@@ -710,7 +739,6 @@ out_sigsegv: | |||
710 | asmlinkage void do_tr(struct pt_regs *regs) | 739 | asmlinkage void do_tr(struct pt_regs *regs) |
711 | { | 740 | { |
712 | unsigned int opcode, tcode = 0; | 741 | unsigned int opcode, tcode = 0; |
713 | siginfo_t info; | ||
714 | 742 | ||
715 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) | 743 | if (__get_user(opcode, (unsigned int __user *) exception_epc(regs))) |
716 | goto out_sigsegv; | 744 | goto out_sigsegv; |
@@ -719,32 +747,7 @@ asmlinkage void do_tr(struct pt_regs *regs) | |||
719 | if (!(opcode & OPCODE)) | 747 | if (!(opcode & OPCODE)) |
720 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); | 748 | tcode = ((opcode >> 6) & ((1 << 10) - 1)); |
721 | 749 | ||
722 | /* | 750 | do_trap_or_bp(regs, tcode, "Trap"); |
723 | * (A short test says that IRIX 5.3 sends SIGTRAP for all trap | ||
724 | * insns, even for trap codes that indicate arithmetic failures. | ||
725 | * Weird ...) | ||
726 | * But should we continue the brokenness??? --macro | ||
727 | */ | ||
728 | switch (tcode) { | ||
729 | case BRK_OVERFLOW: | ||
730 | case BRK_DIVZERO: | ||
731 | die_if_kernel("Trap instruction in kernel code", regs); | ||
732 | if (tcode == BRK_DIVZERO) | ||
733 | info.si_code = FPE_INTDIV; | ||
734 | else | ||
735 | info.si_code = FPE_INTOVF; | ||
736 | info.si_signo = SIGFPE; | ||
737 | info.si_errno = 0; | ||
738 | info.si_addr = (void __user *) regs->cp0_epc; | ||
739 | force_sig_info(SIGFPE, &info, current); | ||
740 | break; | ||
741 | case BRK_BUG: | ||
742 | die("Kernel bug detected", regs); | ||
743 | break; | ||
744 | default: | ||
745 | die_if_kernel("Trap instruction in kernel code", regs); | ||
746 | force_sig(SIGTRAP, current); | ||
747 | } | ||
748 | return; | 751 | return; |
749 | 752 | ||
750 | out_sigsegv: | 753 | out_sigsegv: |
@@ -985,6 +988,21 @@ asmlinkage void do_reserved(struct pt_regs *regs) | |||
985 | (regs->cp0_cause & 0x7f) >> 2); | 988 | (regs->cp0_cause & 0x7f) >> 2); |
986 | } | 989 | } |
987 | 990 | ||
991 | static int __initdata l1parity = 1; | ||
992 | static int __init nol1parity(char *s) | ||
993 | { | ||
994 | l1parity = 0; | ||
995 | return 1; | ||
996 | } | ||
997 | __setup("nol1par", nol1parity); | ||
998 | static int __initdata l2parity = 1; | ||
999 | static int __init nol2parity(char *s) | ||
1000 | { | ||
1001 | l2parity = 0; | ||
1002 | return 1; | ||
1003 | } | ||
1004 | __setup("nol2par", nol2parity); | ||
1005 | |||
988 | /* | 1006 | /* |
989 | * Some MIPS CPUs can enable/disable for cache parity detection, but do | 1007 | * Some MIPS CPUs can enable/disable for cache parity detection, but do |
990 | * it different ways. | 1008 | * it different ways. |
@@ -994,6 +1012,62 @@ static inline void parity_protection_init(void) | |||
994 | switch (current_cpu_type()) { | 1012 | switch (current_cpu_type()) { |
995 | case CPU_24K: | 1013 | case CPU_24K: |
996 | case CPU_34K: | 1014 | case CPU_34K: |
1015 | case CPU_74K: | ||
1016 | case CPU_1004K: | ||
1017 | { | ||
1018 | #define ERRCTL_PE 0x80000000 | ||
1019 | #define ERRCTL_L2P 0x00800000 | ||
1020 | unsigned long errctl; | ||
1021 | unsigned int l1parity_present, l2parity_present; | ||
1022 | |||
1023 | errctl = read_c0_ecc(); | ||
1024 | errctl &= ~(ERRCTL_PE|ERRCTL_L2P); | ||
1025 | |||
1026 | /* probe L1 parity support */ | ||
1027 | write_c0_ecc(errctl | ERRCTL_PE); | ||
1028 | back_to_back_c0_hazard(); | ||
1029 | l1parity_present = (read_c0_ecc() & ERRCTL_PE); | ||
1030 | |||
1031 | /* probe L2 parity support */ | ||
1032 | write_c0_ecc(errctl|ERRCTL_L2P); | ||
1033 | back_to_back_c0_hazard(); | ||
1034 | l2parity_present = (read_c0_ecc() & ERRCTL_L2P); | ||
1035 | |||
1036 | if (l1parity_present && l2parity_present) { | ||
1037 | if (l1parity) | ||
1038 | errctl |= ERRCTL_PE; | ||
1039 | if (l1parity ^ l2parity) | ||
1040 | errctl |= ERRCTL_L2P; | ||
1041 | } else if (l1parity_present) { | ||
1042 | if (l1parity) | ||
1043 | errctl |= ERRCTL_PE; | ||
1044 | } else if (l2parity_present) { | ||
1045 | if (l2parity) | ||
1046 | errctl |= ERRCTL_L2P; | ||
1047 | } else { | ||
1048 | /* No parity available */ | ||
1049 | } | ||
1050 | |||
1051 | printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl); | ||
1052 | |||
1053 | write_c0_ecc(errctl); | ||
1054 | back_to_back_c0_hazard(); | ||
1055 | errctl = read_c0_ecc(); | ||
1056 | printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl); | ||
1057 | |||
1058 | if (l1parity_present) | ||
1059 | printk(KERN_INFO "Cache parity protection %sabled\n", | ||
1060 | (errctl & ERRCTL_PE) ? "en" : "dis"); | ||
1061 | |||
1062 | if (l2parity_present) { | ||
1063 | if (l1parity_present && l1parity) | ||
1064 | errctl ^= ERRCTL_L2P; | ||
1065 | printk(KERN_INFO "L2 cache parity protection %sabled\n", | ||
1066 | (errctl & ERRCTL_L2P) ? "en" : "dis"); | ||
1067 | } | ||
1068 | } | ||
1069 | break; | ||
1070 | |||
997 | case CPU_5KC: | 1071 | case CPU_5KC: |
998 | write_c0_ecc(0x80000000); | 1072 | write_c0_ecc(0x80000000); |
999 | back_to_back_c0_hazard(); | 1073 | back_to_back_c0_hazard(); |
@@ -1306,6 +1380,17 @@ int cp0_compare_irq; | |||
1306 | int cp0_perfcount_irq; | 1380 | int cp0_perfcount_irq; |
1307 | EXPORT_SYMBOL_GPL(cp0_perfcount_irq); | 1381 | EXPORT_SYMBOL_GPL(cp0_perfcount_irq); |
1308 | 1382 | ||
1383 | static int __cpuinitdata noulri; | ||
1384 | |||
1385 | static int __init ulri_disable(char *s) | ||
1386 | { | ||
1387 | pr_info("Disabling ulri\n"); | ||
1388 | noulri = 1; | ||
1389 | |||
1390 | return 1; | ||
1391 | } | ||
1392 | __setup("noulri", ulri_disable); | ||
1393 | |||
1309 | void __cpuinit per_cpu_trap_init(void) | 1394 | void __cpuinit per_cpu_trap_init(void) |
1310 | { | 1395 | { |
1311 | unsigned int cpu = smp_processor_id(); | 1396 | unsigned int cpu = smp_processor_id(); |
@@ -1342,16 +1427,14 @@ void __cpuinit per_cpu_trap_init(void) | |||
1342 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, | 1427 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
1343 | status_set); | 1428 | status_set); |
1344 | 1429 | ||
1345 | #ifdef CONFIG_CPU_MIPSR2 | ||
1346 | if (cpu_has_mips_r2) { | 1430 | if (cpu_has_mips_r2) { |
1347 | unsigned int enable = 0x0000000f; | 1431 | unsigned int enable = 0x0000000f; |
1348 | 1432 | ||
1349 | if (cpu_has_userlocal) | 1433 | if (!noulri && cpu_has_userlocal) |
1350 | enable |= (1 << 29); | 1434 | enable |= (1 << 29); |
1351 | 1435 | ||
1352 | write_c0_hwrena(enable); | 1436 | write_c0_hwrena(enable); |
1353 | } | 1437 | } |
1354 | #endif | ||
1355 | 1438 | ||
1356 | #ifdef CONFIG_MIPS_MT_SMTC | 1439 | #ifdef CONFIG_MIPS_MT_SMTC |
1357 | if (!secondaryTC) { | 1440 | if (!secondaryTC) { |
diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c index c11b2494bb6e..2ab899c4b4ce 100644 --- a/arch/mips/lib/iomap-pci.c +++ b/arch/mips/lib/iomap-pci.c | |||
@@ -45,8 +45,8 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev, | |||
45 | */ | 45 | */ |
46 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 46 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
47 | { | 47 | { |
48 | unsigned long start = pci_resource_start(dev, bar); | 48 | resource_size_t start = pci_resource_start(dev, bar); |
49 | unsigned long len = pci_resource_len(dev, bar); | 49 | resource_size_t len = pci_resource_len(dev, bar); |
50 | unsigned long flags = pci_resource_flags(dev, bar); | 50 | unsigned long flags = pci_resource_flags(dev, bar); |
51 | 51 | ||
52 | if (!len || !start) | 52 | if (!len || !start) |
diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index 8977eb585a37..762786538449 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h | |||
@@ -46,7 +46,7 @@ | |||
46 | #define DPDNORMX DPDNORMx(xm, xe) | 46 | #define DPDNORMX DPDNORMx(xm, xe) |
47 | #define DPDNORMY DPDNORMx(ym, ye) | 47 | #define DPDNORMY DPDNORMx(ym, ye) |
48 | 48 | ||
49 | static __inline ieee754dp builddp(int s, int bx, u64 m) | 49 | static inline ieee754dp builddp(int s, int bx, u64 m) |
50 | { | 50 | { |
51 | ieee754dp r; | 51 | ieee754dp r; |
52 | 52 | ||
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 9917c1e4d947..d9e3586b5bce 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h | |||
@@ -51,7 +51,7 @@ | |||
51 | #define SPDNORMX SPDNORMx(xm, xe) | 51 | #define SPDNORMX SPDNORMx(xm, xe) |
52 | #define SPDNORMY SPDNORMx(ym, ye) | 52 | #define SPDNORMY SPDNORMx(ym, ye) |
53 | 53 | ||
54 | static __inline ieee754sp buildsp(int s, int bx, unsigned m) | 54 | static inline ieee754sp buildsp(int s, int bx, unsigned m) |
55 | { | 55 | { |
56 | ieee754sp r; | 56 | ieee754sp r; |
57 | 57 | ||
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile index b31d8dfed1be..f7f87fc09d1e 100644 --- a/arch/mips/mips-boards/generic/Makefile +++ b/arch/mips/mips-boards/generic/Makefile | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | obj-y := reset.o display.o init.o memory.o \ | 21 | obj-y := reset.o display.o init.o memory.o \ |
22 | cmdline.o time.o | 22 | cmdline.o time.o |
23 | obj-y += amon.o | ||
23 | 24 | ||
24 | obj-$(CONFIG_EARLY_PRINTK) += console.o | 25 | obj-$(CONFIG_EARLY_PRINTK) += console.o |
25 | obj-$(CONFIG_PCI) += pci.o | 26 | obj-$(CONFIG_PCI) += pci.o |
diff --git a/arch/mips/mips-boards/generic/amon.c b/arch/mips/mips-boards/generic/amon.c new file mode 100644 index 000000000000..b7633fda4180 --- /dev/null +++ b/arch/mips/mips-boards/generic/amon.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 MIPS Technologies, Inc. | ||
3 | * All rights reserved. | ||
4 | |||
5 | * This program is free software; you can distribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License (Version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
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 | * Arbitrary Monitor interface | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/smp.h> | ||
24 | |||
25 | #include <asm-mips/addrspace.h> | ||
26 | #include <asm-mips/mips-boards/launch.h> | ||
27 | #include <asm-mips/mipsmtregs.h> | ||
28 | |||
29 | int amon_cpu_avail(int cpu) | ||
30 | { | ||
31 | struct cpulaunch *launch = (struct cpulaunch *)KSEG0ADDR(CPULAUNCH); | ||
32 | |||
33 | if (cpu < 0 || cpu >= NCPULAUNCH) { | ||
34 | pr_debug("avail: cpu%d is out of range\n", cpu); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | launch += cpu; | ||
39 | if (!(launch->flags & LAUNCH_FREADY)) { | ||
40 | pr_debug("avail: cpu%d is not ready\n", cpu); | ||
41 | return 0; | ||
42 | } | ||
43 | if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { | ||
44 | pr_debug("avail: too late.. cpu%d is already gone\n", cpu); | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | void amon_cpu_start(int cpu, | ||
52 | unsigned long pc, unsigned long sp, | ||
53 | unsigned long gp, unsigned long a0) | ||
54 | { | ||
55 | volatile struct cpulaunch *launch = | ||
56 | (struct cpulaunch *)KSEG0ADDR(CPULAUNCH); | ||
57 | |||
58 | if (!amon_cpu_avail(cpu)) | ||
59 | return; | ||
60 | if (cpu == smp_processor_id()) { | ||
61 | pr_debug("launch: I am cpu%d!\n", cpu); | ||
62 | return; | ||
63 | } | ||
64 | launch += cpu; | ||
65 | |||
66 | pr_debug("launch: starting cpu%d\n", cpu); | ||
67 | |||
68 | launch->pc = pc; | ||
69 | launch->gp = gp; | ||
70 | launch->sp = sp; | ||
71 | launch->a0 = a0; | ||
72 | |||
73 | /* Make sure target sees parameters before the go bit */ | ||
74 | smp_mb(); | ||
75 | |||
76 | launch->flags |= LAUNCH_FGO; | ||
77 | while ((launch->flags & LAUNCH_FGONE) == 0) | ||
78 | ; | ||
79 | pr_debug("launch: cpu%d gone!\n", cpu); | ||
80 | } | ||
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c index 1695dca5506b..83b9dc739203 100644 --- a/arch/mips/mips-boards/generic/init.c +++ b/arch/mips/mips-boards/generic/init.c | |||
@@ -226,7 +226,7 @@ void __init kgdb_config(void) | |||
226 | } | 226 | } |
227 | #endif | 227 | #endif |
228 | 228 | ||
229 | void __init mips_nmi_setup(void) | 229 | static void __init mips_nmi_setup(void) |
230 | { | 230 | { |
231 | void *base; | 231 | void *base; |
232 | extern char except_vec_nmi; | 232 | extern char except_vec_nmi; |
@@ -238,7 +238,7 @@ void __init mips_nmi_setup(void) | |||
238 | flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); | 238 | flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); |
239 | } | 239 | } |
240 | 240 | ||
241 | void __init mips_ejtag_setup(void) | 241 | static void __init mips_ejtag_setup(void) |
242 | { | 242 | { |
243 | void *base; | 243 | void *base; |
244 | extern char except_vec_ejtag_debug; | 244 | extern char except_vec_ejtag_debug; |
@@ -295,15 +295,21 @@ void __init prom_init(void) | |||
295 | break; | 295 | break; |
296 | case MIPS_REVISION_CORID_CORE_MSC: | 296 | case MIPS_REVISION_CORID_CORE_MSC: |
297 | case MIPS_REVISION_CORID_CORE_FPGA2: | 297 | case MIPS_REVISION_CORID_CORE_FPGA2: |
298 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
299 | case MIPS_REVISION_CORID_CORE_FPGA4: | ||
300 | case MIPS_REVISION_CORID_CORE_24K: | 298 | case MIPS_REVISION_CORID_CORE_24K: |
301 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | 299 | /* |
300 | * SOCit/ROCit support is essentially identical | ||
301 | * but make an attempt to distinguish them | ||
302 | */ | ||
302 | mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; | 303 | mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; |
303 | break; | 304 | break; |
305 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
306 | case MIPS_REVISION_CORID_CORE_FPGA4: | ||
307 | case MIPS_REVISION_CORID_CORE_FPGA5: | ||
308 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
304 | default: | 309 | default: |
305 | mips_display_message("CC Error"); | 310 | /* See above */ |
306 | while (1); /* We die here... */ | 311 | mips_revision_sconid = MIPS_REVISION_SCON_ROCIT; |
312 | break; | ||
307 | } | 313 | } |
308 | } | 314 | } |
309 | 315 | ||
@@ -418,6 +424,9 @@ void __init prom_init(void) | |||
418 | #ifdef CONFIG_SERIAL_8250_CONSOLE | 424 | #ifdef CONFIG_SERIAL_8250_CONSOLE |
419 | console_config(); | 425 | console_config(); |
420 | #endif | 426 | #endif |
427 | #ifdef CONFIG_MIPS_CMP | ||
428 | register_smp_ops(&cmp_smp_ops); | ||
429 | #endif | ||
421 | #ifdef CONFIG_MIPS_MT_SMP | 430 | #ifdef CONFIG_MIPS_MT_SMP |
422 | register_smp_ops(&vsmp_smp_ops); | 431 | register_smp_ops(&vsmp_smp_ops); |
423 | #endif | 432 | #endif |
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index dc272c188233..5e443bba5662 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c | |||
@@ -37,7 +37,7 @@ enum yamon_memtypes { | |||
37 | yamon_prom, | 37 | yamon_prom, |
38 | yamon_free, | 38 | yamon_free, |
39 | }; | 39 | }; |
40 | struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; | 40 | static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; |
41 | 41 | ||
42 | #ifdef DEBUG | 42 | #ifdef DEBUG |
43 | static char *mtypes[3] = { | 43 | static char *mtypes[3] = { |
@@ -50,7 +50,7 @@ static char *mtypes[3] = { | |||
50 | /* determined physical memory size, not overridden by command line args */ | 50 | /* determined physical memory size, not overridden by command line args */ |
51 | unsigned long physical_memsize = 0L; | 51 | unsigned long physical_memsize = 0L; |
52 | 52 | ||
53 | struct prom_pmemblock * __init prom_getmdesc(void) | 53 | static struct prom_pmemblock * __init prom_getmdesc(void) |
54 | { | 54 | { |
55 | char *memsize_str; | 55 | char *memsize_str; |
56 | unsigned int memsize; | 56 | unsigned int memsize; |
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index b50e0fc406ac..008fd82b5840 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c | |||
@@ -55,16 +55,36 @@ | |||
55 | unsigned long cpu_khz; | 55 | unsigned long cpu_khz; |
56 | 56 | ||
57 | static int mips_cpu_timer_irq; | 57 | static int mips_cpu_timer_irq; |
58 | static int mips_cpu_perf_irq; | ||
58 | extern int cp0_perfcount_irq; | 59 | extern int cp0_perfcount_irq; |
59 | 60 | ||
61 | DEFINE_PER_CPU(unsigned int, tickcount); | ||
62 | #define tickcount_this_cpu __get_cpu_var(tickcount) | ||
63 | static unsigned long ledbitmask; | ||
64 | |||
60 | static void mips_timer_dispatch(void) | 65 | static void mips_timer_dispatch(void) |
61 | { | 66 | { |
67 | #if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS) | ||
68 | /* | ||
69 | * Yes, this is very tacky, won't work as expected with SMTC and | ||
70 | * dyntick will break it, | ||
71 | * but it gives me a nice warm feeling during debug | ||
72 | */ | ||
73 | #define LEDBAR 0xbf000408 | ||
74 | if (tickcount_this_cpu++ >= HZ) { | ||
75 | tickcount_this_cpu = 0; | ||
76 | change_bit(smp_processor_id(), &ledbitmask); | ||
77 | smp_wmb(); /* Make sure every one else sees the change */ | ||
78 | /* This will pick up any recent changes made by other CPU's */ | ||
79 | *(unsigned int *)LEDBAR = ledbitmask; | ||
80 | } | ||
81 | #endif | ||
62 | do_IRQ(mips_cpu_timer_irq); | 82 | do_IRQ(mips_cpu_timer_irq); |
63 | } | 83 | } |
64 | 84 | ||
65 | static void mips_perf_dispatch(void) | 85 | static void mips_perf_dispatch(void) |
66 | { | 86 | { |
67 | do_IRQ(cp0_perfcount_irq); | 87 | do_IRQ(mips_cpu_perf_irq); |
68 | } | 88 | } |
69 | 89 | ||
70 | /* | 90 | /* |
@@ -127,21 +147,20 @@ unsigned long read_persistent_clock(void) | |||
127 | return mc146818_get_cmos_time(); | 147 | return mc146818_get_cmos_time(); |
128 | } | 148 | } |
129 | 149 | ||
130 | void __init plat_perf_setup(void) | 150 | static void __init plat_perf_setup(void) |
131 | { | 151 | { |
132 | cp0_perfcount_irq = -1; | ||
133 | |||
134 | #ifdef MSC01E_INT_BASE | 152 | #ifdef MSC01E_INT_BASE |
135 | if (cpu_has_veic) { | 153 | if (cpu_has_veic) { |
136 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); | 154 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); |
137 | cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | 155 | mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; |
138 | } else | 156 | } else |
139 | #endif | 157 | #endif |
140 | if (cp0_perfcount_irq >= 0) { | 158 | if (cp0_perfcount_irq >= 0) { |
141 | if (cpu_has_vint) | 159 | if (cpu_has_vint) |
142 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); | 160 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); |
161 | mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | ||
143 | #ifdef CONFIG_SMP | 162 | #ifdef CONFIG_SMP |
144 | set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); | 163 | set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq); |
145 | #endif | 164 | #endif |
146 | } | 165 | } |
147 | } | 166 | } |
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile index 931ca4600a63..8dc6e2ac4c03 100644 --- a/arch/mips/mips-boards/malta/Makefile +++ b/arch/mips/mips-boards/malta/Makefile | |||
@@ -22,6 +22,7 @@ | |||
22 | obj-y := malta_int.o malta_platform.o malta_setup.o | 22 | obj-y := malta_int.o malta_platform.o malta_setup.o |
23 | 23 | ||
24 | obj-$(CONFIG_MTD) += malta_mtd.o | 24 | obj-$(CONFIG_MTD) += malta_mtd.o |
25 | # FIXME FIXME FIXME | ||
25 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o | 26 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o |
26 | 27 | ||
27 | EXTRA_CFLAGS += -Werror | 28 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index dbe60eb55e29..8c495104b321 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
32 | #include <linux/random.h> | 32 | #include <linux/random.h> |
33 | 33 | ||
34 | #include <asm/traps.h> | ||
34 | #include <asm/i8259.h> | 35 | #include <asm/i8259.h> |
35 | #include <asm/irq_cpu.h> | 36 | #include <asm/irq_cpu.h> |
36 | #include <asm/irq_regs.h> | 37 | #include <asm/irq_regs.h> |
@@ -41,6 +42,14 @@ | |||
41 | #include <asm/mips-boards/generic.h> | 42 | #include <asm/mips-boards/generic.h> |
42 | #include <asm/mips-boards/msc01_pci.h> | 43 | #include <asm/mips-boards/msc01_pci.h> |
43 | #include <asm/msc01_ic.h> | 44 | #include <asm/msc01_ic.h> |
45 | #include <asm/gic.h> | ||
46 | #include <asm/gcmpregs.h> | ||
47 | |||
48 | int gcmp_present = -1; | ||
49 | int gic_present; | ||
50 | static unsigned long _msc01_biu_base; | ||
51 | static unsigned long _gcmp_base; | ||
52 | static unsigned int ipi_map[NR_CPUS]; | ||
44 | 53 | ||
45 | static DEFINE_SPINLOCK(mips_irq_lock); | 54 | static DEFINE_SPINLOCK(mips_irq_lock); |
46 | 55 | ||
@@ -121,6 +130,17 @@ static void malta_hw0_irqdispatch(void) | |||
121 | do_IRQ(MALTA_INT_BASE + irq); | 130 | do_IRQ(MALTA_INT_BASE + irq); |
122 | } | 131 | } |
123 | 132 | ||
133 | static void malta_ipi_irqdispatch(void) | ||
134 | { | ||
135 | int irq; | ||
136 | |||
137 | irq = gic_get_int(); | ||
138 | if (irq < 0) | ||
139 | return; /* interrupt has already been cleared */ | ||
140 | |||
141 | do_IRQ(MIPS_GIC_IRQ_BASE + irq); | ||
142 | } | ||
143 | |||
124 | static void corehi_irqdispatch(void) | 144 | static void corehi_irqdispatch(void) |
125 | { | 145 | { |
126 | unsigned int intedge, intsteer, pcicmd, pcibadaddr; | 146 | unsigned int intedge, intsteer, pcicmd, pcibadaddr; |
@@ -257,12 +277,61 @@ asmlinkage void plat_irq_dispatch(void) | |||
257 | 277 | ||
258 | if (irq == MIPSCPU_INT_I8259A) | 278 | if (irq == MIPSCPU_INT_I8259A) |
259 | malta_hw0_irqdispatch(); | 279 | malta_hw0_irqdispatch(); |
280 | else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()])) | ||
281 | malta_ipi_irqdispatch(); | ||
260 | else if (irq >= 0) | 282 | else if (irq >= 0) |
261 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); | 283 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); |
262 | else | 284 | else |
263 | spurious_interrupt(); | 285 | spurious_interrupt(); |
264 | } | 286 | } |
265 | 287 | ||
288 | #ifdef CONFIG_MIPS_MT_SMP | ||
289 | |||
290 | |||
291 | #define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3 | ||
292 | #define GIC_MIPS_CPU_IPI_CALL_IRQ 4 | ||
293 | |||
294 | #define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */ | ||
295 | #define C_RESCHED C_SW0 | ||
296 | #define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */ | ||
297 | #define C_CALL C_SW1 | ||
298 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | ||
299 | |||
300 | static void ipi_resched_dispatch(void) | ||
301 | { | ||
302 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | ||
303 | } | ||
304 | |||
305 | static void ipi_call_dispatch(void) | ||
306 | { | ||
307 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | ||
308 | } | ||
309 | |||
310 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
311 | { | ||
312 | return IRQ_HANDLED; | ||
313 | } | ||
314 | |||
315 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
316 | { | ||
317 | smp_call_function_interrupt(); | ||
318 | |||
319 | return IRQ_HANDLED; | ||
320 | } | ||
321 | |||
322 | static struct irqaction irq_resched = { | ||
323 | .handler = ipi_resched_interrupt, | ||
324 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
325 | .name = "IPI_resched" | ||
326 | }; | ||
327 | |||
328 | static struct irqaction irq_call = { | ||
329 | .handler = ipi_call_interrupt, | ||
330 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
331 | .name = "IPI_call" | ||
332 | }; | ||
333 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
334 | |||
266 | static struct irqaction i8259irq = { | 335 | static struct irqaction i8259irq = { |
267 | .handler = no_action, | 336 | .handler = no_action, |
268 | .name = "XT-PIC cascade" | 337 | .name = "XT-PIC cascade" |
@@ -273,13 +342,13 @@ static struct irqaction corehi_irqaction = { | |||
273 | .name = "CoreHi" | 342 | .name = "CoreHi" |
274 | }; | 343 | }; |
275 | 344 | ||
276 | msc_irqmap_t __initdata msc_irqmap[] = { | 345 | static msc_irqmap_t __initdata msc_irqmap[] = { |
277 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, | 346 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, |
278 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, | 347 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, |
279 | }; | 348 | }; |
280 | int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); | 349 | static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); |
281 | 350 | ||
282 | msc_irqmap_t __initdata msc_eicirqmap[] = { | 351 | static msc_irqmap_t __initdata msc_eicirqmap[] = { |
283 | {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, | 352 | {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, |
284 | {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, | 353 | {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, |
285 | {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, | 354 | {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, |
@@ -291,15 +360,90 @@ msc_irqmap_t __initdata msc_eicirqmap[] = { | |||
291 | {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, | 360 | {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, |
292 | {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} | 361 | {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} |
293 | }; | 362 | }; |
294 | int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); | 363 | |
364 | static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); | ||
365 | |||
366 | /* | ||
367 | * This GIC specific tabular array defines the association between External | ||
368 | * Interrupts and CPUs/Core Interrupts. The nature of the External | ||
369 | * Interrupts is also defined here - polarity/trigger. | ||
370 | */ | ||
371 | static struct gic_intr_map gic_intr_map[] = { | ||
372 | { GIC_EXT_INTR(0), X, X, X, X, 0 }, | ||
373 | { GIC_EXT_INTR(1), X, X, X, X, 0 }, | ||
374 | { GIC_EXT_INTR(2), X, X, X, X, 0 }, | ||
375 | { GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
376 | { GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
377 | { GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
378 | { GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
379 | { GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
380 | { GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
381 | { GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
382 | { GIC_EXT_INTR(10), X, X, X, X, 0 }, | ||
383 | { GIC_EXT_INTR(11), X, X, X, X, 0 }, | ||
384 | { GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
385 | { GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
386 | { GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 }, | ||
387 | { GIC_EXT_INTR(15), X, X, X, X, 0 }, | ||
388 | { GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
389 | { GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
390 | { GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
391 | { GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
392 | { GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
393 | { GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
394 | { GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
395 | { GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 }, | ||
396 | }; | ||
397 | |||
398 | /* | ||
399 | * GCMP needs to be detected before any SMP initialisation | ||
400 | */ | ||
401 | int __init gcmp_probe(unsigned long addr, unsigned long size) | ||
402 | { | ||
403 | if (gcmp_present >= 0) | ||
404 | return gcmp_present; | ||
405 | |||
406 | _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); | ||
407 | _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); | ||
408 | gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR; | ||
409 | |||
410 | if (gcmp_present) | ||
411 | printk(KERN_DEBUG "GCMP present\n"); | ||
412 | return gcmp_present; | ||
413 | } | ||
414 | |||
415 | void __init fill_ipi_map(void) | ||
416 | { | ||
417 | int i; | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) { | ||
420 | if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X)) | ||
421 | ipi_map[gic_intr_map[i].cpunum] |= | ||
422 | (1 << (gic_intr_map[i].pin + 2)); | ||
423 | } | ||
424 | } | ||
295 | 425 | ||
296 | void __init arch_init_irq(void) | 426 | void __init arch_init_irq(void) |
297 | { | 427 | { |
428 | int gic_present, gcmp_present; | ||
429 | |||
298 | init_i8259_irqs(); | 430 | init_i8259_irqs(); |
299 | 431 | ||
300 | if (!cpu_has_veic) | 432 | if (!cpu_has_veic) |
301 | mips_cpu_irq_init(); | 433 | mips_cpu_irq_init(); |
302 | 434 | ||
435 | gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); | ||
436 | if (gcmp_present) { | ||
437 | GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK; | ||
438 | gic_present = 1; | ||
439 | } else { | ||
440 | _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); | ||
441 | gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) & | ||
442 | MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF; | ||
443 | } | ||
444 | if (gic_present) | ||
445 | printk(KERN_DEBUG "GIC present\n"); | ||
446 | |||
303 | switch (mips_revision_sconid) { | 447 | switch (mips_revision_sconid) { |
304 | case MIPS_REVISION_SCON_SOCIT: | 448 | case MIPS_REVISION_SCON_SOCIT: |
305 | case MIPS_REVISION_SCON_ROCIT: | 449 | case MIPS_REVISION_SCON_ROCIT: |
@@ -360,4 +504,206 @@ void __init arch_init_irq(void) | |||
360 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, | 504 | setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, |
361 | &corehi_irqaction); | 505 | &corehi_irqaction); |
362 | } | 506 | } |
507 | |||
508 | #if defined(CONFIG_MIPS_MT_SMP) | ||
509 | if (gic_present) { | ||
510 | /* FIXME */ | ||
511 | int i; | ||
512 | struct { | ||
513 | unsigned int resched; | ||
514 | unsigned int call; | ||
515 | } ipiirq[] = { | ||
516 | { | ||
517 | .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0, | ||
518 | .call = GIC_IPI_EXT_INTR_CALLFNC_VPE0}, | ||
519 | { | ||
520 | .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1, | ||
521 | .call = GIC_IPI_EXT_INTR_CALLFNC_VPE1 | ||
522 | }, { | ||
523 | .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2, | ||
524 | .call = GIC_IPI_EXT_INTR_CALLFNC_VPE2 | ||
525 | }, { | ||
526 | .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3, | ||
527 | .call = GIC_IPI_EXT_INTR_CALLFNC_VPE3 | ||
528 | } | ||
529 | }; | ||
530 | #define NIPI (sizeof(ipiirq)/sizeof(ipiirq[0])) | ||
531 | fill_ipi_map(); | ||
532 | gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); | ||
533 | if (!gcmp_present) { | ||
534 | /* Enable the GIC */ | ||
535 | i = REG(_msc01_biu_base, MSC01_SC_CFG); | ||
536 | REG(_msc01_biu_base, MSC01_SC_CFG) = | ||
537 | (i | (0x1 << MSC01_SC_CFG_GICENA_SHF)); | ||
538 | pr_debug("GIC Enabled\n"); | ||
539 | } | ||
540 | |||
541 | /* set up ipi interrupts */ | ||
542 | if (cpu_has_vint) { | ||
543 | set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch); | ||
544 | set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch); | ||
545 | } | ||
546 | /* Argh.. this really needs sorting out.. */ | ||
547 | printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status()); | ||
548 | write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4); | ||
549 | printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status()); | ||
550 | write_c0_status(0x1100dc00); | ||
551 | printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status()); | ||
552 | for (i = 0; i < NIPI; i++) { | ||
553 | setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched); | ||
554 | setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call); | ||
555 | |||
556 | set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq); | ||
557 | set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq); | ||
558 | } | ||
559 | } else { | ||
560 | /* set up ipi interrupts */ | ||
561 | if (cpu_has_veic) { | ||
562 | set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch); | ||
563 | set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch); | ||
564 | cpu_ipi_resched_irq = MSC01E_INT_SW0; | ||
565 | cpu_ipi_call_irq = MSC01E_INT_SW1; | ||
566 | } else { | ||
567 | if (cpu_has_vint) { | ||
568 | set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); | ||
569 | set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); | ||
570 | } | ||
571 | cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; | ||
572 | cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; | ||
573 | } | ||
574 | |||
575 | setup_irq(cpu_ipi_resched_irq, &irq_resched); | ||
576 | setup_irq(cpu_ipi_call_irq, &irq_call); | ||
577 | |||
578 | set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); | ||
579 | set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); | ||
580 | } | ||
581 | #endif | ||
582 | } | ||
583 | |||
584 | void malta_be_init(void) | ||
585 | { | ||
586 | if (gcmp_present) { | ||
587 | /* Could change CM error mask register */ | ||
588 | } | ||
589 | } | ||
590 | |||
591 | |||
592 | static char *tr[8] = { | ||
593 | "mem", "gcr", "gic", "mmio", | ||
594 | "0x04", "0x05", "0x06", "0x07" | ||
595 | }; | ||
596 | |||
597 | static char *mcmd[32] = { | ||
598 | [0x00] = "0x00", | ||
599 | [0x01] = "Legacy Write", | ||
600 | [0x02] = "Legacy Read", | ||
601 | [0x03] = "0x03", | ||
602 | [0x04] = "0x04", | ||
603 | [0x05] = "0x05", | ||
604 | [0x06] = "0x06", | ||
605 | [0x07] = "0x07", | ||
606 | [0x08] = "Coherent Read Own", | ||
607 | [0x09] = "Coherent Read Share", | ||
608 | [0x0a] = "Coherent Read Discard", | ||
609 | [0x0b] = "Coherent Ready Share Always", | ||
610 | [0x0c] = "Coherent Upgrade", | ||
611 | [0x0d] = "Coherent Writeback", | ||
612 | [0x0e] = "0x0e", | ||
613 | [0x0f] = "0x0f", | ||
614 | [0x10] = "Coherent Copyback", | ||
615 | [0x11] = "Coherent Copyback Invalidate", | ||
616 | [0x12] = "Coherent Invalidate", | ||
617 | [0x13] = "Coherent Write Invalidate", | ||
618 | [0x14] = "Coherent Completion Sync", | ||
619 | [0x15] = "0x15", | ||
620 | [0x16] = "0x16", | ||
621 | [0x17] = "0x17", | ||
622 | [0x18] = "0x18", | ||
623 | [0x19] = "0x19", | ||
624 | [0x1a] = "0x1a", | ||
625 | [0x1b] = "0x1b", | ||
626 | [0x1c] = "0x1c", | ||
627 | [0x1d] = "0x1d", | ||
628 | [0x1e] = "0x1e", | ||
629 | [0x1f] = "0x1f" | ||
630 | }; | ||
631 | |||
632 | static char *core[8] = { | ||
633 | "Invalid/OK", "Invalid/Data", | ||
634 | "Shared/OK", "Shared/Data", | ||
635 | "Modified/OK", "Modified/Data", | ||
636 | "Exclusive/OK", "Exclusive/Data" | ||
637 | }; | ||
638 | |||
639 | static char *causes[32] = { | ||
640 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", | ||
641 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", | ||
642 | "0x08", "0x09", "0x0a", "0x0b", | ||
643 | "0x0c", "0x0d", "0x0e", "0x0f", | ||
644 | "0x10", "0x11", "0x12", "0x13", | ||
645 | "0x14", "0x15", "0x16", "INTVN_WR_ERR", | ||
646 | "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", | ||
647 | "0x1c", "0x1d", "0x1e", "0x1f" | ||
648 | }; | ||
649 | |||
650 | int malta_be_handler(struct pt_regs *regs, int is_fixup) | ||
651 | { | ||
652 | /* This duplicates the handling in do_be which seems wrong */ | ||
653 | int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; | ||
654 | |||
655 | if (gcmp_present) { | ||
656 | unsigned long cm_error = GCMPGCB(GCMEC); | ||
657 | unsigned long cm_addr = GCMPGCB(GCMEA); | ||
658 | unsigned long cm_other = GCMPGCB(GCMEO); | ||
659 | unsigned long cause, ocause; | ||
660 | char buf[256]; | ||
661 | |||
662 | cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK); | ||
663 | if (cause != 0) { | ||
664 | cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF; | ||
665 | if (cause < 16) { | ||
666 | unsigned long cca_bits = (cm_error >> 15) & 7; | ||
667 | unsigned long tr_bits = (cm_error >> 12) & 7; | ||
668 | unsigned long mcmd_bits = (cm_error >> 7) & 0x1f; | ||
669 | unsigned long stag_bits = (cm_error >> 3) & 15; | ||
670 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
671 | |||
672 | snprintf(buf, sizeof(buf), | ||
673 | "CCA=%lu TR=%s MCmd=%s STag=%lu " | ||
674 | "SPort=%lu\n", | ||
675 | cca_bits, tr[tr_bits], mcmd[mcmd_bits], | ||
676 | stag_bits, sport_bits); | ||
677 | } else { | ||
678 | /* glob state & sresp together */ | ||
679 | unsigned long c3_bits = (cm_error >> 18) & 7; | ||
680 | unsigned long c2_bits = (cm_error >> 15) & 7; | ||
681 | unsigned long c1_bits = (cm_error >> 12) & 7; | ||
682 | unsigned long c0_bits = (cm_error >> 9) & 7; | ||
683 | unsigned long sc_bit = (cm_error >> 8) & 1; | ||
684 | unsigned long mcmd_bits = (cm_error >> 3) & 0x1f; | ||
685 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
686 | snprintf(buf, sizeof(buf), | ||
687 | "C3=%s C2=%s C1=%s C0=%s SC=%s " | ||
688 | "MCmd=%s SPort=%lu\n", | ||
689 | core[c3_bits], core[c2_bits], | ||
690 | core[c1_bits], core[c0_bits], | ||
691 | sc_bit ? "True" : "False", | ||
692 | mcmd[mcmd_bits], sport_bits); | ||
693 | } | ||
694 | |||
695 | ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >> | ||
696 | GCMP_GCB_GMEO_ERROR_2ND_SHF; | ||
697 | |||
698 | printk("CM_ERROR=%08lx %s <%s>\n", cm_error, | ||
699 | causes[cause], buf); | ||
700 | printk("CM_ADDR =%08lx\n", cm_addr); | ||
701 | printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); | ||
702 | |||
703 | /* reprime cause register */ | ||
704 | GCMPGCB(GCMEC) = 0; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | return retval; | ||
363 | } | 709 | } |
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 2cd8f5734b36..e7cad54936ca 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Carsten Langgaard, carstenl@mips.com | 2 | * Carsten Langgaard, carstenl@mips.com |
3 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | 3 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. |
4 | * Copyright (C) Dmitri Vorobiev | 4 | * Copyright (C) 2008 Dmitri Vorobiev |
5 | * | 5 | * |
6 | * This program is free software; you can distribute it and/or modify it | 6 | * This program is free software; you can distribute it and/or modify it |
7 | * under the terms of the GNU General Public License (Version 2) as | 7 | * under the terms of the GNU General Public License (Version 2) as |
@@ -36,7 +36,10 @@ | |||
36 | #include <linux/console.h> | 36 | #include <linux/console.h> |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | struct resource standard_io_resources[] = { | 39 | extern void malta_be_init(void); |
40 | extern int malta_be_handler(struct pt_regs *regs, int is_fixup); | ||
41 | |||
42 | static struct resource standard_io_resources[] = { | ||
40 | { | 43 | { |
41 | .name = "dma1", | 44 | .name = "dma1", |
42 | .start = 0x00, | 45 | .start = 0x00, |
@@ -220,4 +223,7 @@ void __init plat_mem_setup(void) | |||
220 | screen_info_setup(); | 223 | screen_info_setup(); |
221 | #endif | 224 | #endif |
222 | mips_reboot_setup(); | 225 | mips_reboot_setup(); |
226 | |||
227 | board_be_init = malta_be_init; | ||
228 | board_be_handler = malta_be_handler; | ||
223 | } | 229 | } |
diff --git a/arch/mips/mipssim/sim_setup.c b/arch/mips/mipssim/sim_setup.c index d49fe73426b7..7c7148ef2646 100644 --- a/arch/mips/mipssim/sim_setup.c +++ b/arch/mips/mipssim/sim_setup.c | |||
@@ -39,9 +39,6 @@ | |||
39 | static void __init serial_init(void); | 39 | static void __init serial_init(void); |
40 | unsigned int _isbonito = 0; | 40 | unsigned int _isbonito = 0; |
41 | 41 | ||
42 | extern void __init sanitize_tlb_entries(void); | ||
43 | |||
44 | |||
45 | const char *get_system_type(void) | 42 | const char *get_system_type(void) |
46 | { | 43 | { |
47 | return "MIPSsim"; | 44 | return "MIPSsim"; |
@@ -55,9 +52,6 @@ void __init plat_mem_setup(void) | |||
55 | 52 | ||
56 | pr_info("Linux started...\n"); | 53 | pr_info("Linux started...\n"); |
57 | 54 | ||
58 | #ifdef CONFIG_MIPS_MT_SMP | ||
59 | sanitize_tlb_entries(); | ||
60 | #endif | ||
61 | } | 55 | } |
62 | 56 | ||
63 | extern struct plat_smp_ops ssmtc_smp_ops; | 57 | extern struct plat_smp_ops ssmtc_smp_ops; |
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index c6f832e0f41c..48731020ca0e 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile | |||
@@ -4,30 +4,29 @@ | |||
4 | 4 | ||
5 | obj-y += cache.o dma-default.o extable.o fault.o \ | 5 | obj-y += cache.o dma-default.o extable.o fault.o \ |
6 | init.o pgtable.o tlbex.o tlbex-fault.o \ | 6 | init.o pgtable.o tlbex.o tlbex-fault.o \ |
7 | uasm.o | 7 | uasm.o page.o |
8 | 8 | ||
9 | obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o | 9 | obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o |
10 | obj-$(CONFIG_64BIT) += pgtable-64.o | 10 | obj-$(CONFIG_64BIT) += pgtable-64.o |
11 | obj-$(CONFIG_HIGHMEM) += highmem.o | 11 | obj-$(CONFIG_HIGHMEM) += highmem.o |
12 | 12 | ||
13 | obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 13 | obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o tlb-r4k.o |
14 | obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 14 | obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o tlb-r4k.o |
15 | obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 15 | obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o tlb-r4k.o |
16 | obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 16 | obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o tlb-r4k.o |
17 | obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 17 | obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o tlb-r4k.o |
18 | obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o pg-r4k.o | 18 | obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o |
19 | obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 19 | obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o tlb-r4k.o |
20 | obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 20 | obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o tlb-r4k.o |
21 | obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 21 | obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o tlb-r4k.o |
22 | obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 22 | obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o tlb-r4k.o |
23 | obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r8k.o | 23 | obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o tlb-r8k.o |
24 | obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 24 | obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o tlb-r4k.o |
25 | obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 25 | obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o tlb-r4k.o |
26 | obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o pg-sb1.o \ | 26 | obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o tlb-r4k.o |
27 | tlb-r4k.o | 27 | obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o |
28 | obj-$(CONFIG_CPU_TX39XX) += c-tx39.o pg-r4k.o tlb-r3k.o | 28 | obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o |
29 | obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | 29 | obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o |
30 | obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o | ||
31 | 30 | ||
32 | obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o | 31 | obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o |
33 | obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o | 32 | obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o |
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 77aefb4ebedd..643c8bcffff3 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/linkage.h> | 14 | #include <linux/linkage.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/module.h> | ||
17 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
18 | 19 | ||
19 | #include <asm/bcache.h> | 20 | #include <asm/bcache.h> |
@@ -53,6 +54,12 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info, | |||
53 | preempt_enable(); | 54 | preempt_enable(); |
54 | } | 55 | } |
55 | 56 | ||
57 | #if defined(CONFIG_MIPS_CMP) | ||
58 | #define cpu_has_safe_index_cacheops 0 | ||
59 | #else | ||
60 | #define cpu_has_safe_index_cacheops 1 | ||
61 | #endif | ||
62 | |||
56 | /* | 63 | /* |
57 | * Must die. | 64 | * Must die. |
58 | */ | 65 | */ |
@@ -481,6 +488,8 @@ static inline void local_r4k_flush_cache_page(void *args) | |||
481 | 488 | ||
482 | if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { | 489 | if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { |
483 | r4k_blast_dcache_page(addr); | 490 | r4k_blast_dcache_page(addr); |
491 | if (exec && !cpu_icache_snoops_remote_store) | ||
492 | r4k_blast_scache_page(addr); | ||
484 | } | 493 | } |
485 | if (exec) { | 494 | if (exec) { |
486 | if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { | 495 | if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { |
@@ -583,7 +592,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) | |||
583 | * subset property so we have to flush the primary caches | 592 | * subset property so we have to flush the primary caches |
584 | * explicitly | 593 | * explicitly |
585 | */ | 594 | */ |
586 | if (size >= dcache_size) { | 595 | if (cpu_has_safe_index_cacheops && size >= dcache_size) { |
587 | r4k_blast_dcache(); | 596 | r4k_blast_dcache(); |
588 | } else { | 597 | } else { |
589 | R4600_HIT_CACHEOP_WAR_IMPL; | 598 | R4600_HIT_CACHEOP_WAR_IMPL; |
@@ -606,7 +615,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) | |||
606 | return; | 615 | return; |
607 | } | 616 | } |
608 | 617 | ||
609 | if (size >= dcache_size) { | 618 | if (cpu_has_safe_index_cacheops && size >= dcache_size) { |
610 | r4k_blast_dcache(); | 619 | r4k_blast_dcache(); |
611 | } else { | 620 | } else { |
612 | R4600_HIT_CACHEOP_WAR_IMPL; | 621 | R4600_HIT_CACHEOP_WAR_IMPL; |
@@ -968,6 +977,7 @@ static void __cpuinit probe_pcache(void) | |||
968 | case CPU_24K: | 977 | case CPU_24K: |
969 | case CPU_34K: | 978 | case CPU_34K: |
970 | case CPU_74K: | 979 | case CPU_74K: |
980 | case CPU_1004K: | ||
971 | if ((read_c0_config7() & (1 << 16))) { | 981 | if ((read_c0_config7() & (1 << 16))) { |
972 | /* effectively physically indexed dcache, | 982 | /* effectively physically indexed dcache, |
973 | thus no virtual aliases. */ | 983 | thus no virtual aliases. */ |
@@ -1216,9 +1226,25 @@ void au1x00_fixup_config_od(void) | |||
1216 | } | 1226 | } |
1217 | } | 1227 | } |
1218 | 1228 | ||
1229 | static int __cpuinitdata cca = -1; | ||
1230 | |||
1231 | static int __init cca_setup(char *str) | ||
1232 | { | ||
1233 | get_option(&str, &cca); | ||
1234 | |||
1235 | return 1; | ||
1236 | } | ||
1237 | |||
1238 | __setup("cca=", cca_setup); | ||
1239 | |||
1219 | static void __cpuinit coherency_setup(void) | 1240 | static void __cpuinit coherency_setup(void) |
1220 | { | 1241 | { |
1221 | change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); | 1242 | if (cca < 0 || cca > 7) |
1243 | cca = read_c0_config() & CONF_CM_CMASK; | ||
1244 | _page_cachable_default = cca << _CACHE_SHIFT; | ||
1245 | |||
1246 | pr_debug("Using cache attribute %d\n", cca); | ||
1247 | change_c0_config(CONF_CM_CMASK, cca); | ||
1222 | 1248 | ||
1223 | /* | 1249 | /* |
1224 | * c0_status.cu=0 specifies that updates by the sc instruction use | 1250 | * c0_status.cu=0 specifies that updates by the sc instruction use |
@@ -1248,6 +1274,20 @@ static void __cpuinit coherency_setup(void) | |||
1248 | } | 1274 | } |
1249 | } | 1275 | } |
1250 | 1276 | ||
1277 | #if defined(CONFIG_DMA_NONCOHERENT) | ||
1278 | |||
1279 | static int __cpuinitdata coherentio; | ||
1280 | |||
1281 | static int __init setcoherentio(char *str) | ||
1282 | { | ||
1283 | coherentio = 1; | ||
1284 | |||
1285 | return 1; | ||
1286 | } | ||
1287 | |||
1288 | __setup("coherentio", setcoherentio); | ||
1289 | #endif | ||
1290 | |||
1251 | void __cpuinit r4k_cache_init(void) | 1291 | void __cpuinit r4k_cache_init(void) |
1252 | { | 1292 | { |
1253 | extern void build_clear_page(void); | 1293 | extern void build_clear_page(void); |
@@ -1307,14 +1347,22 @@ void __cpuinit r4k_cache_init(void) | |||
1307 | flush_data_cache_page = r4k_flush_data_cache_page; | 1347 | flush_data_cache_page = r4k_flush_data_cache_page; |
1308 | flush_icache_range = r4k_flush_icache_range; | 1348 | flush_icache_range = r4k_flush_icache_range; |
1309 | 1349 | ||
1310 | #ifdef CONFIG_DMA_NONCOHERENT | 1350 | #if defined(CONFIG_DMA_NONCOHERENT) |
1311 | _dma_cache_wback_inv = r4k_dma_cache_wback_inv; | 1351 | if (coherentio) { |
1312 | _dma_cache_wback = r4k_dma_cache_wback_inv; | 1352 | _dma_cache_wback_inv = (void *)cache_noop; |
1313 | _dma_cache_inv = r4k_dma_cache_inv; | 1353 | _dma_cache_wback = (void *)cache_noop; |
1354 | _dma_cache_inv = (void *)cache_noop; | ||
1355 | } else { | ||
1356 | _dma_cache_wback_inv = r4k_dma_cache_wback_inv; | ||
1357 | _dma_cache_wback = r4k_dma_cache_wback_inv; | ||
1358 | _dma_cache_inv = r4k_dma_cache_inv; | ||
1359 | } | ||
1314 | #endif | 1360 | #endif |
1315 | 1361 | ||
1316 | build_clear_page(); | 1362 | build_clear_page(); |
1317 | build_copy_page(); | 1363 | build_copy_page(); |
1364 | #if !defined(CONFIG_MIPS_CMP) | ||
1318 | local_r4k___flush_cache_all(NULL); | 1365 | local_r4k___flush_cache_all(NULL); |
1366 | #endif | ||
1319 | coherency_setup(); | 1367 | coherency_setup(); |
1320 | } | 1368 | } |
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index f5903679ee6a..034e8506f6ea 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c | |||
@@ -130,8 +130,28 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, | |||
130 | } | 130 | } |
131 | } | 131 | } |
132 | 132 | ||
133 | static char cache_panic[] __cpuinitdata = | 133 | unsigned long _page_cachable_default; |
134 | "Yeee, unsupported cache architecture."; | 134 | EXPORT_SYMBOL_GPL(_page_cachable_default); |
135 | |||
136 | static inline void setup_protection_map(void) | ||
137 | { | ||
138 | protection_map[0] = PAGE_NONE; | ||
139 | protection_map[1] = PAGE_READONLY; | ||
140 | protection_map[2] = PAGE_COPY; | ||
141 | protection_map[3] = PAGE_COPY; | ||
142 | protection_map[4] = PAGE_READONLY; | ||
143 | protection_map[5] = PAGE_READONLY; | ||
144 | protection_map[6] = PAGE_COPY; | ||
145 | protection_map[7] = PAGE_COPY; | ||
146 | protection_map[8] = PAGE_NONE; | ||
147 | protection_map[9] = PAGE_READONLY; | ||
148 | protection_map[10] = PAGE_SHARED; | ||
149 | protection_map[11] = PAGE_SHARED; | ||
150 | protection_map[12] = PAGE_READONLY; | ||
151 | protection_map[13] = PAGE_READONLY; | ||
152 | protection_map[14] = PAGE_SHARED; | ||
153 | protection_map[15] = PAGE_SHARED; | ||
154 | } | ||
135 | 155 | ||
136 | void __devinit cpu_cache_init(void) | 156 | void __devinit cpu_cache_init(void) |
137 | { | 157 | { |
@@ -139,34 +159,29 @@ void __devinit cpu_cache_init(void) | |||
139 | extern void __weak r3k_cache_init(void); | 159 | extern void __weak r3k_cache_init(void); |
140 | 160 | ||
141 | r3k_cache_init(); | 161 | r3k_cache_init(); |
142 | return; | ||
143 | } | 162 | } |
144 | if (cpu_has_6k_cache) { | 163 | if (cpu_has_6k_cache) { |
145 | extern void __weak r6k_cache_init(void); | 164 | extern void __weak r6k_cache_init(void); |
146 | 165 | ||
147 | r6k_cache_init(); | 166 | r6k_cache_init(); |
148 | return; | ||
149 | } | 167 | } |
150 | if (cpu_has_4k_cache) { | 168 | if (cpu_has_4k_cache) { |
151 | extern void __weak r4k_cache_init(void); | 169 | extern void __weak r4k_cache_init(void); |
152 | 170 | ||
153 | r4k_cache_init(); | 171 | r4k_cache_init(); |
154 | return; | ||
155 | } | 172 | } |
156 | if (cpu_has_8k_cache) { | 173 | if (cpu_has_8k_cache) { |
157 | extern void __weak r8k_cache_init(void); | 174 | extern void __weak r8k_cache_init(void); |
158 | 175 | ||
159 | r8k_cache_init(); | 176 | r8k_cache_init(); |
160 | return; | ||
161 | } | 177 | } |
162 | if (cpu_has_tx39_cache) { | 178 | if (cpu_has_tx39_cache) { |
163 | extern void __weak tx39_cache_init(void); | 179 | extern void __weak tx39_cache_init(void); |
164 | 180 | ||
165 | tx39_cache_init(); | 181 | tx39_cache_init(); |
166 | return; | ||
167 | } | 182 | } |
168 | 183 | ||
169 | panic(cache_panic); | 184 | setup_protection_map(); |
170 | } | 185 | } |
171 | 186 | ||
172 | int __weak __uncached_access(struct file *file, unsigned long addr) | 187 | int __weak __uncached_access(struct file *file, unsigned long addr) |
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index c7aed133d11d..ecd562d2c348 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c | |||
@@ -142,7 +142,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) | |||
142 | #endif | 142 | #endif |
143 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); | 143 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); |
144 | pte = mk_pte(page, PAGE_KERNEL); | 144 | pte = mk_pte(page, PAGE_KERNEL); |
145 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) | 145 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) |
146 | entrylo = pte.pte_high; | 146 | entrylo = pte.pte_high; |
147 | #else | 147 | #else |
148 | entrylo = pte_val(pte) >> 6; | 148 | entrylo = pte_val(pte) >> 6; |
@@ -221,7 +221,7 @@ void copy_user_highpage(struct page *to, struct page *from, | |||
221 | copy_page(vto, vfrom); | 221 | copy_page(vto, vfrom); |
222 | kunmap_atomic(vfrom, KM_USER0); | 222 | kunmap_atomic(vfrom, KM_USER0); |
223 | } | 223 | } |
224 | if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || | 224 | if ((!cpu_has_ic_fills_f_dc) || |
225 | pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) | 225 | pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) |
226 | flush_data_cache_page((unsigned long)vto); | 226 | flush_data_cache_page((unsigned long)vto); |
227 | kunmap_atomic(vto, KM_USER1); | 227 | kunmap_atomic(vto, KM_USER1); |
@@ -229,8 +229,6 @@ void copy_user_highpage(struct page *to, struct page *from, | |||
229 | smp_wmb(); | 229 | smp_wmb(); |
230 | } | 230 | } |
231 | 231 | ||
232 | EXPORT_SYMBOL(copy_user_highpage); | ||
233 | |||
234 | void copy_to_user_page(struct vm_area_struct *vma, | 232 | void copy_to_user_page(struct vm_area_struct *vma, |
235 | struct page *page, unsigned long vaddr, void *dst, const void *src, | 233 | struct page *page, unsigned long vaddr, void *dst, const void *src, |
236 | unsigned long len) | 234 | unsigned long len) |
@@ -249,8 +247,6 @@ void copy_to_user_page(struct vm_area_struct *vma, | |||
249 | flush_cache_page(vma, vaddr, page_to_pfn(page)); | 247 | flush_cache_page(vma, vaddr, page_to_pfn(page)); |
250 | } | 248 | } |
251 | 249 | ||
252 | EXPORT_SYMBOL(copy_to_user_page); | ||
253 | |||
254 | void copy_from_user_page(struct vm_area_struct *vma, | 250 | void copy_from_user_page(struct vm_area_struct *vma, |
255 | struct page *page, unsigned long vaddr, void *dst, const void *src, | 251 | struct page *page, unsigned long vaddr, void *dst, const void *src, |
256 | unsigned long len) | 252 | unsigned long len) |
@@ -267,9 +263,6 @@ void copy_from_user_page(struct vm_area_struct *vma, | |||
267 | } | 263 | } |
268 | } | 264 | } |
269 | 265 | ||
270 | EXPORT_SYMBOL(copy_from_user_page); | ||
271 | |||
272 | |||
273 | #ifdef CONFIG_HIGHMEM | 266 | #ifdef CONFIG_HIGHMEM |
274 | unsigned long highstart_pfn, highend_pfn; | 267 | unsigned long highstart_pfn, highend_pfn; |
275 | 268 | ||
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c new file mode 100644 index 000000000000..d827d6144369 --- /dev/null +++ b/arch/mips/mm/page.c | |||
@@ -0,0 +1,684 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) | ||
7 | * Copyright (C) 2007 Maciej W. Rozycki | ||
8 | * Copyright (C) 2008 Thiemo Seufer | ||
9 | */ | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | |||
17 | #include <asm/bugs.h> | ||
18 | #include <asm/cacheops.h> | ||
19 | #include <asm/inst.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/pgtable.h> | ||
23 | #include <asm/prefetch.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/bootinfo.h> | ||
26 | #include <asm/mipsregs.h> | ||
27 | #include <asm/mmu_context.h> | ||
28 | #include <asm/cpu.h> | ||
29 | #include <asm/war.h> | ||
30 | |||
31 | #ifdef CONFIG_SIBYTE_DMA_PAGEOPS | ||
32 | #include <asm/sibyte/sb1250.h> | ||
33 | #include <asm/sibyte/sb1250_regs.h> | ||
34 | #include <asm/sibyte/sb1250_dma.h> | ||
35 | #endif | ||
36 | |||
37 | #include "uasm.h" | ||
38 | |||
39 | /* Registers used in the assembled routines. */ | ||
40 | #define ZERO 0 | ||
41 | #define AT 2 | ||
42 | #define A0 4 | ||
43 | #define A1 5 | ||
44 | #define A2 6 | ||
45 | #define T0 8 | ||
46 | #define T1 9 | ||
47 | #define T2 10 | ||
48 | #define T3 11 | ||
49 | #define T9 25 | ||
50 | #define RA 31 | ||
51 | |||
52 | /* Handle labels (which must be positive integers). */ | ||
53 | enum label_id { | ||
54 | label_clear_nopref = 1, | ||
55 | label_clear_pref, | ||
56 | label_copy_nopref, | ||
57 | label_copy_pref_both, | ||
58 | label_copy_pref_store, | ||
59 | }; | ||
60 | |||
61 | UASM_L_LA(_clear_nopref) | ||
62 | UASM_L_LA(_clear_pref) | ||
63 | UASM_L_LA(_copy_nopref) | ||
64 | UASM_L_LA(_copy_pref_both) | ||
65 | UASM_L_LA(_copy_pref_store) | ||
66 | |||
67 | /* We need one branch and therefore one relocation per target label. */ | ||
68 | static struct uasm_label __cpuinitdata labels[5]; | ||
69 | static struct uasm_reloc __cpuinitdata relocs[5]; | ||
70 | |||
71 | #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) | ||
72 | #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) | ||
73 | |||
74 | /* | ||
75 | * Maximum sizes: | ||
76 | * | ||
77 | * R4000 128 bytes S-cache: 0x058 bytes | ||
78 | * R4600 v1.7: 0x05c bytes | ||
79 | * R4600 v2.0: 0x060 bytes | ||
80 | * With prefetching, 16 word strides 0x120 bytes | ||
81 | */ | ||
82 | |||
83 | static u32 clear_page_array[0x120 / 4]; | ||
84 | |||
85 | #ifdef CONFIG_SIBYTE_DMA_PAGEOPS | ||
86 | void clear_page_cpu(void *page) __attribute__((alias("clear_page_array"))); | ||
87 | #else | ||
88 | void clear_page(void *page) __attribute__((alias("clear_page_array"))); | ||
89 | #endif | ||
90 | |||
91 | EXPORT_SYMBOL(clear_page); | ||
92 | |||
93 | /* | ||
94 | * Maximum sizes: | ||
95 | * | ||
96 | * R4000 128 bytes S-cache: 0x11c bytes | ||
97 | * R4600 v1.7: 0x080 bytes | ||
98 | * R4600 v2.0: 0x07c bytes | ||
99 | * With prefetching, 16 word strides 0x540 bytes | ||
100 | */ | ||
101 | static u32 copy_page_array[0x540 / 4]; | ||
102 | |||
103 | #ifdef CONFIG_SIBYTE_DMA_PAGEOPS | ||
104 | void | ||
105 | copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array"))); | ||
106 | #else | ||
107 | void copy_page(void *to, void *from) __attribute__((alias("copy_page_array"))); | ||
108 | #endif | ||
109 | |||
110 | EXPORT_SYMBOL(copy_page); | ||
111 | |||
112 | |||
113 | static int pref_bias_clear_store __cpuinitdata; | ||
114 | static int pref_bias_copy_load __cpuinitdata; | ||
115 | static int pref_bias_copy_store __cpuinitdata; | ||
116 | |||
117 | static u32 pref_src_mode __cpuinitdata; | ||
118 | static u32 pref_dst_mode __cpuinitdata; | ||
119 | |||
120 | static int clear_word_size __cpuinitdata; | ||
121 | static int copy_word_size __cpuinitdata; | ||
122 | |||
123 | static int half_clear_loop_size __cpuinitdata; | ||
124 | static int half_copy_loop_size __cpuinitdata; | ||
125 | |||
126 | static int cache_line_size __cpuinitdata; | ||
127 | #define cache_line_mask() (cache_line_size - 1) | ||
128 | |||
129 | static inline void __cpuinit | ||
130 | pg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off) | ||
131 | { | ||
132 | if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { | ||
133 | if (off > 0x7fff) { | ||
134 | uasm_i_lui(buf, T9, uasm_rel_hi(off)); | ||
135 | uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); | ||
136 | } else | ||
137 | uasm_i_addiu(buf, T9, ZERO, off); | ||
138 | uasm_i_daddu(buf, reg1, reg2, T9); | ||
139 | } else { | ||
140 | if (off > 0x7fff) { | ||
141 | uasm_i_lui(buf, T9, uasm_rel_hi(off)); | ||
142 | uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off)); | ||
143 | UASM_i_ADDU(buf, reg1, reg2, T9); | ||
144 | } else | ||
145 | UASM_i_ADDIU(buf, reg1, reg2, off); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void __cpuinit set_prefetch_parameters(void) | ||
150 | { | ||
151 | if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) | ||
152 | clear_word_size = 8; | ||
153 | else | ||
154 | clear_word_size = 4; | ||
155 | |||
156 | if (cpu_has_64bit_gp_regs) | ||
157 | copy_word_size = 8; | ||
158 | else | ||
159 | copy_word_size = 4; | ||
160 | |||
161 | /* | ||
162 | * The pref's used here are using "streaming" hints, which cause the | ||
163 | * copied data to be kicked out of the cache sooner. A page copy often | ||
164 | * ends up copying a lot more data than is commonly used, so this seems | ||
165 | * to make sense in terms of reducing cache pollution, but I've no real | ||
166 | * performance data to back this up. | ||
167 | */ | ||
168 | if (cpu_has_prefetch) { | ||
169 | /* | ||
170 | * XXX: Most prefetch bias values in here are based on | ||
171 | * guesswork. | ||
172 | */ | ||
173 | cache_line_size = cpu_dcache_line_size(); | ||
174 | switch (current_cpu_type()) { | ||
175 | case CPU_TX49XX: | ||
176 | /* TX49 supports only Pref_Load */ | ||
177 | pref_bias_copy_load = 256; | ||
178 | break; | ||
179 | |||
180 | case CPU_RM9000: | ||
181 | /* | ||
182 | * As a workaround for erratum G105 which make the | ||
183 | * PrepareForStore hint unusable we fall back to | ||
184 | * StoreRetained on the RM9000. Once it is known which | ||
185 | * versions of the RM9000 we'll be able to condition- | ||
186 | * alize this. | ||
187 | */ | ||
188 | |||
189 | case CPU_R10000: | ||
190 | case CPU_R12000: | ||
191 | case CPU_R14000: | ||
192 | /* | ||
193 | * Those values have been experimentally tuned for an | ||
194 | * Origin 200. | ||
195 | */ | ||
196 | pref_bias_clear_store = 512; | ||
197 | pref_bias_copy_load = 256; | ||
198 | pref_bias_copy_store = 256; | ||
199 | pref_src_mode = Pref_LoadStreamed; | ||
200 | pref_dst_mode = Pref_StoreStreamed; | ||
201 | break; | ||
202 | |||
203 | case CPU_SB1: | ||
204 | case CPU_SB1A: | ||
205 | pref_bias_clear_store = 128; | ||
206 | pref_bias_copy_load = 128; | ||
207 | pref_bias_copy_store = 128; | ||
208 | /* | ||
209 | * SB1 pass1 Pref_LoadStreamed/Pref_StoreStreamed | ||
210 | * hints are broken. | ||
211 | */ | ||
212 | if (current_cpu_type() == CPU_SB1 && | ||
213 | (current_cpu_data.processor_id & 0xff) < 0x02) { | ||
214 | pref_src_mode = Pref_Load; | ||
215 | pref_dst_mode = Pref_Store; | ||
216 | } else { | ||
217 | pref_src_mode = Pref_LoadStreamed; | ||
218 | pref_dst_mode = Pref_StoreStreamed; | ||
219 | } | ||
220 | break; | ||
221 | |||
222 | default: | ||
223 | pref_bias_clear_store = 128; | ||
224 | pref_bias_copy_load = 256; | ||
225 | pref_bias_copy_store = 128; | ||
226 | pref_src_mode = Pref_LoadStreamed; | ||
227 | pref_dst_mode = Pref_PrepareForStore; | ||
228 | break; | ||
229 | } | ||
230 | } else { | ||
231 | if (cpu_has_cache_cdex_s) | ||
232 | cache_line_size = cpu_scache_line_size(); | ||
233 | else if (cpu_has_cache_cdex_p) | ||
234 | cache_line_size = cpu_dcache_line_size(); | ||
235 | } | ||
236 | /* | ||
237 | * Too much unrolling will overflow the available space in | ||
238 | * clear_space_array / copy_page_array. 8 words sounds generous, | ||
239 | * but a R4000 with 128 byte L2 line length can exceed even that. | ||
240 | */ | ||
241 | half_clear_loop_size = min(8 * clear_word_size, | ||
242 | max(cache_line_size >> 1, | ||
243 | 4 * clear_word_size)); | ||
244 | half_copy_loop_size = min(8 * copy_word_size, | ||
245 | max(cache_line_size >> 1, | ||
246 | 4 * copy_word_size)); | ||
247 | } | ||
248 | |||
249 | static void __cpuinit build_clear_store(u32 **buf, int off) | ||
250 | { | ||
251 | if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) { | ||
252 | uasm_i_sd(buf, ZERO, off, A0); | ||
253 | } else { | ||
254 | uasm_i_sw(buf, ZERO, off, A0); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static inline void __cpuinit build_clear_pref(u32 **buf, int off) | ||
259 | { | ||
260 | if (off & cache_line_mask()) | ||
261 | return; | ||
262 | |||
263 | if (pref_bias_clear_store) { | ||
264 | uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off, | ||
265 | A0); | ||
266 | } else if (cpu_has_cache_cdex_s) { | ||
267 | uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); | ||
268 | } else if (cpu_has_cache_cdex_p) { | ||
269 | if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { | ||
270 | uasm_i_nop(buf); | ||
271 | uasm_i_nop(buf); | ||
272 | uasm_i_nop(buf); | ||
273 | uasm_i_nop(buf); | ||
274 | } | ||
275 | |||
276 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
277 | uasm_i_lw(buf, ZERO, ZERO, AT); | ||
278 | |||
279 | uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | void __cpuinit build_clear_page(void) | ||
284 | { | ||
285 | int off; | ||
286 | u32 *buf = (u32 *)&clear_page_array; | ||
287 | struct uasm_label *l = labels; | ||
288 | struct uasm_reloc *r = relocs; | ||
289 | int i; | ||
290 | |||
291 | memset(labels, 0, sizeof(labels)); | ||
292 | memset(relocs, 0, sizeof(relocs)); | ||
293 | |||
294 | set_prefetch_parameters(); | ||
295 | |||
296 | /* | ||
297 | * This algorithm makes the following assumptions: | ||
298 | * - The prefetch bias is a multiple of 2 words. | ||
299 | * - The prefetch bias is less than one page. | ||
300 | */ | ||
301 | BUG_ON(pref_bias_clear_store % (2 * clear_word_size)); | ||
302 | BUG_ON(PAGE_SIZE < pref_bias_clear_store); | ||
303 | |||
304 | off = PAGE_SIZE - pref_bias_clear_store; | ||
305 | if (off > 0xffff || !pref_bias_clear_store) | ||
306 | pg_addiu(&buf, A2, A0, off); | ||
307 | else | ||
308 | uasm_i_ori(&buf, A2, A0, off); | ||
309 | |||
310 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
311 | uasm_i_lui(&buf, AT, 0xa000); | ||
312 | |||
313 | off = min(8, pref_bias_clear_store / cache_line_size) * | ||
314 | cache_line_size; | ||
315 | while (off) { | ||
316 | build_clear_pref(&buf, -off); | ||
317 | off -= cache_line_size; | ||
318 | } | ||
319 | uasm_l_clear_pref(&l, buf); | ||
320 | do { | ||
321 | build_clear_pref(&buf, off); | ||
322 | build_clear_store(&buf, off); | ||
323 | off += clear_word_size; | ||
324 | } while (off < half_clear_loop_size); | ||
325 | pg_addiu(&buf, A0, A0, 2 * off); | ||
326 | off = -off; | ||
327 | do { | ||
328 | build_clear_pref(&buf, off); | ||
329 | if (off == -clear_word_size) | ||
330 | uasm_il_bne(&buf, &r, A0, A2, label_clear_pref); | ||
331 | build_clear_store(&buf, off); | ||
332 | off += clear_word_size; | ||
333 | } while (off < 0); | ||
334 | |||
335 | if (pref_bias_clear_store) { | ||
336 | pg_addiu(&buf, A2, A0, pref_bias_clear_store); | ||
337 | uasm_l_clear_nopref(&l, buf); | ||
338 | off = 0; | ||
339 | do { | ||
340 | build_clear_store(&buf, off); | ||
341 | off += clear_word_size; | ||
342 | } while (off < half_clear_loop_size); | ||
343 | pg_addiu(&buf, A0, A0, 2 * off); | ||
344 | off = -off; | ||
345 | do { | ||
346 | if (off == -clear_word_size) | ||
347 | uasm_il_bne(&buf, &r, A0, A2, | ||
348 | label_clear_nopref); | ||
349 | build_clear_store(&buf, off); | ||
350 | off += clear_word_size; | ||
351 | } while (off < 0); | ||
352 | } | ||
353 | |||
354 | uasm_i_jr(&buf, RA); | ||
355 | uasm_i_nop(&buf); | ||
356 | |||
357 | BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array)); | ||
358 | |||
359 | uasm_resolve_relocs(relocs, labels); | ||
360 | |||
361 | pr_debug("Synthesized clear page handler (%u instructions).\n", | ||
362 | (u32)(buf - clear_page_array)); | ||
363 | |||
364 | pr_debug("\t.set push\n"); | ||
365 | pr_debug("\t.set noreorder\n"); | ||
366 | for (i = 0; i < (buf - clear_page_array); i++) | ||
367 | pr_debug("\t.word 0x%08x\n", clear_page_array[i]); | ||
368 | pr_debug("\t.set pop\n"); | ||
369 | } | ||
370 | |||
371 | static void __cpuinit build_copy_load(u32 **buf, int reg, int off) | ||
372 | { | ||
373 | if (cpu_has_64bit_gp_regs) { | ||
374 | uasm_i_ld(buf, reg, off, A1); | ||
375 | } else { | ||
376 | uasm_i_lw(buf, reg, off, A1); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | static void __cpuinit build_copy_store(u32 **buf, int reg, int off) | ||
381 | { | ||
382 | if (cpu_has_64bit_gp_regs) { | ||
383 | uasm_i_sd(buf, reg, off, A0); | ||
384 | } else { | ||
385 | uasm_i_sw(buf, reg, off, A0); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | static inline void build_copy_load_pref(u32 **buf, int off) | ||
390 | { | ||
391 | if (off & cache_line_mask()) | ||
392 | return; | ||
393 | |||
394 | if (pref_bias_copy_load) | ||
395 | uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1); | ||
396 | } | ||
397 | |||
398 | static inline void build_copy_store_pref(u32 **buf, int off) | ||
399 | { | ||
400 | if (off & cache_line_mask()) | ||
401 | return; | ||
402 | |||
403 | if (pref_bias_copy_store) { | ||
404 | uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off, | ||
405 | A0); | ||
406 | } else if (cpu_has_cache_cdex_s) { | ||
407 | uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0); | ||
408 | } else if (cpu_has_cache_cdex_p) { | ||
409 | if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { | ||
410 | uasm_i_nop(buf); | ||
411 | uasm_i_nop(buf); | ||
412 | uasm_i_nop(buf); | ||
413 | uasm_i_nop(buf); | ||
414 | } | ||
415 | |||
416 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
417 | uasm_i_lw(buf, ZERO, ZERO, AT); | ||
418 | |||
419 | uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | void __cpuinit build_copy_page(void) | ||
424 | { | ||
425 | int off; | ||
426 | u32 *buf = (u32 *)©_page_array; | ||
427 | struct uasm_label *l = labels; | ||
428 | struct uasm_reloc *r = relocs; | ||
429 | int i; | ||
430 | |||
431 | memset(labels, 0, sizeof(labels)); | ||
432 | memset(relocs, 0, sizeof(relocs)); | ||
433 | |||
434 | set_prefetch_parameters(); | ||
435 | |||
436 | /* | ||
437 | * This algorithm makes the following assumptions: | ||
438 | * - All prefetch biases are multiples of 8 words. | ||
439 | * - The prefetch biases are less than one page. | ||
440 | * - The store prefetch bias isn't greater than the load | ||
441 | * prefetch bias. | ||
442 | */ | ||
443 | BUG_ON(pref_bias_copy_load % (8 * copy_word_size)); | ||
444 | BUG_ON(pref_bias_copy_store % (8 * copy_word_size)); | ||
445 | BUG_ON(PAGE_SIZE < pref_bias_copy_load); | ||
446 | BUG_ON(pref_bias_copy_store > pref_bias_copy_load); | ||
447 | |||
448 | off = PAGE_SIZE - pref_bias_copy_load; | ||
449 | if (off > 0xffff || !pref_bias_copy_load) | ||
450 | pg_addiu(&buf, A2, A0, off); | ||
451 | else | ||
452 | uasm_i_ori(&buf, A2, A0, off); | ||
453 | |||
454 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
455 | uasm_i_lui(&buf, AT, 0xa000); | ||
456 | |||
457 | off = min(8, pref_bias_copy_load / cache_line_size) * cache_line_size; | ||
458 | while (off) { | ||
459 | build_copy_load_pref(&buf, -off); | ||
460 | off -= cache_line_size; | ||
461 | } | ||
462 | off = min(8, pref_bias_copy_store / cache_line_size) * cache_line_size; | ||
463 | while (off) { | ||
464 | build_copy_store_pref(&buf, -off); | ||
465 | off -= cache_line_size; | ||
466 | } | ||
467 | uasm_l_copy_pref_both(&l, buf); | ||
468 | do { | ||
469 | build_copy_load_pref(&buf, off); | ||
470 | build_copy_load(&buf, T0, off); | ||
471 | build_copy_load_pref(&buf, off + copy_word_size); | ||
472 | build_copy_load(&buf, T1, off + copy_word_size); | ||
473 | build_copy_load_pref(&buf, off + 2 * copy_word_size); | ||
474 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
475 | build_copy_load_pref(&buf, off + 3 * copy_word_size); | ||
476 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
477 | build_copy_store_pref(&buf, off); | ||
478 | build_copy_store(&buf, T0, off); | ||
479 | build_copy_store_pref(&buf, off + copy_word_size); | ||
480 | build_copy_store(&buf, T1, off + copy_word_size); | ||
481 | build_copy_store_pref(&buf, off + 2 * copy_word_size); | ||
482 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
483 | build_copy_store_pref(&buf, off + 3 * copy_word_size); | ||
484 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
485 | off += 4 * copy_word_size; | ||
486 | } while (off < half_copy_loop_size); | ||
487 | pg_addiu(&buf, A1, A1, 2 * off); | ||
488 | pg_addiu(&buf, A0, A0, 2 * off); | ||
489 | off = -off; | ||
490 | do { | ||
491 | build_copy_load_pref(&buf, off); | ||
492 | build_copy_load(&buf, T0, off); | ||
493 | build_copy_load_pref(&buf, off + copy_word_size); | ||
494 | build_copy_load(&buf, T1, off + copy_word_size); | ||
495 | build_copy_load_pref(&buf, off + 2 * copy_word_size); | ||
496 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
497 | build_copy_load_pref(&buf, off + 3 * copy_word_size); | ||
498 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
499 | build_copy_store_pref(&buf, off); | ||
500 | build_copy_store(&buf, T0, off); | ||
501 | build_copy_store_pref(&buf, off + copy_word_size); | ||
502 | build_copy_store(&buf, T1, off + copy_word_size); | ||
503 | build_copy_store_pref(&buf, off + 2 * copy_word_size); | ||
504 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
505 | build_copy_store_pref(&buf, off + 3 * copy_word_size); | ||
506 | if (off == -(4 * copy_word_size)) | ||
507 | uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both); | ||
508 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
509 | off += 4 * copy_word_size; | ||
510 | } while (off < 0); | ||
511 | |||
512 | if (pref_bias_copy_load - pref_bias_copy_store) { | ||
513 | pg_addiu(&buf, A2, A0, | ||
514 | pref_bias_copy_load - pref_bias_copy_store); | ||
515 | uasm_l_copy_pref_store(&l, buf); | ||
516 | off = 0; | ||
517 | do { | ||
518 | build_copy_load(&buf, T0, off); | ||
519 | build_copy_load(&buf, T1, off + copy_word_size); | ||
520 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
521 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
522 | build_copy_store_pref(&buf, off); | ||
523 | build_copy_store(&buf, T0, off); | ||
524 | build_copy_store_pref(&buf, off + copy_word_size); | ||
525 | build_copy_store(&buf, T1, off + copy_word_size); | ||
526 | build_copy_store_pref(&buf, off + 2 * copy_word_size); | ||
527 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
528 | build_copy_store_pref(&buf, off + 3 * copy_word_size); | ||
529 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
530 | off += 4 * copy_word_size; | ||
531 | } while (off < half_copy_loop_size); | ||
532 | pg_addiu(&buf, A1, A1, 2 * off); | ||
533 | pg_addiu(&buf, A0, A0, 2 * off); | ||
534 | off = -off; | ||
535 | do { | ||
536 | build_copy_load(&buf, T0, off); | ||
537 | build_copy_load(&buf, T1, off + copy_word_size); | ||
538 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
539 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
540 | build_copy_store_pref(&buf, off); | ||
541 | build_copy_store(&buf, T0, off); | ||
542 | build_copy_store_pref(&buf, off + copy_word_size); | ||
543 | build_copy_store(&buf, T1, off + copy_word_size); | ||
544 | build_copy_store_pref(&buf, off + 2 * copy_word_size); | ||
545 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
546 | build_copy_store_pref(&buf, off + 3 * copy_word_size); | ||
547 | if (off == -(4 * copy_word_size)) | ||
548 | uasm_il_bne(&buf, &r, A2, A0, | ||
549 | label_copy_pref_store); | ||
550 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
551 | off += 4 * copy_word_size; | ||
552 | } while (off < 0); | ||
553 | } | ||
554 | |||
555 | if (pref_bias_copy_store) { | ||
556 | pg_addiu(&buf, A2, A0, pref_bias_copy_store); | ||
557 | uasm_l_copy_nopref(&l, buf); | ||
558 | off = 0; | ||
559 | do { | ||
560 | build_copy_load(&buf, T0, off); | ||
561 | build_copy_load(&buf, T1, off + copy_word_size); | ||
562 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
563 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
564 | build_copy_store(&buf, T0, off); | ||
565 | build_copy_store(&buf, T1, off + copy_word_size); | ||
566 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
567 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
568 | off += 4 * copy_word_size; | ||
569 | } while (off < half_copy_loop_size); | ||
570 | pg_addiu(&buf, A1, A1, 2 * off); | ||
571 | pg_addiu(&buf, A0, A0, 2 * off); | ||
572 | off = -off; | ||
573 | do { | ||
574 | build_copy_load(&buf, T0, off); | ||
575 | build_copy_load(&buf, T1, off + copy_word_size); | ||
576 | build_copy_load(&buf, T2, off + 2 * copy_word_size); | ||
577 | build_copy_load(&buf, T3, off + 3 * copy_word_size); | ||
578 | build_copy_store(&buf, T0, off); | ||
579 | build_copy_store(&buf, T1, off + copy_word_size); | ||
580 | build_copy_store(&buf, T2, off + 2 * copy_word_size); | ||
581 | if (off == -(4 * copy_word_size)) | ||
582 | uasm_il_bne(&buf, &r, A2, A0, | ||
583 | label_copy_nopref); | ||
584 | build_copy_store(&buf, T3, off + 3 * copy_word_size); | ||
585 | off += 4 * copy_word_size; | ||
586 | } while (off < 0); | ||
587 | } | ||
588 | |||
589 | uasm_i_jr(&buf, RA); | ||
590 | uasm_i_nop(&buf); | ||
591 | |||
592 | BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array)); | ||
593 | |||
594 | uasm_resolve_relocs(relocs, labels); | ||
595 | |||
596 | pr_debug("Synthesized copy page handler (%u instructions).\n", | ||
597 | (u32)(buf - copy_page_array)); | ||
598 | |||
599 | pr_debug("\t.set push\n"); | ||
600 | pr_debug("\t.set noreorder\n"); | ||
601 | for (i = 0; i < (buf - copy_page_array); i++) | ||
602 | pr_debug("\t.word 0x%08x\n", copy_page_array[i]); | ||
603 | pr_debug("\t.set pop\n"); | ||
604 | } | ||
605 | |||
606 | #ifdef CONFIG_SIBYTE_DMA_PAGEOPS | ||
607 | |||
608 | /* | ||
609 | * Pad descriptors to cacheline, since each is exclusively owned by a | ||
610 | * particular CPU. | ||
611 | */ | ||
612 | struct dmadscr { | ||
613 | u64 dscr_a; | ||
614 | u64 dscr_b; | ||
615 | u64 pad_a; | ||
616 | u64 pad_b; | ||
617 | } ____cacheline_aligned_in_smp page_descr[DM_NUM_CHANNELS]; | ||
618 | |||
619 | void sb1_dma_init(void) | ||
620 | { | ||
621 | int i; | ||
622 | |||
623 | for (i = 0; i < DM_NUM_CHANNELS; i++) { | ||
624 | const u64 base_val = CPHYSADDR((unsigned long)&page_descr[i]) | | ||
625 | V_DM_DSCR_BASE_RINGSZ(1); | ||
626 | void *base_reg = IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE)); | ||
627 | |||
628 | __raw_writeq(base_val, base_reg); | ||
629 | __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg); | ||
630 | __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | void clear_page(void *page) | ||
635 | { | ||
636 | u64 to_phys = CPHYSADDR((unsigned long)page); | ||
637 | unsigned int cpu = smp_processor_id(); | ||
638 | |||
639 | /* if the page is not in KSEG0, use old way */ | ||
640 | if ((long)KSEGX((unsigned long)page) != (long)CKSEG0) | ||
641 | return clear_page_cpu(page); | ||
642 | |||
643 | page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | | ||
644 | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT; | ||
645 | page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); | ||
646 | __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); | ||
647 | |||
648 | /* | ||
649 | * Don't really want to do it this way, but there's no | ||
650 | * reliable way to delay completion detection. | ||
651 | */ | ||
652 | while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) | ||
653 | & M_DM_DSCR_BASE_INTERRUPT)) | ||
654 | ; | ||
655 | __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); | ||
656 | } | ||
657 | |||
658 | void copy_page(void *to, void *from) | ||
659 | { | ||
660 | u64 from_phys = CPHYSADDR((unsigned long)from); | ||
661 | u64 to_phys = CPHYSADDR((unsigned long)to); | ||
662 | unsigned int cpu = smp_processor_id(); | ||
663 | |||
664 | /* if any page is not in KSEG0, use old way */ | ||
665 | if ((long)KSEGX((unsigned long)to) != (long)CKSEG0 | ||
666 | || (long)KSEGX((unsigned long)from) != (long)CKSEG0) | ||
667 | return copy_page_cpu(to, from); | ||
668 | |||
669 | page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST | | ||
670 | M_DM_DSCRA_INTERRUPT; | ||
671 | page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); | ||
672 | __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); | ||
673 | |||
674 | /* | ||
675 | * Don't really want to do it this way, but there's no | ||
676 | * reliable way to delay completion detection. | ||
677 | */ | ||
678 | while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) | ||
679 | & M_DM_DSCR_BASE_INTERRUPT)) | ||
680 | ; | ||
681 | __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); | ||
682 | } | ||
683 | |||
684 | #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */ | ||
diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c deleted file mode 100644 index 455dedb5b39e..000000000000 --- a/arch/mips/mm/pg-r4k.c +++ /dev/null | |||
@@ -1,534 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org) | ||
7 | * Copyright (C) 2007 Maciej W. Rozycki | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/proc_fs.h> | ||
15 | |||
16 | #include <asm/bugs.h> | ||
17 | #include <asm/cacheops.h> | ||
18 | #include <asm/inst.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pgtable.h> | ||
22 | #include <asm/prefetch.h> | ||
23 | #include <asm/system.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | #include <asm/mipsregs.h> | ||
26 | #include <asm/mmu_context.h> | ||
27 | #include <asm/cpu.h> | ||
28 | #include <asm/war.h> | ||
29 | |||
30 | #define half_scache_line_size() (cpu_scache_line_size() >> 1) | ||
31 | #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) | ||
32 | #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) | ||
33 | |||
34 | |||
35 | /* | ||
36 | * Maximum sizes: | ||
37 | * | ||
38 | * R4000 128 bytes S-cache: 0x58 bytes | ||
39 | * R4600 v1.7: 0x5c bytes | ||
40 | * R4600 v2.0: 0x60 bytes | ||
41 | * With prefetching, 16 byte strides 0xa0 bytes | ||
42 | */ | ||
43 | |||
44 | static unsigned int clear_page_array[0x130 / 4]; | ||
45 | |||
46 | void clear_page(void * page) __attribute__((alias("clear_page_array"))); | ||
47 | |||
48 | EXPORT_SYMBOL(clear_page); | ||
49 | |||
50 | /* | ||
51 | * Maximum sizes: | ||
52 | * | ||
53 | * R4000 128 bytes S-cache: 0x11c bytes | ||
54 | * R4600 v1.7: 0x080 bytes | ||
55 | * R4600 v2.0: 0x07c bytes | ||
56 | * With prefetching, 16 byte strides 0x0b8 bytes | ||
57 | */ | ||
58 | static unsigned int copy_page_array[0x148 / 4]; | ||
59 | |||
60 | void copy_page(void *to, void *from) __attribute__((alias("copy_page_array"))); | ||
61 | |||
62 | EXPORT_SYMBOL(copy_page); | ||
63 | |||
64 | /* | ||
65 | * This is suboptimal for 32-bit kernels; we assume that R10000 is only used | ||
66 | * with 64-bit kernels. The prefetch offsets have been experimentally tuned | ||
67 | * an Origin 200. | ||
68 | */ | ||
69 | static int pref_offset_clear __cpuinitdata = 512; | ||
70 | static int pref_offset_copy __cpuinitdata = 256; | ||
71 | |||
72 | static unsigned int pref_src_mode __cpuinitdata; | ||
73 | static unsigned int pref_dst_mode __cpuinitdata; | ||
74 | |||
75 | static int load_offset __cpuinitdata; | ||
76 | static int store_offset __cpuinitdata; | ||
77 | |||
78 | static unsigned int __cpuinitdata *dest, *epc; | ||
79 | |||
80 | static unsigned int instruction_pending; | ||
81 | static union mips_instruction delayed_mi; | ||
82 | |||
83 | static void __cpuinit emit_instruction(union mips_instruction mi) | ||
84 | { | ||
85 | if (instruction_pending) | ||
86 | *epc++ = delayed_mi.word; | ||
87 | |||
88 | instruction_pending = 1; | ||
89 | delayed_mi = mi; | ||
90 | } | ||
91 | |||
92 | static inline void flush_delay_slot_or_nop(void) | ||
93 | { | ||
94 | if (instruction_pending) { | ||
95 | *epc++ = delayed_mi.word; | ||
96 | instruction_pending = 0; | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | *epc++ = 0; | ||
101 | } | ||
102 | |||
103 | static inline unsigned int *label(void) | ||
104 | { | ||
105 | if (instruction_pending) { | ||
106 | *epc++ = delayed_mi.word; | ||
107 | instruction_pending = 0; | ||
108 | } | ||
109 | |||
110 | return epc; | ||
111 | } | ||
112 | |||
113 | static inline void build_insn_word(unsigned int word) | ||
114 | { | ||
115 | union mips_instruction mi; | ||
116 | |||
117 | mi.word = word; | ||
118 | |||
119 | emit_instruction(mi); | ||
120 | } | ||
121 | |||
122 | static inline void build_nop(void) | ||
123 | { | ||
124 | build_insn_word(0); /* nop */ | ||
125 | } | ||
126 | |||
127 | static inline void build_src_pref(int advance) | ||
128 | { | ||
129 | if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) { | ||
130 | union mips_instruction mi; | ||
131 | |||
132 | mi.i_format.opcode = pref_op; | ||
133 | mi.i_format.rs = 5; /* $a1 */ | ||
134 | mi.i_format.rt = pref_src_mode; | ||
135 | mi.i_format.simmediate = load_offset + advance; | ||
136 | |||
137 | emit_instruction(mi); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static inline void __build_load_reg(int reg) | ||
142 | { | ||
143 | union mips_instruction mi; | ||
144 | unsigned int width; | ||
145 | |||
146 | if (cpu_has_64bit_gp_regs) { | ||
147 | mi.i_format.opcode = ld_op; | ||
148 | width = 8; | ||
149 | } else { | ||
150 | mi.i_format.opcode = lw_op; | ||
151 | width = 4; | ||
152 | } | ||
153 | mi.i_format.rs = 5; /* $a1 */ | ||
154 | mi.i_format.rt = reg; /* $reg */ | ||
155 | mi.i_format.simmediate = load_offset; | ||
156 | |||
157 | load_offset += width; | ||
158 | emit_instruction(mi); | ||
159 | } | ||
160 | |||
161 | static inline void build_load_reg(int reg) | ||
162 | { | ||
163 | if (cpu_has_prefetch) | ||
164 | build_src_pref(pref_offset_copy); | ||
165 | |||
166 | __build_load_reg(reg); | ||
167 | } | ||
168 | |||
169 | static inline void build_dst_pref(int advance) | ||
170 | { | ||
171 | if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) { | ||
172 | union mips_instruction mi; | ||
173 | |||
174 | mi.i_format.opcode = pref_op; | ||
175 | mi.i_format.rs = 4; /* $a0 */ | ||
176 | mi.i_format.rt = pref_dst_mode; | ||
177 | mi.i_format.simmediate = store_offset + advance; | ||
178 | |||
179 | emit_instruction(mi); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static inline void build_cdex_s(void) | ||
184 | { | ||
185 | union mips_instruction mi; | ||
186 | |||
187 | if ((store_offset & (cpu_scache_line_size() - 1))) | ||
188 | return; | ||
189 | |||
190 | mi.c_format.opcode = cache_op; | ||
191 | mi.c_format.rs = 4; /* $a0 */ | ||
192 | mi.c_format.c_op = 3; /* Create Dirty Exclusive */ | ||
193 | mi.c_format.cache = 3; /* Secondary Data Cache */ | ||
194 | mi.c_format.simmediate = store_offset; | ||
195 | |||
196 | emit_instruction(mi); | ||
197 | } | ||
198 | |||
199 | static inline void build_cdex_p(void) | ||
200 | { | ||
201 | union mips_instruction mi; | ||
202 | |||
203 | if (store_offset & (cpu_dcache_line_size() - 1)) | ||
204 | return; | ||
205 | |||
206 | if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) { | ||
207 | build_nop(); | ||
208 | build_nop(); | ||
209 | build_nop(); | ||
210 | build_nop(); | ||
211 | } | ||
212 | |||
213 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
214 | build_insn_word(0x8c200000); /* lw $zero, ($at) */ | ||
215 | |||
216 | mi.c_format.opcode = cache_op; | ||
217 | mi.c_format.rs = 4; /* $a0 */ | ||
218 | mi.c_format.c_op = 3; /* Create Dirty Exclusive */ | ||
219 | mi.c_format.cache = 1; /* Data Cache */ | ||
220 | mi.c_format.simmediate = store_offset; | ||
221 | |||
222 | emit_instruction(mi); | ||
223 | } | ||
224 | |||
225 | static void __cpuinit __build_store_reg(int reg) | ||
226 | { | ||
227 | union mips_instruction mi; | ||
228 | unsigned int width; | ||
229 | |||
230 | if (cpu_has_64bit_gp_regs || | ||
231 | (cpu_has_64bit_zero_reg && reg == 0)) { | ||
232 | mi.i_format.opcode = sd_op; | ||
233 | width = 8; | ||
234 | } else { | ||
235 | mi.i_format.opcode = sw_op; | ||
236 | width = 4; | ||
237 | } | ||
238 | mi.i_format.rs = 4; /* $a0 */ | ||
239 | mi.i_format.rt = reg; /* $reg */ | ||
240 | mi.i_format.simmediate = store_offset; | ||
241 | |||
242 | store_offset += width; | ||
243 | emit_instruction(mi); | ||
244 | } | ||
245 | |||
246 | static inline void build_store_reg(int reg) | ||
247 | { | ||
248 | int pref_off = cpu_has_prefetch ? | ||
249 | (reg ? pref_offset_copy : pref_offset_clear) : 0; | ||
250 | if (pref_off) | ||
251 | build_dst_pref(pref_off); | ||
252 | else if (cpu_has_cache_cdex_s) | ||
253 | build_cdex_s(); | ||
254 | else if (cpu_has_cache_cdex_p) | ||
255 | build_cdex_p(); | ||
256 | |||
257 | __build_store_reg(reg); | ||
258 | } | ||
259 | |||
260 | static inline void build_addiu_rt_rs(unsigned int rt, unsigned int rs, | ||
261 | unsigned long offset) | ||
262 | { | ||
263 | union mips_instruction mi; | ||
264 | |||
265 | BUG_ON(offset > 0x7fff); | ||
266 | |||
267 | if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) { | ||
268 | mi.i_format.opcode = addiu_op; | ||
269 | mi.i_format.rs = 0; /* $zero */ | ||
270 | mi.i_format.rt = 25; /* $t9 */ | ||
271 | mi.i_format.simmediate = offset; | ||
272 | emit_instruction(mi); | ||
273 | |||
274 | mi.r_format.opcode = spec_op; | ||
275 | mi.r_format.rs = rs; | ||
276 | mi.r_format.rt = 25; /* $t9 */ | ||
277 | mi.r_format.rd = rt; | ||
278 | mi.r_format.re = 0; | ||
279 | mi.r_format.func = daddu_op; | ||
280 | } else { | ||
281 | mi.i_format.opcode = cpu_has_64bit_gp_regs ? | ||
282 | daddiu_op : addiu_op; | ||
283 | mi.i_format.rs = rs; | ||
284 | mi.i_format.rt = rt; | ||
285 | mi.i_format.simmediate = offset; | ||
286 | } | ||
287 | emit_instruction(mi); | ||
288 | } | ||
289 | |||
290 | static inline void build_addiu_a2_a0(unsigned long offset) | ||
291 | { | ||
292 | build_addiu_rt_rs(6, 4, offset); /* $a2, $a0, offset */ | ||
293 | } | ||
294 | |||
295 | static inline void build_addiu_a2(unsigned long offset) | ||
296 | { | ||
297 | build_addiu_rt_rs(6, 6, offset); /* $a2, $a2, offset */ | ||
298 | } | ||
299 | |||
300 | static inline void build_addiu_a1(unsigned long offset) | ||
301 | { | ||
302 | build_addiu_rt_rs(5, 5, offset); /* $a1, $a1, offset */ | ||
303 | |||
304 | load_offset -= offset; | ||
305 | } | ||
306 | |||
307 | static inline void build_addiu_a0(unsigned long offset) | ||
308 | { | ||
309 | build_addiu_rt_rs(4, 4, offset); /* $a0, $a0, offset */ | ||
310 | |||
311 | store_offset -= offset; | ||
312 | } | ||
313 | |||
314 | static inline void build_bne(unsigned int *dest) | ||
315 | { | ||
316 | union mips_instruction mi; | ||
317 | |||
318 | mi.i_format.opcode = bne_op; | ||
319 | mi.i_format.rs = 6; /* $a2 */ | ||
320 | mi.i_format.rt = 4; /* $a0 */ | ||
321 | mi.i_format.simmediate = dest - epc - 1; | ||
322 | |||
323 | *epc++ = mi.word; | ||
324 | flush_delay_slot_or_nop(); | ||
325 | } | ||
326 | |||
327 | static inline void build_jr_ra(void) | ||
328 | { | ||
329 | union mips_instruction mi; | ||
330 | |||
331 | mi.r_format.opcode = spec_op; | ||
332 | mi.r_format.rs = 31; | ||
333 | mi.r_format.rt = 0; | ||
334 | mi.r_format.rd = 0; | ||
335 | mi.r_format.re = 0; | ||
336 | mi.r_format.func = jr_op; | ||
337 | |||
338 | *epc++ = mi.word; | ||
339 | flush_delay_slot_or_nop(); | ||
340 | } | ||
341 | |||
342 | void __cpuinit build_clear_page(void) | ||
343 | { | ||
344 | unsigned int loop_start; | ||
345 | unsigned long off; | ||
346 | int i; | ||
347 | |||
348 | epc = (unsigned int *) &clear_page_array; | ||
349 | instruction_pending = 0; | ||
350 | store_offset = 0; | ||
351 | |||
352 | if (cpu_has_prefetch) { | ||
353 | switch (current_cpu_type()) { | ||
354 | case CPU_TX49XX: | ||
355 | /* TX49 supports only Pref_Load */ | ||
356 | pref_offset_clear = 0; | ||
357 | pref_offset_copy = 0; | ||
358 | break; | ||
359 | |||
360 | case CPU_RM9000: | ||
361 | /* | ||
362 | * As a workaround for erratum G105 which make the | ||
363 | * PrepareForStore hint unusable we fall back to | ||
364 | * StoreRetained on the RM9000. Once it is known which | ||
365 | * versions of the RM9000 we'll be able to condition- | ||
366 | * alize this. | ||
367 | */ | ||
368 | |||
369 | case CPU_R10000: | ||
370 | case CPU_R12000: | ||
371 | case CPU_R14000: | ||
372 | pref_src_mode = Pref_LoadStreamed; | ||
373 | pref_dst_mode = Pref_StoreStreamed; | ||
374 | break; | ||
375 | |||
376 | default: | ||
377 | pref_src_mode = Pref_LoadStreamed; | ||
378 | pref_dst_mode = Pref_PrepareForStore; | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0); | ||
384 | if (off > 0x7fff) { | ||
385 | build_addiu_a2_a0(off >> 1); | ||
386 | build_addiu_a2(off >> 1); | ||
387 | } else | ||
388 | build_addiu_a2_a0(off); | ||
389 | |||
390 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
391 | build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ | ||
392 | |||
393 | dest = label(); | ||
394 | do { | ||
395 | build_store_reg(0); | ||
396 | build_store_reg(0); | ||
397 | build_store_reg(0); | ||
398 | build_store_reg(0); | ||
399 | } while (store_offset < half_scache_line_size()); | ||
400 | build_addiu_a0(2 * store_offset); | ||
401 | loop_start = store_offset; | ||
402 | do { | ||
403 | build_store_reg(0); | ||
404 | build_store_reg(0); | ||
405 | build_store_reg(0); | ||
406 | build_store_reg(0); | ||
407 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
408 | build_bne(dest); | ||
409 | |||
410 | if (cpu_has_prefetch && pref_offset_clear) { | ||
411 | build_addiu_a2_a0(pref_offset_clear); | ||
412 | dest = label(); | ||
413 | loop_start = store_offset; | ||
414 | do { | ||
415 | __build_store_reg(0); | ||
416 | __build_store_reg(0); | ||
417 | __build_store_reg(0); | ||
418 | __build_store_reg(0); | ||
419 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
420 | build_addiu_a0(2 * store_offset); | ||
421 | loop_start = store_offset; | ||
422 | do { | ||
423 | __build_store_reg(0); | ||
424 | __build_store_reg(0); | ||
425 | __build_store_reg(0); | ||
426 | __build_store_reg(0); | ||
427 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
428 | build_bne(dest); | ||
429 | } | ||
430 | |||
431 | build_jr_ra(); | ||
432 | |||
433 | BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array)); | ||
434 | |||
435 | pr_info("Synthesized clear page handler (%u instructions).\n", | ||
436 | (unsigned int)(epc - clear_page_array)); | ||
437 | |||
438 | pr_debug("\t.set push\n"); | ||
439 | pr_debug("\t.set noreorder\n"); | ||
440 | for (i = 0; i < (epc - clear_page_array); i++) | ||
441 | pr_debug("\t.word 0x%08x\n", clear_page_array[i]); | ||
442 | pr_debug("\t.set pop\n"); | ||
443 | } | ||
444 | |||
445 | void __cpuinit build_copy_page(void) | ||
446 | { | ||
447 | unsigned int loop_start; | ||
448 | unsigned long off; | ||
449 | int i; | ||
450 | |||
451 | epc = (unsigned int *) ©_page_array; | ||
452 | store_offset = load_offset = 0; | ||
453 | instruction_pending = 0; | ||
454 | |||
455 | off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0); | ||
456 | if (off > 0x7fff) { | ||
457 | build_addiu_a2_a0(off >> 1); | ||
458 | build_addiu_a2(off >> 1); | ||
459 | } else | ||
460 | build_addiu_a2_a0(off); | ||
461 | |||
462 | if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x()) | ||
463 | build_insn_word(0x3c01a000); /* lui $at, 0xa000 */ | ||
464 | |||
465 | dest = label(); | ||
466 | loop_start = store_offset; | ||
467 | do { | ||
468 | build_load_reg( 8); | ||
469 | build_load_reg( 9); | ||
470 | build_load_reg(10); | ||
471 | build_load_reg(11); | ||
472 | build_store_reg( 8); | ||
473 | build_store_reg( 9); | ||
474 | build_store_reg(10); | ||
475 | build_store_reg(11); | ||
476 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
477 | build_addiu_a0(2 * store_offset); | ||
478 | build_addiu_a1(2 * load_offset); | ||
479 | loop_start = store_offset; | ||
480 | do { | ||
481 | build_load_reg( 8); | ||
482 | build_load_reg( 9); | ||
483 | build_load_reg(10); | ||
484 | build_load_reg(11); | ||
485 | build_store_reg( 8); | ||
486 | build_store_reg( 9); | ||
487 | build_store_reg(10); | ||
488 | build_store_reg(11); | ||
489 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
490 | build_bne(dest); | ||
491 | |||
492 | if (cpu_has_prefetch && pref_offset_copy) { | ||
493 | build_addiu_a2_a0(pref_offset_copy); | ||
494 | dest = label(); | ||
495 | loop_start = store_offset; | ||
496 | do { | ||
497 | __build_load_reg( 8); | ||
498 | __build_load_reg( 9); | ||
499 | __build_load_reg(10); | ||
500 | __build_load_reg(11); | ||
501 | __build_store_reg( 8); | ||
502 | __build_store_reg( 9); | ||
503 | __build_store_reg(10); | ||
504 | __build_store_reg(11); | ||
505 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
506 | build_addiu_a0(2 * store_offset); | ||
507 | build_addiu_a1(2 * load_offset); | ||
508 | loop_start = store_offset; | ||
509 | do { | ||
510 | __build_load_reg( 8); | ||
511 | __build_load_reg( 9); | ||
512 | __build_load_reg(10); | ||
513 | __build_load_reg(11); | ||
514 | __build_store_reg( 8); | ||
515 | __build_store_reg( 9); | ||
516 | __build_store_reg(10); | ||
517 | __build_store_reg(11); | ||
518 | } while ((store_offset - loop_start) < half_scache_line_size()); | ||
519 | build_bne(dest); | ||
520 | } | ||
521 | |||
522 | build_jr_ra(); | ||
523 | |||
524 | BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array)); | ||
525 | |||
526 | pr_info("Synthesized copy page handler (%u instructions).\n", | ||
527 | (unsigned int)(epc - copy_page_array)); | ||
528 | |||
529 | pr_debug("\t.set push\n"); | ||
530 | pr_debug("\t.set noreorder\n"); | ||
531 | for (i = 0; i < (epc - copy_page_array); i++) | ||
532 | pr_debug("\t.word 0x%08x\n", copy_page_array[i]); | ||
533 | pr_debug("\t.set pop\n"); | ||
534 | } | ||
diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c deleted file mode 100644 index 49e289d05414..000000000000 --- a/arch/mips/mm/pg-sb1.c +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | ||
3 | * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) | ||
4 | * Copyright (C) 2000 SiByte, Inc. | ||
5 | * Copyright (C) 2005 Thiemo Seufer | ||
6 | * | ||
7 | * Written by Justin Carlson of SiByte, Inc. | ||
8 | * and Kip Walker of Broadcom Corp. | ||
9 | * | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
24 | */ | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/smp.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | #include <asm/sibyte/sb1250.h> | ||
31 | #include <asm/sibyte/sb1250_regs.h> | ||
32 | #include <asm/sibyte/sb1250_dma.h> | ||
33 | |||
34 | #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS | ||
35 | #define SB1_PREF_LOAD_STREAMED_HINT "0" | ||
36 | #define SB1_PREF_STORE_STREAMED_HINT "1" | ||
37 | #else | ||
38 | #define SB1_PREF_LOAD_STREAMED_HINT "4" | ||
39 | #define SB1_PREF_STORE_STREAMED_HINT "5" | ||
40 | #endif | ||
41 | |||
42 | static inline void clear_page_cpu(void *page) | ||
43 | { | ||
44 | unsigned char *addr = (unsigned char *) page; | ||
45 | unsigned char *end = addr + PAGE_SIZE; | ||
46 | |||
47 | /* | ||
48 | * JDCXXX - This should be bottlenecked by the write buffer, but these | ||
49 | * things tend to be mildly unpredictable...should check this on the | ||
50 | * performance model | ||
51 | * | ||
52 | * We prefetch 4 lines ahead. We're also "cheating" slightly here... | ||
53 | * since we know we're on an SB1, we force the assembler to take | ||
54 | * 64-bit operands to speed things up | ||
55 | */ | ||
56 | __asm__ __volatile__( | ||
57 | " .set push \n" | ||
58 | " .set mips4 \n" | ||
59 | " .set noreorder \n" | ||
60 | #ifdef CONFIG_CPU_HAS_PREFETCH | ||
61 | " daddiu %0, %0, 128 \n" | ||
62 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%0) \n" | ||
63 | /* Prefetch the first 4 lines */ | ||
64 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%0) \n" | ||
65 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%0) \n" | ||
66 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n" | ||
67 | "1: sd $0, -128(%0) \n" /* Throw out a cacheline of 0's */ | ||
68 | " sd $0, -120(%0) \n" | ||
69 | " sd $0, -112(%0) \n" | ||
70 | " sd $0, -104(%0) \n" | ||
71 | " daddiu %0, %0, 32 \n" | ||
72 | " bnel %0, %1, 1b \n" | ||
73 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n" | ||
74 | " daddiu %0, %0, -128 \n" | ||
75 | #endif | ||
76 | " sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ | ||
77 | "1: sd $0, 8(%0) \n" | ||
78 | " sd $0, 16(%0) \n" | ||
79 | " sd $0, 24(%0) \n" | ||
80 | " daddiu %0, %0, 32 \n" | ||
81 | " bnel %0, %1, 1b \n" | ||
82 | " sd $0, 0(%0) \n" | ||
83 | " .set pop \n" | ||
84 | : "+r" (addr) | ||
85 | : "r" (end) | ||
86 | : "memory"); | ||
87 | } | ||
88 | |||
89 | static inline void copy_page_cpu(void *to, void *from) | ||
90 | { | ||
91 | unsigned char *src = (unsigned char *)from; | ||
92 | unsigned char *dst = (unsigned char *)to; | ||
93 | unsigned char *end = src + PAGE_SIZE; | ||
94 | |||
95 | /* | ||
96 | * The pref's used here are using "streaming" hints, which cause the | ||
97 | * copied data to be kicked out of the cache sooner. A page copy often | ||
98 | * ends up copying a lot more data than is commonly used, so this seems | ||
99 | * to make sense in terms of reducing cache pollution, but I've no real | ||
100 | * performance data to back this up | ||
101 | */ | ||
102 | __asm__ __volatile__( | ||
103 | " .set push \n" | ||
104 | " .set mips4 \n" | ||
105 | " .set noreorder \n" | ||
106 | #ifdef CONFIG_CPU_HAS_PREFETCH | ||
107 | " daddiu %0, %0, 128 \n" | ||
108 | " daddiu %1, %1, 128 \n" | ||
109 | " pref " SB1_PREF_LOAD_STREAMED_HINT ", -128(%0)\n" | ||
110 | /* Prefetch the first 4 lines */ | ||
111 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%1)\n" | ||
112 | " pref " SB1_PREF_LOAD_STREAMED_HINT ", -96(%0)\n" | ||
113 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%1)\n" | ||
114 | " pref " SB1_PREF_LOAD_STREAMED_HINT ", -64(%0)\n" | ||
115 | " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%1)\n" | ||
116 | " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n" | ||
117 | "1: pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%1)\n" | ||
118 | # ifdef CONFIG_64BIT | ||
119 | " ld $8, -128(%0) \n" /* Block copy a cacheline */ | ||
120 | " ld $9, -120(%0) \n" | ||
121 | " ld $10, -112(%0) \n" | ||
122 | " ld $11, -104(%0) \n" | ||
123 | " sd $8, -128(%1) \n" | ||
124 | " sd $9, -120(%1) \n" | ||
125 | " sd $10, -112(%1) \n" | ||
126 | " sd $11, -104(%1) \n" | ||
127 | # else | ||
128 | " lw $2, -128(%0) \n" /* Block copy a cacheline */ | ||
129 | " lw $3, -124(%0) \n" | ||
130 | " lw $6, -120(%0) \n" | ||
131 | " lw $7, -116(%0) \n" | ||
132 | " lw $8, -112(%0) \n" | ||
133 | " lw $9, -108(%0) \n" | ||
134 | " lw $10, -104(%0) \n" | ||
135 | " lw $11, -100(%0) \n" | ||
136 | " sw $2, -128(%1) \n" | ||
137 | " sw $3, -124(%1) \n" | ||
138 | " sw $6, -120(%1) \n" | ||
139 | " sw $7, -116(%1) \n" | ||
140 | " sw $8, -112(%1) \n" | ||
141 | " sw $9, -108(%1) \n" | ||
142 | " sw $10, -104(%1) \n" | ||
143 | " sw $11, -100(%1) \n" | ||
144 | # endif | ||
145 | " daddiu %0, %0, 32 \n" | ||
146 | " daddiu %1, %1, 32 \n" | ||
147 | " bnel %0, %2, 1b \n" | ||
148 | " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n" | ||
149 | " daddiu %0, %0, -128 \n" | ||
150 | " daddiu %1, %1, -128 \n" | ||
151 | #endif | ||
152 | #ifdef CONFIG_64BIT | ||
153 | " ld $8, 0(%0) \n" /* Block copy a cacheline */ | ||
154 | "1: ld $9, 8(%0) \n" | ||
155 | " ld $10, 16(%0) \n" | ||
156 | " ld $11, 24(%0) \n" | ||
157 | " sd $8, 0(%1) \n" | ||
158 | " sd $9, 8(%1) \n" | ||
159 | " sd $10, 16(%1) \n" | ||
160 | " sd $11, 24(%1) \n" | ||
161 | #else | ||
162 | " lw $2, 0(%0) \n" /* Block copy a cacheline */ | ||
163 | "1: lw $3, 4(%0) \n" | ||
164 | " lw $6, 8(%0) \n" | ||
165 | " lw $7, 12(%0) \n" | ||
166 | " lw $8, 16(%0) \n" | ||
167 | " lw $9, 20(%0) \n" | ||
168 | " lw $10, 24(%0) \n" | ||
169 | " lw $11, 28(%0) \n" | ||
170 | " sw $2, 0(%1) \n" | ||
171 | " sw $3, 4(%1) \n" | ||
172 | " sw $6, 8(%1) \n" | ||
173 | " sw $7, 12(%1) \n" | ||
174 | " sw $8, 16(%1) \n" | ||
175 | " sw $9, 20(%1) \n" | ||
176 | " sw $10, 24(%1) \n" | ||
177 | " sw $11, 28(%1) \n" | ||
178 | #endif | ||
179 | " daddiu %0, %0, 32 \n" | ||
180 | " daddiu %1, %1, 32 \n" | ||
181 | " bnel %0, %2, 1b \n" | ||
182 | #ifdef CONFIG_64BIT | ||
183 | " ld $8, 0(%0) \n" | ||
184 | #else | ||
185 | " lw $2, 0(%0) \n" | ||
186 | #endif | ||
187 | " .set pop \n" | ||
188 | : "+r" (src), "+r" (dst) | ||
189 | : "r" (end) | ||
190 | #ifdef CONFIG_64BIT | ||
191 | : "$8", "$9", "$10", "$11", "memory"); | ||
192 | #else | ||
193 | : "$2", "$3", "$6", "$7", "$8", "$9", "$10", "$11", "memory"); | ||
194 | #endif | ||
195 | } | ||
196 | |||
197 | |||
198 | #ifdef CONFIG_SIBYTE_DMA_PAGEOPS | ||
199 | |||
200 | /* | ||
201 | * Pad descriptors to cacheline, since each is exclusively owned by a | ||
202 | * particular CPU. | ||
203 | */ | ||
204 | typedef struct dmadscr_s { | ||
205 | u64 dscr_a; | ||
206 | u64 dscr_b; | ||
207 | u64 pad_a; | ||
208 | u64 pad_b; | ||
209 | } dmadscr_t; | ||
210 | |||
211 | static dmadscr_t page_descr[DM_NUM_CHANNELS] | ||
212 | __attribute__((aligned(SMP_CACHE_BYTES))); | ||
213 | |||
214 | void sb1_dma_init(void) | ||
215 | { | ||
216 | int i; | ||
217 | |||
218 | for (i = 0; i < DM_NUM_CHANNELS; i++) { | ||
219 | const u64 base_val = CPHYSADDR((unsigned long)&page_descr[i]) | | ||
220 | V_DM_DSCR_BASE_RINGSZ(1); | ||
221 | void *base_reg = IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE)); | ||
222 | |||
223 | __raw_writeq(base_val, base_reg); | ||
224 | __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg); | ||
225 | __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | void clear_page(void *page) | ||
230 | { | ||
231 | u64 to_phys = CPHYSADDR((unsigned long)page); | ||
232 | unsigned int cpu = smp_processor_id(); | ||
233 | |||
234 | /* if the page is not in KSEG0, use old way */ | ||
235 | if ((long)KSEGX((unsigned long)page) != (long)CKSEG0) | ||
236 | return clear_page_cpu(page); | ||
237 | |||
238 | page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | | ||
239 | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT; | ||
240 | page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); | ||
241 | __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); | ||
242 | |||
243 | /* | ||
244 | * Don't really want to do it this way, but there's no | ||
245 | * reliable way to delay completion detection. | ||
246 | */ | ||
247 | while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) | ||
248 | & M_DM_DSCR_BASE_INTERRUPT)) | ||
249 | ; | ||
250 | __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); | ||
251 | } | ||
252 | |||
253 | void copy_page(void *to, void *from) | ||
254 | { | ||
255 | u64 from_phys = CPHYSADDR((unsigned long)from); | ||
256 | u64 to_phys = CPHYSADDR((unsigned long)to); | ||
257 | unsigned int cpu = smp_processor_id(); | ||
258 | |||
259 | /* if any page is not in KSEG0, use old way */ | ||
260 | if ((long)KSEGX((unsigned long)to) != (long)CKSEG0 | ||
261 | || (long)KSEGX((unsigned long)from) != (long)CKSEG0) | ||
262 | return copy_page_cpu(to, from); | ||
263 | |||
264 | page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST | | ||
265 | M_DM_DSCRA_INTERRUPT; | ||
266 | page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE); | ||
267 | __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT))); | ||
268 | |||
269 | /* | ||
270 | * Don't really want to do it this way, but there's no | ||
271 | * reliable way to delay completion detection. | ||
272 | */ | ||
273 | while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG))) | ||
274 | & M_DM_DSCR_BASE_INTERRUPT)) | ||
275 | ; | ||
276 | __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE))); | ||
277 | } | ||
278 | |||
279 | #else /* !CONFIG_SIBYTE_DMA_PAGEOPS */ | ||
280 | |||
281 | void clear_page(void *page) | ||
282 | { | ||
283 | return clear_page_cpu(page); | ||
284 | } | ||
285 | |||
286 | void copy_page(void *to, void *from) | ||
287 | { | ||
288 | return copy_page_cpu(to, from); | ||
289 | } | ||
290 | |||
291 | #endif /* !CONFIG_SIBYTE_DMA_PAGEOPS */ | ||
292 | |||
293 | EXPORT_SYMBOL(clear_page); | ||
294 | EXPORT_SYMBOL(copy_page); | ||
295 | |||
296 | void __cpuinit build_clear_page(void) | ||
297 | { | ||
298 | } | ||
299 | |||
300 | void __cpuinit build_copy_page(void) | ||
301 | { | ||
302 | } | ||
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c index 57df1c38e303..7dfa579ab24c 100644 --- a/arch/mips/mm/pgtable.c +++ b/arch/mips/mm/pgtable.c | |||
@@ -12,7 +12,6 @@ void show_mem(void) | |||
12 | 12 | ||
13 | printk("Mem-info:\n"); | 13 | printk("Mem-info:\n"); |
14 | show_free_areas(); | 14 | show_free_areas(); |
15 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | ||
16 | pfn = max_mapnr; | 15 | pfn = max_mapnr; |
17 | while (pfn-- > 0) { | 16 | while (pfn-- > 0) { |
18 | if (!pfn_valid(pfn)) | 17 | if (!pfn_valid(pfn)) |
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 63065d6e8063..5ce2fa745626 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c | |||
@@ -299,7 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
299 | idx = read_c0_index(); | 299 | idx = read_c0_index(); |
300 | ptep = pte_offset_map(pmdp, address); | 300 | ptep = pte_offset_map(pmdp, address); |
301 | 301 | ||
302 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) | 302 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) |
303 | write_c0_entrylo0(ptep->pte_high); | 303 | write_c0_entrylo0(ptep->pte_high); |
304 | ptep++; | 304 | ptep++; |
305 | write_c0_entrylo1(ptep->pte_high); | 305 | write_c0_entrylo1(ptep->pte_high); |
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 1a6f7704cc89..1655aa69e133 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c | |||
@@ -58,13 +58,13 @@ enum opcode { | |||
58 | insn_invalid, | 58 | insn_invalid, |
59 | insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, | 59 | insn_addu, insn_addiu, insn_and, insn_andi, insn_beq, |
60 | insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, | 60 | insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, |
61 | insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0, | 61 | insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0, |
62 | insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, | 62 | insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, |
63 | insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld, | 63 | insn_dsrl32, insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, |
64 | insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0, | 64 | insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, |
65 | insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll, | 65 | insn_mtc0, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd, |
66 | insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi, | 66 | insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw, |
67 | insn_tlbwr, insn_xor, insn_xori | 67 | insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori |
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct insn { | 70 | struct insn { |
@@ -94,6 +94,7 @@ static struct insn insn_table[] __cpuinitdata = { | |||
94 | { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, | 94 | { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM }, |
95 | { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, | 95 | { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM }, |
96 | { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, | 96 | { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM }, |
97 | { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | ||
97 | { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 98 | { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
98 | { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, | 99 | { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD }, |
99 | { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, | 100 | { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET}, |
@@ -116,6 +117,7 @@ static struct insn insn_table[] __cpuinitdata = { | |||
116 | { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, | 117 | { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, |
117 | { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, | 118 | { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, |
118 | { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, | 119 | { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, |
120 | { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | ||
119 | { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, | 121 | { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 }, |
120 | { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 122 | { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
121 | { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, | 123 | { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, |
@@ -337,6 +339,7 @@ I_u1s2(_bgezl) | |||
337 | I_u1s2(_bltz) | 339 | I_u1s2(_bltz) |
338 | I_u1s2(_bltzl) | 340 | I_u1s2(_bltzl) |
339 | I_u1u2s3(_bne) | 341 | I_u1u2s3(_bne) |
342 | I_u2s3u1(_cache) | ||
340 | I_u1u2u3(_dmfc0) | 343 | I_u1u2u3(_dmfc0) |
341 | I_u1u2u3(_dmtc0) | 344 | I_u1u2u3(_dmtc0) |
342 | I_u2u1s3(_daddiu) | 345 | I_u2u1s3(_daddiu) |
@@ -359,6 +362,7 @@ I_u2s3u1(_lw) | |||
359 | I_u1u2u3(_mfc0) | 362 | I_u1u2u3(_mfc0) |
360 | I_u1u2u3(_mtc0) | 363 | I_u1u2u3(_mtc0) |
361 | I_u2u1u3(_ori) | 364 | I_u2u1u3(_ori) |
365 | I_u2s3u1(_pref) | ||
362 | I_0(_rfe) | 366 | I_0(_rfe) |
363 | I_u2s3u1(_sc) | 367 | I_u2s3u1(_sc) |
364 | I_u2s3u1(_scd) | 368 | I_u2s3u1(_scd) |
@@ -555,6 +559,14 @@ uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) | |||
555 | } | 559 | } |
556 | 560 | ||
557 | void __cpuinit | 561 | void __cpuinit |
562 | uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, | ||
563 | unsigned int reg2, int lid) | ||
564 | { | ||
565 | uasm_r_mips_pc16(r, *p, lid); | ||
566 | uasm_i_bne(p, reg1, reg2, 0); | ||
567 | } | ||
568 | |||
569 | void __cpuinit | ||
558 | uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) | 570 | uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid) |
559 | { | 571 | { |
560 | uasm_r_mips_pc16(r, *p, lid); | 572 | uasm_r_mips_pc16(r, *p, lid); |
diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h index fe0574f6e77d..0d6a66f32030 100644 --- a/arch/mips/mm/uasm.h +++ b/arch/mips/mm/uasm.h | |||
@@ -55,6 +55,7 @@ Ip_u1s2(_bgezl); | |||
55 | Ip_u1s2(_bltz); | 55 | Ip_u1s2(_bltz); |
56 | Ip_u1s2(_bltzl); | 56 | Ip_u1s2(_bltzl); |
57 | Ip_u1u2s3(_bne); | 57 | Ip_u1u2s3(_bne); |
58 | Ip_u2s3u1(_cache); | ||
58 | Ip_u1u2u3(_dmfc0); | 59 | Ip_u1u2u3(_dmfc0); |
59 | Ip_u1u2u3(_dmtc0); | 60 | Ip_u1u2u3(_dmtc0); |
60 | Ip_u2u1s3(_daddiu); | 61 | Ip_u2u1s3(_daddiu); |
@@ -77,6 +78,7 @@ Ip_u2s3u1(_lw); | |||
77 | Ip_u1u2u3(_mfc0); | 78 | Ip_u1u2u3(_mfc0); |
78 | Ip_u1u2u3(_mtc0); | 79 | Ip_u1u2u3(_mtc0); |
79 | Ip_u2u1u3(_ori); | 80 | Ip_u2u1u3(_ori); |
81 | Ip_u2s3u1(_pref); | ||
80 | Ip_0(_rfe); | 82 | Ip_0(_rfe); |
81 | Ip_u2s3u1(_sc); | 83 | Ip_u2s3u1(_sc); |
82 | Ip_u2s3u1(_scd); | 84 | Ip_u2s3u1(_scd); |
@@ -177,6 +179,8 @@ void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | |||
177 | void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid); | 179 | void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid); |
178 | void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 180 | void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
179 | void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 181 | void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
182 | void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1, | ||
183 | unsigned int reg2, int lid); | ||
180 | void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 184 | void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
181 | void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 185 | void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
182 | void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); | 186 | void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid); |
diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/nxp/pnx8550/common/Makefile index 31cc1a5cec3b..31cc1a5cec3b 100644 --- a/arch/mips/philips/pnx8550/common/Makefile +++ b/arch/mips/nxp/pnx8550/common/Makefile | |||
diff --git a/arch/mips/philips/pnx8550/common/gdb_hook.c b/arch/mips/nxp/pnx8550/common/gdb_hook.c index ad4624f6d9bc..ad4624f6d9bc 100644 --- a/arch/mips/philips/pnx8550/common/gdb_hook.c +++ b/arch/mips/nxp/pnx8550/common/gdb_hook.c | |||
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/nxp/pnx8550/common/int.c index aad03429a5e3..aad03429a5e3 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/nxp/pnx8550/common/int.c | |||
diff --git a/arch/mips/philips/pnx8550/common/pci.c b/arch/mips/nxp/pnx8550/common/pci.c index eee4f3dfc410..eee4f3dfc410 100644 --- a/arch/mips/philips/pnx8550/common/pci.c +++ b/arch/mips/nxp/pnx8550/common/pci.c | |||
diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/nxp/pnx8550/common/platform.c index c839436bd012..c7c763dbe588 100644 --- a/arch/mips/philips/pnx8550/common/platform.c +++ b/arch/mips/nxp/pnx8550/common/platform.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Platform device support for Philips PNX8550 SoCs | 2 | * Platform device support for NXP PNX8550 SoCs |
3 | * | 3 | * |
4 | * Copyright 2005, Embedded Alley Solutions, Inc | 4 | * Copyright 2005, Embedded Alley Solutions, Inc |
5 | * | 5 | * |
diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/nxp/pnx8550/common/proc.c index 18b125e3b65d..18b125e3b65d 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/nxp/pnx8550/common/proc.c | |||
diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/nxp/pnx8550/common/prom.c index 2f567452e7ac..2f567452e7ac 100644 --- a/arch/mips/philips/pnx8550/common/prom.c +++ b/arch/mips/nxp/pnx8550/common/prom.c | |||
diff --git a/arch/mips/philips/pnx8550/common/reset.c b/arch/mips/nxp/pnx8550/common/reset.c index 7b2cbc5b2c7c..7b2cbc5b2c7c 100644 --- a/arch/mips/philips/pnx8550/common/reset.c +++ b/arch/mips/nxp/pnx8550/common/reset.c | |||
diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/nxp/pnx8550/common/setup.c index 92d764c97701..92d764c97701 100644 --- a/arch/mips/philips/pnx8550/common/setup.c +++ b/arch/mips/nxp/pnx8550/common/setup.c | |||
diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/nxp/pnx8550/common/time.c index 62f495b57f93..62f495b57f93 100644 --- a/arch/mips/philips/pnx8550/common/time.c +++ b/arch/mips/nxp/pnx8550/common/time.c | |||
diff --git a/arch/mips/philips/pnx8550/jbs/Makefile b/arch/mips/nxp/pnx8550/jbs/Makefile index e8228dbca8f6..ad6a8ca7d8ce 100644 --- a/arch/mips/philips/pnx8550/jbs/Makefile +++ b/arch/mips/nxp/pnx8550/jbs/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | 1 | ||
2 | # Makefile for the Philips JBS Board. | 2 | # Makefile for the NXP JBS Board. |
3 | 3 | ||
4 | lib-y := init.o board_setup.o irqmap.o | 4 | lib-y := init.o board_setup.o irqmap.o |
diff --git a/arch/mips/philips/pnx8550/jbs/board_setup.c b/arch/mips/nxp/pnx8550/jbs/board_setup.c index f92826e0096d..f92826e0096d 100644 --- a/arch/mips/philips/pnx8550/jbs/board_setup.c +++ b/arch/mips/nxp/pnx8550/jbs/board_setup.c | |||
diff --git a/arch/mips/philips/pnx8550/jbs/init.c b/arch/mips/nxp/pnx8550/jbs/init.c index 90b4d35f3ece..d59b4a4e5e8b 100644 --- a/arch/mips/philips/pnx8550/jbs/init.c +++ b/arch/mips/nxp/pnx8550/jbs/init.c | |||
@@ -40,7 +40,7 @@ extern char *prom_getenv(char *envname); | |||
40 | 40 | ||
41 | const char *get_system_type(void) | 41 | const char *get_system_type(void) |
42 | { | 42 | { |
43 | return "Philips PNX8550/JBS"; | 43 | return "NXP PNX8550/JBS"; |
44 | } | 44 | } |
45 | 45 | ||
46 | void __init prom_init(void) | 46 | void __init prom_init(void) |
diff --git a/arch/mips/philips/pnx8550/jbs/irqmap.c b/arch/mips/nxp/pnx8550/jbs/irqmap.c index 98c3429e6e50..7fc89842002c 100644 --- a/arch/mips/philips/pnx8550/jbs/irqmap.c +++ b/arch/mips/nxp/pnx8550/jbs/irqmap.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Philips JBS board irqmap. | 2 | * NXP JBS board irqmap. |
3 | * | 3 | * |
4 | * Copyright 2005 Embedded Alley Solutions, Inc | 4 | * Copyright 2005 Embedded Alley Solutions, Inc |
5 | * source@embeddealley.com | 5 | * source@embeddealley.com |
@@ -33,4 +33,3 @@ char pnx8550_irq_tab[][5] __initdata = { | |||
33 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | 33 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, |
34 | [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | 34 | [17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, |
35 | }; | 35 | }; |
36 | |||
diff --git a/arch/mips/philips/pnx8550/stb810/Makefile b/arch/mips/nxp/pnx8550/stb810/Makefile index f14b592af398..ab91d72c5664 100644 --- a/arch/mips/philips/pnx8550/stb810/Makefile +++ b/arch/mips/nxp/pnx8550/stb810/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | 1 | ||
2 | # Makefile for the Philips STB810 Board. | 2 | # Makefile for the NXP STB810 Board. |
3 | 3 | ||
4 | lib-y := prom_init.o board_setup.o irqmap.o | 4 | lib-y := prom_init.o board_setup.o irqmap.o |
diff --git a/arch/mips/philips/pnx8550/stb810/board_setup.c b/arch/mips/nxp/pnx8550/stb810/board_setup.c index 345d71e53cf2..1282c27cfcb7 100644 --- a/arch/mips/philips/pnx8550/stb810/board_setup.c +++ b/arch/mips/nxp/pnx8550/stb810/board_setup.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * STB810 specific board startup routines. | 2 | * STB810 specific board startup routines. |
3 | * | 3 | * |
4 | * Based on the arch/mips/philips/pnx8550/jbs/board_setup.c | 4 | * Based on the arch/mips/nxp/pnx8550/jbs/board_setup.c |
5 | * | 5 | * |
6 | * Author: MontaVista Software, Inc. | 6 | * Author: MontaVista Software, Inc. |
7 | * source@mvista.com | 7 | * source@mvista.com |
diff --git a/arch/mips/philips/pnx8550/stb810/irqmap.c b/arch/mips/nxp/pnx8550/stb810/irqmap.c index 5ee11e19975e..8c034963ddcd 100644 --- a/arch/mips/philips/pnx8550/stb810/irqmap.c +++ b/arch/mips/nxp/pnx8550/stb810/irqmap.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Philips STB810 board irqmap. | 2 | * NXP STB810 board irqmap. |
3 | * | 3 | * |
4 | * Author: MontaVista Software, Inc. | 4 | * Author: MontaVista Software, Inc. |
5 | * source@mvista.com | 5 | * source@mvista.com |
@@ -20,4 +20,3 @@ char pnx8550_irq_tab[][5] __initdata = { | |||
20 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | 20 | [9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, |
21 | [10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, | 21 | [10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff}, |
22 | }; | 22 | }; |
23 | |||
diff --git a/arch/mips/philips/pnx8550/stb810/prom_init.c b/arch/mips/nxp/pnx8550/stb810/prom_init.c index 832dd60b0a7a..ca7f4ada0640 100644 --- a/arch/mips/philips/pnx8550/stb810/prom_init.c +++ b/arch/mips/nxp/pnx8550/stb810/prom_init.c | |||
@@ -28,7 +28,7 @@ extern char *prom_getenv(char *envname); | |||
28 | 28 | ||
29 | const char *get_system_type(void) | 29 | const char *get_system_type(void) |
30 | { | 30 | { |
31 | return "Philips PNX8550/STB810"; | 31 | return "NXP PNX8950/STB810"; |
32 | } | 32 | } |
33 | 33 | ||
34 | void __init prom_init(void) | 34 | void __init prom_init(void) |
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index aa52aa146cea..b5f6f71b27bc 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c | |||
@@ -80,6 +80,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) | |||
80 | case CPU_24K: | 80 | case CPU_24K: |
81 | case CPU_25KF: | 81 | case CPU_25KF: |
82 | case CPU_34K: | 82 | case CPU_34K: |
83 | case CPU_1004K: | ||
83 | case CPU_74K: | 84 | case CPU_74K: |
84 | case CPU_SB1: | 85 | case CPU_SB1: |
85 | case CPU_SB1A: | 86 | case CPU_SB1A: |
diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h index fa6b4aae7523..2bfc17c30106 100644 --- a/arch/mips/oprofile/op_impl.h +++ b/arch/mips/oprofile/op_impl.h | |||
@@ -10,7 +10,6 @@ | |||
10 | #ifndef OP_IMPL_H | 10 | #ifndef OP_IMPL_H |
11 | #define OP_IMPL_H 1 | 11 | #define OP_IMPL_H 1 |
12 | 12 | ||
13 | extern int null_perf_irq(void); | ||
14 | extern int (*perf_irq)(void); | 13 | extern int (*perf_irq)(void); |
15 | 14 | ||
16 | /* Per-counter configuration as set via oprofilefs. */ | 15 | /* Per-counter configuration as set via oprofilefs. */ |
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index ccbea229a0e6..da8cbb6899dc 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c | |||
@@ -31,9 +31,14 @@ | |||
31 | 31 | ||
32 | #define M_COUNTER_OVERFLOW (1UL << 31) | 32 | #define M_COUNTER_OVERFLOW (1UL << 31) |
33 | 33 | ||
34 | static int (*save_perf_irq)(void); | ||
35 | |||
34 | #ifdef CONFIG_MIPS_MT_SMP | 36 | #ifdef CONFIG_MIPS_MT_SMP |
35 | #define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id())) | 37 | static int cpu_has_mipsmt_pertccounters; |
36 | #define vpe_id() smp_processor_id() | 38 | #define WHAT (M_TC_EN_VPE | \ |
39 | M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id)) | ||
40 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
41 | 0 : cpu_data[smp_processor_id()].vpe_id) | ||
37 | 42 | ||
38 | /* | 43 | /* |
39 | * The number of bits to shift to convert between counters per core and | 44 | * The number of bits to shift to convert between counters per core and |
@@ -243,11 +248,11 @@ static inline int __n_counters(void) | |||
243 | { | 248 | { |
244 | if (!(read_c0_config1() & M_CONFIG1_PC)) | 249 | if (!(read_c0_config1() & M_CONFIG1_PC)) |
245 | return 0; | 250 | return 0; |
246 | if (!(r_c0_perfctrl0() & M_PERFCTL_MORE)) | 251 | if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) |
247 | return 1; | 252 | return 1; |
248 | if (!(r_c0_perfctrl1() & M_PERFCTL_MORE)) | 253 | if (!(read_c0_perfctrl1() & M_PERFCTL_MORE)) |
249 | return 2; | 254 | return 2; |
250 | if (!(r_c0_perfctrl2() & M_PERFCTL_MORE)) | 255 | if (!(read_c0_perfctrl2() & M_PERFCTL_MORE)) |
251 | return 3; | 256 | return 3; |
252 | 257 | ||
253 | return 4; | 258 | return 4; |
@@ -274,8 +279,9 @@ static inline int n_counters(void) | |||
274 | return counters; | 279 | return counters; |
275 | } | 280 | } |
276 | 281 | ||
277 | static inline void reset_counters(int counters) | 282 | static void reset_counters(void *arg) |
278 | { | 283 | { |
284 | int counters = (int)arg; | ||
279 | switch (counters) { | 285 | switch (counters) { |
280 | case 4: | 286 | case 4: |
281 | w_c0_perfctrl3(0); | 287 | w_c0_perfctrl3(0); |
@@ -302,9 +308,12 @@ static int __init mipsxx_init(void) | |||
302 | return -ENODEV; | 308 | return -ENODEV; |
303 | } | 309 | } |
304 | 310 | ||
305 | reset_counters(counters); | 311 | #ifdef CONFIG_MIPS_MT_SMP |
306 | 312 | cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19); | |
307 | counters = counters_total_to_per_cpu(counters); | 313 | if (!cpu_has_mipsmt_pertccounters) |
314 | counters = counters_total_to_per_cpu(counters); | ||
315 | #endif | ||
316 | on_each_cpu(reset_counters, (void *)counters, 0, 1); | ||
308 | 317 | ||
309 | op_model_mipsxx_ops.num_counters = counters; | 318 | op_model_mipsxx_ops.num_counters = counters; |
310 | switch (current_cpu_type()) { | 319 | switch (current_cpu_type()) { |
@@ -320,6 +329,13 @@ static int __init mipsxx_init(void) | |||
320 | op_model_mipsxx_ops.cpu_type = "mips/25K"; | 329 | op_model_mipsxx_ops.cpu_type = "mips/25K"; |
321 | break; | 330 | break; |
322 | 331 | ||
332 | case CPU_1004K: | ||
333 | #if 0 | ||
334 | /* FIXME: report as 34K for now */ | ||
335 | op_model_mipsxx_ops.cpu_type = "mips/1004K"; | ||
336 | break; | ||
337 | #endif | ||
338 | |||
323 | case CPU_34K: | 339 | case CPU_34K: |
324 | op_model_mipsxx_ops.cpu_type = "mips/34K"; | 340 | op_model_mipsxx_ops.cpu_type = "mips/34K"; |
325 | break; | 341 | break; |
@@ -355,6 +371,7 @@ static int __init mipsxx_init(void) | |||
355 | return -ENODEV; | 371 | return -ENODEV; |
356 | } | 372 | } |
357 | 373 | ||
374 | save_perf_irq = perf_irq; | ||
358 | perf_irq = mipsxx_perfcount_handler; | 375 | perf_irq = mipsxx_perfcount_handler; |
359 | 376 | ||
360 | return 0; | 377 | return 0; |
@@ -365,9 +382,9 @@ static void mipsxx_exit(void) | |||
365 | int counters = op_model_mipsxx_ops.num_counters; | 382 | int counters = op_model_mipsxx_ops.num_counters; |
366 | 383 | ||
367 | counters = counters_per_cpu_to_total(counters); | 384 | counters = counters_per_cpu_to_total(counters); |
368 | reset_counters(counters); | 385 | on_each_cpu(reset_counters, (void *)counters, 0, 1); |
369 | 386 | ||
370 | perf_irq = null_perf_irq; | 387 | perf_irq = save_perf_irq; |
371 | } | 388 | } |
372 | 389 | ||
373 | struct op_mips_model op_model_mipsxx_ops = { | 390 | struct op_mips_model op_model_mipsxx_ops = { |
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c index ca0276c8070a..00c36c9dbe0e 100644 --- a/arch/mips/pci/fixup-au1000.c +++ b/arch/mips/pci/fixup-au1000.c | |||
@@ -26,13 +26,10 @@ | |||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | 26 | * with this program; if not, write to the Free Software Foundation, Inc., |
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 27 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
28 | */ | 28 | */ |
29 | #include <linux/types.h> | 29 | |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <linux/kernel.h> | ||
32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
33 | 32 | ||
34 | #include <asm/mach-au1x00/au1000.h> | ||
35 | |||
36 | extern char irq_tab_alchemy[][5]; | 33 | extern char irq_tab_alchemy[][5]; |
37 | 34 | ||
38 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 35 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c index d61064652498..0e160d9f07c3 100644 --- a/arch/mips/pci/ops-pnx8550.c +++ b/arch/mips/pci/ops-pnx8550.c | |||
@@ -90,14 +90,14 @@ config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int | |||
90 | 90 | ||
91 | loops--; | 91 | loops--; |
92 | if (loops == 0) { | 92 | if (loops == 0) { |
93 | printk("%s : Arbiter Locked.\n", __FUNCTION__); | 93 | printk("%s : Arbiter Locked.\n", __func__); |
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | clear_status(); | 97 | clear_status(); |
98 | if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) { | 98 | if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) { |
99 | printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n", | 99 | printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n", |
100 | __FUNCTION__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, | 100 | __func__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, |
101 | pci_cmd); | 101 | pci_cmd); |
102 | } | 102 | } |
103 | 103 | ||
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 855977ca51cd..6537d90a25bb 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c | |||
@@ -143,9 +143,6 @@ void __init plat_time_init(void) | |||
143 | mips_hpt_frequency = 33000000 * 3 * 5; | 143 | mips_hpt_frequency = 33000000 * 3 * 5; |
144 | } | 144 | } |
145 | 145 | ||
146 | /* No other usable initialization hook than this ... */ | ||
147 | extern void (*late_time_init)(void); | ||
148 | |||
149 | unsigned long ocd_base; | 146 | unsigned long ocd_base; |
150 | 147 | ||
151 | EXPORT_SYMBOL(ocd_base); | 148 | EXPORT_SYMBOL(ocd_base); |
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 624bbdbff2a8..b6cab089561e 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c | |||
@@ -142,7 +142,7 @@ static irqreturn_t ip32_rtc_int(int irq, void *dev_id) | |||
142 | reg_c = CMOS_READ(RTC_INTR_FLAGS); | 142 | reg_c = CMOS_READ(RTC_INTR_FLAGS); |
143 | if (!(reg_c & RTC_IRQF)) { | 143 | if (!(reg_c & RTC_IRQF)) { |
144 | printk(KERN_WARNING | 144 | printk(KERN_WARNING |
145 | "%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__); | 145 | "%s: RTC IRQ without RTC_IRQF\n", __func__); |
146 | } | 146 | } |
147 | /* Wait until interrupt goes away */ | 147 | /* Wait until interrupt goes away */ |
148 | disable_irq(MACEISA_RTC_IRQ); | 148 | disable_irq(MACEISA_RTC_IRQ); |
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index 3f808b629242..6d31f2a98abf 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c | |||
@@ -173,7 +173,7 @@ static const u32 toshiba_rbtx4927_irq_debug_flag = | |||
173 | { \ | 173 | { \ |
174 | char tmp[100]; \ | 174 | char tmp[100]; \ |
175 | sprintf( tmp, str ); \ | 175 | sprintf( tmp, str ); \ |
176 | printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ | 176 | printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \ |
177 | } | 177 | } |
178 | #else | 178 | #else |
179 | #define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag, str...) | 179 | #define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag, str...) |
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index e466e5e711d8..2203c77b2ce2 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c | |||
@@ -93,7 +93,7 @@ static const u32 toshiba_rbtx4927_setup_debug_flag = | |||
93 | { \ | 93 | { \ |
94 | char tmp[100]; \ | 94 | char tmp[100]; \ |
95 | sprintf( tmp, str ); \ | 95 | sprintf( tmp, str ); \ |
96 | printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \ | 96 | printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \ |
97 | } | 97 | } |
98 | #else | 98 | #else |
99 | #define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag, str...) | 99 | #define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag, str...) |
diff --git a/arch/mips/tx4938/common/dbgio.c b/arch/mips/tx4938/common/dbgio.c index bea59ff1842a..33b9c672a322 100644 --- a/arch/mips/tx4938/common/dbgio.c +++ b/arch/mips/tx4938/common/dbgio.c | |||
@@ -31,9 +31,7 @@ | |||
31 | * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp> | 31 | * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp> |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <asm/mipsregs.h> | 34 | #include <linux/types> |
35 | #include <asm/system.h> | ||
36 | #include <asm/tx4938/tx4938_mips.h> | ||
37 | 35 | ||
38 | extern u8 txx9_sio_kdbg_rd(void); | 36 | extern u8 txx9_sio_kdbg_rd(void); |
39 | extern int txx9_sio_kdbg_wr( u8 ch ); | 37 | extern int txx9_sio_kdbg_wr( u8 ch ); |
diff --git a/arch/mips/tx4938/common/prom.c b/arch/mips/tx4938/common/prom.c index 3189a65f7d7e..20baeaeba4cd 100644 --- a/arch/mips/tx4938/common/prom.c +++ b/arch/mips/tx4938/common/prom.c | |||
@@ -13,13 +13,8 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/types.h> |
17 | #include <linux/sched.h> | 17 | #include <linux/io.h> |
18 | #include <linux/bootmem.h> | ||
19 | |||
20 | #include <asm/addrspace.h> | ||
21 | #include <asm/bootinfo.h> | ||
22 | #include <asm/tx4938/tx4938.h> | ||
23 | 18 | ||
24 | static unsigned int __init | 19 | static unsigned int __init |
25 | tx4938_process_sdccr(u64 * addr) | 20 | tx4938_process_sdccr(u64 * addr) |
@@ -35,7 +30,7 @@ tx4938_process_sdccr(u64 * addr) | |||
35 | unsigned int bc = 4; | 30 | unsigned int bc = 4; |
36 | unsigned int msize = 0; | 31 | unsigned int msize = 0; |
37 | 32 | ||
38 | val = (*((vu64 *) (addr))); | 33 | val = ____raw_readq((void __iomem *)addr); |
39 | 34 | ||
40 | /* MVMCP -- need #defs for these bits masks */ | 35 | /* MVMCP -- need #defs for these bits masks */ |
41 | sdccr_ce = ((val & (1 << 10)) >> 10); | 36 | sdccr_ce = ((val & (1 << 10)) >> 10); |
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index f00185017e80..4d6a8dc46c76 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c | |||
@@ -67,24 +67,7 @@ IRQ Device | |||
67 | 63 RBTX4938-IOC/07 SWINT | 67 | 63 RBTX4938-IOC/07 SWINT |
68 | */ | 68 | */ |
69 | #include <linux/init.h> | 69 | #include <linux/init.h> |
70 | #include <linux/kernel.h> | ||
71 | #include <linux/types.h> | ||
72 | #include <linux/mm.h> | ||
73 | #include <linux/swap.h> | ||
74 | #include <linux/ioport.h> | ||
75 | #include <linux/sched.h> | ||
76 | #include <linux/interrupt.h> | 70 | #include <linux/interrupt.h> |
77 | #include <linux/pci.h> | ||
78 | #include <linux/timex.h> | ||
79 | #include <asm/bootinfo.h> | ||
80 | #include <asm/page.h> | ||
81 | #include <asm/io.h> | ||
82 | #include <asm/irq.h> | ||
83 | #include <asm/processor.h> | ||
84 | #include <asm/reboot.h> | ||
85 | #include <asm/time.h> | ||
86 | #include <asm/wbflush.h> | ||
87 | #include <linux/bootmem.h> | ||
88 | #include <asm/tx4938/rbtx4938.h> | 71 | #include <asm/tx4938/rbtx4938.h> |
89 | 72 | ||
90 | static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); | 73 | static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); |
@@ -99,21 +82,16 @@ static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { | |||
99 | .unmask = toshiba_rbtx4938_irq_ioc_enable, | 82 | .unmask = toshiba_rbtx4938_irq_ioc_enable, |
100 | }; | 83 | }; |
101 | 84 | ||
102 | #define TOSHIBA_RBTX4938_IOC_INTR_ENAB 0xb7f02000 | ||
103 | #define TOSHIBA_RBTX4938_IOC_INTR_STAT 0xb7f0200a | ||
104 | |||
105 | int | 85 | int |
106 | toshiba_rbtx4938_irq_nested(int sw_irq) | 86 | toshiba_rbtx4938_irq_nested(int sw_irq) |
107 | { | 87 | { |
108 | u8 level3; | 88 | u8 level3; |
109 | 89 | ||
110 | level3 = reg_rd08(TOSHIBA_RBTX4938_IOC_INTR_STAT) & 0xff; | 90 | level3 = readb(rbtx4938_imstat_addr); |
111 | if (level3) { | 91 | if (level3) |
112 | /* must use fls so onboard ATA has priority */ | 92 | /* must use fls so onboard ATA has priority */ |
113 | sw_irq = TOSHIBA_RBTX4938_IRQ_IOC_BEG + fls(level3) - 1; | 93 | sw_irq = TOSHIBA_RBTX4938_IRQ_IOC_BEG + fls(level3) - 1; |
114 | } | ||
115 | 94 | ||
116 | wbflush(); | ||
117 | return sw_irq; | 95 | return sw_irq; |
118 | } | 96 | } |
119 | 97 | ||
@@ -144,25 +122,23 @@ toshiba_rbtx4938_irq_ioc_init(void) | |||
144 | static void | 122 | static void |
145 | toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) | 123 | toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) |
146 | { | 124 | { |
147 | volatile unsigned char v; | 125 | unsigned char v; |
148 | 126 | ||
149 | v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | 127 | v = readb(rbtx4938_imask_addr); |
150 | v |= (1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); | 128 | v |= (1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); |
151 | TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); | 129 | writeb(v, rbtx4938_imask_addr); |
152 | mmiowb(); | 130 | mmiowb(); |
153 | TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
154 | } | 131 | } |
155 | 132 | ||
156 | static void | 133 | static void |
157 | toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) | 134 | toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) |
158 | { | 135 | { |
159 | volatile unsigned char v; | 136 | unsigned char v; |
160 | 137 | ||
161 | v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | 138 | v = readb(rbtx4938_imask_addr); |
162 | v &= ~(1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); | 139 | v &= ~(1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG)); |
163 | TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v); | 140 | writeb(v, rbtx4938_imask_addr); |
164 | mmiowb(); | 141 | mmiowb(); |
165 | TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB); | ||
166 | } | 142 | } |
167 | 143 | ||
168 | void __init arch_init_irq(void) | 144 | void __init arch_init_irq(void) |
@@ -174,14 +150,12 @@ void __init arch_init_irq(void) | |||
174 | /* all IRC interrupt mode are Low Active. */ | 150 | /* all IRC interrupt mode are Low Active. */ |
175 | 151 | ||
176 | /* mask all IOC interrupts */ | 152 | /* mask all IOC interrupts */ |
177 | *rbtx4938_imask_ptr = 0; | 153 | writeb(0, rbtx4938_imask_addr); |
178 | 154 | ||
179 | /* clear SoftInt interrupts */ | 155 | /* clear SoftInt interrupts */ |
180 | *rbtx4938_softint_ptr = 0; | 156 | writeb(0, rbtx4938_softint_addr); |
181 | tx4938_irq_init(); | 157 | tx4938_irq_init(); |
182 | toshiba_rbtx4938_irq_ioc_init(); | 158 | toshiba_rbtx4938_irq_ioc_init(); |
183 | /* Onboard 10M Ether: High Active */ | 159 | /* Onboard 10M Ether: High Active */ |
184 | set_irq_type(RBTX4938_IRQ_ETHER, IRQF_TRIGGER_HIGH); | 160 | set_irq_type(RBTX4938_IRQ_ETHER, IRQF_TRIGGER_HIGH); |
185 | |||
186 | wbflush(); | ||
187 | } | 161 | } |
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c index 61249f049cd6..3a3659e8633a 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c | |||
@@ -21,8 +21,8 @@ | |||
21 | #include <linux/pm.h> | 21 | #include <linux/pm.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/gpio.h> | ||
24 | 25 | ||
25 | #include <asm/wbflush.h> | ||
26 | #include <asm/reboot.h> | 26 | #include <asm/reboot.h> |
27 | #include <asm/time.h> | 27 | #include <asm/time.h> |
28 | #include <asm/txx9tmr.h> | 28 | #include <asm/txx9tmr.h> |
@@ -34,7 +34,7 @@ | |||
34 | #endif | 34 | #endif |
35 | #include <linux/spi/spi.h> | 35 | #include <linux/spi/spi.h> |
36 | #include <asm/tx4938/spi.h> | 36 | #include <asm/tx4938/spi.h> |
37 | #include <asm/gpio.h> | 37 | #include <asm/txx9pio.h> |
38 | 38 | ||
39 | extern char * __init prom_getcmdline(void); | 39 | extern char * __init prom_getcmdline(void); |
40 | static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr); | 40 | static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr); |
@@ -90,12 +90,11 @@ void rbtx4938_machine_restart(char *command) | |||
90 | local_irq_disable(); | 90 | local_irq_disable(); |
91 | 91 | ||
92 | printk("Rebooting..."); | 92 | printk("Rebooting..."); |
93 | *rbtx4938_softresetlock_ptr = 1; | 93 | writeb(1, rbtx4938_softresetlock_addr); |
94 | *rbtx4938_sfvol_ptr = 1; | 94 | writeb(1, rbtx4938_sfvol_addr); |
95 | *rbtx4938_softreset_ptr = 1; | 95 | writeb(1, rbtx4938_softreset_addr); |
96 | wbflush(); | 96 | while(1) |
97 | 97 | ; | |
98 | while(1); | ||
99 | } | 98 | } |
100 | 99 | ||
101 | void __init | 100 | void __init |
@@ -487,7 +486,7 @@ static int __init tx4938_pcibios_init(void) | |||
487 | } | 486 | } |
488 | 487 | ||
489 | /* Reset PCI Bus */ | 488 | /* Reset PCI Bus */ |
490 | *rbtx4938_pcireset_ptr = 0; | 489 | writeb(0, rbtx4938_pcireset_addr); |
491 | /* Reset PCIC */ | 490 | /* Reset PCIC */ |
492 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; | 491 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; |
493 | if (txboard_pci66_mode > 0) | 492 | if (txboard_pci66_mode > 0) |
@@ -495,8 +494,8 @@ static int __init tx4938_pcibios_init(void) | |||
495 | mdelay(10); | 494 | mdelay(10); |
496 | /* clear PCIC reset */ | 495 | /* clear PCIC reset */ |
497 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; | 496 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; |
498 | *rbtx4938_pcireset_ptr = 1; | 497 | writeb(1, rbtx4938_pcireset_addr); |
499 | wbflush(); | 498 | mmiowb(); |
500 | tx4938_report_pcic_status1(tx4938_pcicptr); | 499 | tx4938_report_pcic_status1(tx4938_pcicptr); |
501 | 500 | ||
502 | tx4938_report_pciclk(); | 501 | tx4938_report_pciclk(); |
@@ -504,15 +503,15 @@ static int __init tx4938_pcibios_init(void) | |||
504 | if (txboard_pci66_mode == 0 && | 503 | if (txboard_pci66_mode == 0 && |
505 | txboard_pci66_check(&tx4938_pci_controller[0], 0, 0)) { | 504 | txboard_pci66_check(&tx4938_pci_controller[0], 0, 0)) { |
506 | /* Reset PCI Bus */ | 505 | /* Reset PCI Bus */ |
507 | *rbtx4938_pcireset_ptr = 0; | 506 | writeb(0, rbtx4938_pcireset_addr); |
508 | /* Reset PCIC */ | 507 | /* Reset PCIC */ |
509 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; | 508 | tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST; |
510 | tx4938_pciclk66_setup(); | 509 | tx4938_pciclk66_setup(); |
511 | mdelay(10); | 510 | mdelay(10); |
512 | /* clear PCIC reset */ | 511 | /* clear PCIC reset */ |
513 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; | 512 | tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST; |
514 | *rbtx4938_pcireset_ptr = 1; | 513 | writeb(1, rbtx4938_pcireset_addr); |
515 | wbflush(); | 514 | mmiowb(); |
516 | /* Reinitialize PCIC */ | 515 | /* Reinitialize PCIC */ |
517 | tx4938_report_pciclk(); | 516 | tx4938_report_pciclk(); |
518 | tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb); | 517 | tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb); |
@@ -615,9 +614,6 @@ static void __init rbtx4938_spi_setup(void) | |||
615 | { | 614 | { |
616 | /* set SPI_SEL */ | 615 | /* set SPI_SEL */ |
617 | tx4938_ccfgptr->pcfg |= TX4938_PCFG_SPI_SEL; | 616 | tx4938_ccfgptr->pcfg |= TX4938_PCFG_SPI_SEL; |
618 | /* chip selects for SPI devices */ | ||
619 | tx4938_pioptr->dout |= (1 << SEEPROM1_CS); | ||
620 | tx4938_pioptr->dir |= (1 << SEEPROM1_CS); | ||
621 | } | 617 | } |
622 | 618 | ||
623 | static struct resource rbtx4938_fpga_resource; | 619 | static struct resource rbtx4938_fpga_resource; |
@@ -776,12 +772,13 @@ void __init tx4938_board_setup(void) | |||
776 | txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); | 772 | txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); |
777 | 773 | ||
778 | /* enable DMA */ | 774 | /* enable DMA */ |
779 | TX4938_WR64(0xff1fb150, TX4938_DMA_MCR_MSTEN); | 775 | for (i = 0; i < 2; i++) |
780 | TX4938_WR64(0xff1fb950, TX4938_DMA_MCR_MSTEN); | 776 | ____raw_writeq(TX4938_DMA_MCR_MSTEN, |
777 | (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); | ||
781 | 778 | ||
782 | /* PIO */ | 779 | /* PIO */ |
783 | tx4938_pioptr->maskcpu = 0; | 780 | __raw_writel(0, &tx4938_pioptr->maskcpu); |
784 | tx4938_pioptr->maskext = 0; | 781 | __raw_writel(0, &tx4938_pioptr->maskext); |
785 | 782 | ||
786 | /* TX4938 internal registers */ | 783 | /* TX4938 internal registers */ |
787 | if (request_resource(&iomem_resource, &tx4938_reg_resource)) | 784 | if (request_resource(&iomem_resource, &tx4938_reg_resource)) |
@@ -863,10 +860,6 @@ void __init plat_mem_setup(void) | |||
863 | if (txx9_master_clock == 0) | 860 | if (txx9_master_clock == 0) |
864 | txx9_master_clock = 25000000; /* 25MHz */ | 861 | txx9_master_clock = 25000000; /* 25MHz */ |
865 | tx4938_board_setup(); | 862 | tx4938_board_setup(); |
866 | /* setup serial stuff */ | ||
867 | TX4938_WR(0xff1ff314, 0x00000000); /* h/w flow control off */ | ||
868 | TX4938_WR(0xff1ff414, 0x00000000); /* h/w flow control off */ | ||
869 | |||
870 | #ifndef CONFIG_PCI | 863 | #ifndef CONFIG_PCI |
871 | set_io_port_base(RBTX4938_ETHER_BASE); | 864 | set_io_port_base(RBTX4938_ETHER_BASE); |
872 | #endif | 865 | #endif |
@@ -932,16 +925,16 @@ void __init plat_mem_setup(void) | |||
932 | pcfg = tx4938_ccfgptr->pcfg; /* updated */ | 925 | pcfg = tx4938_ccfgptr->pcfg; /* updated */ |
933 | /* fixup piosel */ | 926 | /* fixup piosel */ |
934 | if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == | 927 | if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == |
935 | TX4938_PCFG_ATA_SEL) { | 928 | TX4938_PCFG_ATA_SEL) |
936 | *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x04; | 929 | writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x04, |
937 | } | 930 | rbtx4938_piosel_addr); |
938 | else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == | 931 | else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == |
939 | TX4938_PCFG_NDF_SEL) { | 932 | TX4938_PCFG_NDF_SEL) |
940 | *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x08; | 933 | writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x08, |
941 | } | 934 | rbtx4938_piosel_addr); |
942 | else { | 935 | else |
943 | *rbtx4938_piosel_ptr &= ~(0x08 | 0x04); | 936 | writeb(readb(rbtx4938_piosel_addr) & ~(0x08 | 0x04), |
944 | } | 937 | rbtx4938_piosel_addr); |
945 | 938 | ||
946 | rbtx4938_fpga_resource.name = "FPGA Registers"; | 939 | rbtx4938_fpga_resource.name = "FPGA Registers"; |
947 | rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); | 940 | rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); |
@@ -950,17 +943,14 @@ void __init plat_mem_setup(void) | |||
950 | if (request_resource(&iomem_resource, &rbtx4938_fpga_resource)) | 943 | if (request_resource(&iomem_resource, &rbtx4938_fpga_resource)) |
951 | printk("request resource for fpga failed\n"); | 944 | printk("request resource for fpga failed\n"); |
952 | 945 | ||
953 | /* disable all OnBoard I/O interrupts */ | ||
954 | *rbtx4938_imask_ptr = 0; | ||
955 | |||
956 | _machine_restart = rbtx4938_machine_restart; | 946 | _machine_restart = rbtx4938_machine_restart; |
957 | _machine_halt = rbtx4938_machine_halt; | 947 | _machine_halt = rbtx4938_machine_halt; |
958 | pm_power_off = rbtx4938_machine_power_off; | 948 | pm_power_off = rbtx4938_machine_power_off; |
959 | 949 | ||
960 | *rbtx4938_led_ptr = 0xff; | 950 | writeb(0xff, rbtx4938_led_addr); |
961 | printk("RBTX4938 --- FPGA(Rev %02x)", *rbtx4938_fpga_rev_ptr); | 951 | printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", |
962 | printk(" DIPSW:%02x,%02x\n", | 952 | readb(rbtx4938_fpga_rev_addr), |
963 | *rbtx4938_dipsw_ptr, *rbtx4938_bdipsw_ptr); | 953 | readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); |
964 | } | 954 | } |
965 | 955 | ||
966 | static int __init rbtx4938_ne_init(void) | 956 | static int __init rbtx4938_ne_init(void) |
@@ -984,106 +974,48 @@ device_initcall(rbtx4938_ne_init); | |||
984 | 974 | ||
985 | /* GPIO support */ | 975 | /* GPIO support */ |
986 | 976 | ||
987 | static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); | 977 | int gpio_to_irq(unsigned gpio) |
988 | |||
989 | static void rbtx4938_spi_gpio_set(unsigned gpio, int value) | ||
990 | { | 978 | { |
991 | u8 val; | 979 | return -EINVAL; |
992 | unsigned long flags; | ||
993 | gpio -= 16; | ||
994 | spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags); | ||
995 | val = *rbtx4938_spics_ptr; | ||
996 | if (value) | ||
997 | val |= 1 << gpio; | ||
998 | else | ||
999 | val &= ~(1 << gpio); | ||
1000 | *rbtx4938_spics_ptr = val; | ||
1001 | mmiowb(); | ||
1002 | spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags); | ||
1003 | } | 980 | } |
1004 | 981 | ||
1005 | static int rbtx4938_spi_gpio_dir_out(unsigned gpio, int value) | 982 | int irq_to_gpio(unsigned irq) |
1006 | { | 983 | { |
1007 | rbtx4938_spi_gpio_set(gpio, value); | 984 | return -EINVAL; |
1008 | return 0; | ||
1009 | } | 985 | } |
1010 | 986 | ||
1011 | static DEFINE_SPINLOCK(tx4938_gpio_lock); | 987 | static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); |
1012 | |||
1013 | static int tx4938_gpio_get(unsigned gpio) | ||
1014 | { | ||
1015 | return tx4938_pioptr->din & (1 << gpio); | ||
1016 | } | ||
1017 | 988 | ||
1018 | static void tx4938_gpio_set_raw(unsigned gpio, int value) | 989 | static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset, |
990 | int value) | ||
1019 | { | 991 | { |
1020 | u32 val; | 992 | u8 val; |
1021 | val = tx4938_pioptr->dout; | 993 | unsigned long flags; |
994 | spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags); | ||
995 | val = readb(rbtx4938_spics_addr); | ||
1022 | if (value) | 996 | if (value) |
1023 | val |= 1 << gpio; | 997 | val |= 1 << offset; |
1024 | else | 998 | else |
1025 | val &= ~(1 << gpio); | 999 | val &= ~(1 << offset); |
1026 | tx4938_pioptr->dout = val; | 1000 | writeb(val, rbtx4938_spics_addr); |
1027 | } | ||
1028 | |||
1029 | static void tx4938_gpio_set(unsigned gpio, int value) | ||
1030 | { | ||
1031 | unsigned long flags; | ||
1032 | spin_lock_irqsave(&tx4938_gpio_lock, flags); | ||
1033 | tx4938_gpio_set_raw(gpio, value); | ||
1034 | mmiowb(); | ||
1035 | spin_unlock_irqrestore(&tx4938_gpio_lock, flags); | ||
1036 | } | ||
1037 | |||
1038 | static int tx4938_gpio_dir_in(unsigned gpio) | ||
1039 | { | ||
1040 | spin_lock_irq(&tx4938_gpio_lock); | ||
1041 | tx4938_pioptr->dir &= ~(1 << gpio); | ||
1042 | mmiowb(); | 1001 | mmiowb(); |
1043 | spin_unlock_irq(&tx4938_gpio_lock); | 1002 | spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags); |
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | static int tx4938_gpio_dir_out(unsigned int gpio, int value) | ||
1048 | { | ||
1049 | spin_lock_irq(&tx4938_gpio_lock); | ||
1050 | tx4938_gpio_set_raw(gpio, value); | ||
1051 | tx4938_pioptr->dir |= 1 << gpio; | ||
1052 | mmiowb(); | ||
1053 | spin_unlock_irq(&tx4938_gpio_lock); | ||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | int gpio_direction_input(unsigned gpio) | ||
1058 | { | ||
1059 | if (gpio < 16) | ||
1060 | return tx4938_gpio_dir_in(gpio); | ||
1061 | return -EINVAL; | ||
1062 | } | ||
1063 | |||
1064 | int gpio_direction_output(unsigned gpio, int value) | ||
1065 | { | ||
1066 | if (gpio < 16) | ||
1067 | return tx4938_gpio_dir_out(gpio, value); | ||
1068 | if (gpio < 16 + 3) | ||
1069 | return rbtx4938_spi_gpio_dir_out(gpio, value); | ||
1070 | return -EINVAL; | ||
1071 | } | 1003 | } |
1072 | 1004 | ||
1073 | int gpio_get_value(unsigned gpio) | 1005 | static int rbtx4938_spi_gpio_dir_out(struct gpio_chip *chip, |
1006 | unsigned int offset, int value) | ||
1074 | { | 1007 | { |
1075 | if (gpio < 16) | 1008 | rbtx4938_spi_gpio_set(chip, offset, value); |
1076 | return tx4938_gpio_get(gpio); | ||
1077 | return 0; | 1009 | return 0; |
1078 | } | 1010 | } |
1079 | 1011 | ||
1080 | void gpio_set_value(unsigned gpio, int value) | 1012 | static struct gpio_chip rbtx4938_spi_gpio_chip = { |
1081 | { | 1013 | .set = rbtx4938_spi_gpio_set, |
1082 | if (gpio < 16) | 1014 | .direction_output = rbtx4938_spi_gpio_dir_out, |
1083 | tx4938_gpio_set(gpio, value); | 1015 | .label = "RBTX4938-SPICS", |
1084 | else | 1016 | .base = 16, |
1085 | rbtx4938_spi_gpio_set(gpio, value); | 1017 | .ngpio = 3, |
1086 | } | 1018 | }; |
1087 | 1019 | ||
1088 | /* SPI support */ | 1020 | /* SPI support */ |
1089 | 1021 | ||
@@ -1094,7 +1026,6 @@ static void __init txx9_spi_init(unsigned long base, int irq) | |||
1094 | .start = base, | 1026 | .start = base, |
1095 | .end = base + 0x20 - 1, | 1027 | .end = base + 0x20 - 1, |
1096 | .flags = IORESOURCE_MEM, | 1028 | .flags = IORESOURCE_MEM, |
1097 | .parent = &tx4938_reg_resource, | ||
1098 | }, { | 1029 | }, { |
1099 | .start = irq, | 1030 | .start = irq, |
1100 | .flags = IORESOURCE_IRQ, | 1031 | .flags = IORESOURCE_IRQ, |
@@ -1118,10 +1049,25 @@ static int __init rbtx4938_spi_init(void) | |||
1118 | spi_eeprom_register(SEEPROM1_CS); | 1049 | spi_eeprom_register(SEEPROM1_CS); |
1119 | spi_eeprom_register(16 + SEEPROM2_CS); | 1050 | spi_eeprom_register(16 + SEEPROM2_CS); |
1120 | spi_eeprom_register(16 + SEEPROM3_CS); | 1051 | spi_eeprom_register(16 + SEEPROM3_CS); |
1052 | gpio_request(16 + SRTC_CS, "rtc-rs5c348"); | ||
1053 | gpio_direction_output(16 + SRTC_CS, 0); | ||
1054 | gpio_request(SEEPROM1_CS, "seeprom1"); | ||
1055 | gpio_direction_output(SEEPROM1_CS, 1); | ||
1056 | gpio_request(16 + SEEPROM2_CS, "seeprom2"); | ||
1057 | gpio_direction_output(16 + SEEPROM2_CS, 1); | ||
1058 | gpio_request(16 + SEEPROM3_CS, "seeprom3"); | ||
1059 | gpio_direction_output(16 + SEEPROM3_CS, 1); | ||
1121 | txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI); | 1060 | txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI); |
1122 | return 0; | 1061 | return 0; |
1123 | } | 1062 | } |
1124 | arch_initcall(rbtx4938_spi_init); | 1063 | |
1064 | static int __init rbtx4938_arch_init(void) | ||
1065 | { | ||
1066 | txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, 16); | ||
1067 | gpiochip_add(&rbtx4938_spi_gpio_chip); | ||
1068 | return rbtx4938_spi_init(); | ||
1069 | } | ||
1070 | arch_initcall(rbtx4938_arch_init); | ||
1125 | 1071 | ||
1126 | /* Watchdog support */ | 1072 | /* Watchdog support */ |
1127 | 1073 | ||
@@ -1131,7 +1077,6 @@ static int __init txx9_wdt_init(unsigned long base) | |||
1131 | .start = base, | 1077 | .start = base, |
1132 | .end = base + 0x100 - 1, | 1078 | .end = base + 0x100 - 1, |
1133 | .flags = IORESOURCE_MEM, | 1079 | .flags = IORESOURCE_MEM, |
1134 | .parent = &tx4938_reg_resource, | ||
1135 | }; | 1080 | }; |
1136 | struct platform_device *dev = | 1081 | struct platform_device *dev = |
1137 | platform_device_register_simple("txx9wdt", -1, &res, 1); | 1082 | platform_device_register_simple("txx9wdt", -1, &res, 1); |
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index 76d4b5ed3fc0..c64995342ba8 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * init.c, Common initialization routines for NEC VR4100 series. | 2 | * init.c, Common initialization routines for NEC VR4100 series. |
3 | * | 3 | * |
4 | * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> | 4 | * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 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 | 7 | * it under the terms of the GNU General Public License as published by |
@@ -53,6 +53,8 @@ void __init plat_time_init(void) | |||
53 | void __init plat_mem_setup(void) | 53 | void __init plat_mem_setup(void) |
54 | { | 54 | { |
55 | iomem_resource_init(); | 55 | iomem_resource_init(); |
56 | |||
57 | vr41xx_siu_setup(); | ||
56 | } | 58 | } |
57 | 59 | ||
58 | void __init prom_init(void) | 60 | void __init prom_init(void) |
diff --git a/arch/mips/vr41xx/common/siu.c b/arch/mips/vr41xx/common/siu.c index b735f45b25f0..654dee6208be 100644 --- a/arch/mips/vr41xx/common/siu.c +++ b/arch/mips/vr41xx/common/siu.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * NEC VR4100 series SIU platform device. | 2 | * NEC VR4100 series SIU platform device. |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> | 4 | * Copyright (C) 2007-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 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 | 7 | * it under the terms of the GNU General Public License as published by |
@@ -118,3 +118,37 @@ err_free_device: | |||
118 | return retval; | 118 | return retval; |
119 | } | 119 | } |
120 | device_initcall(vr41xx_siu_add); | 120 | device_initcall(vr41xx_siu_add); |
121 | |||
122 | void __init vr41xx_siu_setup(void) | ||
123 | { | ||
124 | struct uart_port port; | ||
125 | struct resource *res; | ||
126 | unsigned int *type; | ||
127 | int i; | ||
128 | |||
129 | switch (current_cpu_type()) { | ||
130 | case CPU_VR4111: | ||
131 | case CPU_VR4121: | ||
132 | type = siu_type1_ports; | ||
133 | res = siu_type1_resource; | ||
134 | break; | ||
135 | case CPU_VR4122: | ||
136 | case CPU_VR4131: | ||
137 | case CPU_VR4133: | ||
138 | type = siu_type2_ports; | ||
139 | res = siu_type2_resource; | ||
140 | break; | ||
141 | default: | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | for (i = 0; i < SIU_PORTS_MAX; i++) { | ||
146 | port.line = i; | ||
147 | port.type = type[i]; | ||
148 | if (port.type == PORT_UNKNOWN) | ||
149 | break; | ||
150 | port.mapbase = res[i].start; | ||
151 | port.membase = (unsigned char __iomem *)KSEG1ADDR(res[i].start); | ||
152 | vr41xx_siu_early_setup(&port); | ||
153 | } | ||
154 | } | ||
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c index ee2d9f8af5ad..2646fcbd7d89 100644 --- a/arch/mn10300/kernel/asm-offsets.c +++ b/arch/mn10300/kernel/asm-offsets.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/signal.h> | 8 | #include <linux/signal.h> |
9 | #include <linux/personality.h> | 9 | #include <linux/personality.h> |
10 | #include <linux/kbuild.h> | ||
10 | #include <asm/ucontext.h> | 11 | #include <asm/ucontext.h> |
11 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
12 | #include <asm/thread_info.h> | 13 | #include <asm/thread_info.h> |
@@ -14,14 +15,6 @@ | |||
14 | #include "sigframe.h" | 15 | #include "sigframe.h" |
15 | #include "mn10300-serial.h" | 16 | #include "mn10300-serial.h" |
16 | 17 | ||
17 | #define DEFINE(sym, val) \ | ||
18 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
19 | |||
20 | #define BLANK() asm volatile("\n->") | ||
21 | |||
22 | #define OFFSET(sym, str, mem) \ | ||
23 | DEFINE(sym, offsetof(struct str, mem)); | ||
24 | |||
25 | void foo(void) | 18 | void foo(void) |
26 | { | 19 | { |
27 | OFFSET(SIGCONTEXT_d0, sigcontext, d0); | 20 | OFFSET(SIGCONTEXT_d0, sigcontext, d0); |
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c index dbceae4307da..c1a8d8f941fd 100644 --- a/arch/mn10300/unit-asb2305/pci-iomap.c +++ b/arch/mn10300/unit-asb2305/pci-iomap.c | |||
@@ -16,8 +16,8 @@ | |||
16 | */ | 16 | */ |
17 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 17 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
18 | { | 18 | { |
19 | unsigned long start = pci_resource_start(dev, bar); | 19 | resource_size_t start = pci_resource_start(dev, bar); |
20 | unsigned long len = pci_resource_len(dev, bar); | 20 | resource_size_t len = pci_resource_len(dev, bar); |
21 | unsigned long flags = pci_resource_flags(dev, bar); | 21 | unsigned long flags = pci_resource_flags(dev, bar); |
22 | 22 | ||
23 | if (!len || !start) | 23 | if (!len || !start) |
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c index eaa79bc14d94..3efc0b73e4ff 100644 --- a/arch/parisc/kernel/asm-offsets.c +++ b/arch/parisc/kernel/asm-offsets.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/thread_info.h> | 32 | #include <linux/thread_info.h> |
33 | #include <linux/ptrace.h> | 33 | #include <linux/ptrace.h> |
34 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
35 | #include <linux/kbuild.h> | ||
35 | 36 | ||
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
37 | #include <asm/ptrace.h> | 38 | #include <asm/ptrace.h> |
@@ -39,11 +40,6 @@ | |||
39 | #include <asm/pdc.h> | 40 | #include <asm/pdc.h> |
40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
41 | 42 | ||
42 | #define DEFINE(sym, val) \ | ||
43 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
44 | |||
45 | #define BLANK() asm volatile("\n->" : : ) | ||
46 | |||
47 | #ifdef CONFIG_64BIT | 43 | #ifdef CONFIG_64BIT |
48 | #define FRAME_SIZE 128 | 44 | #define FRAME_SIZE 128 |
49 | #else | 45 | #else |
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 9448d4e91142..ccd61b9567a6 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c | |||
@@ -397,10 +397,9 @@ pcxl_dma_init(void) | |||
397 | "pcxl_dma_init: Unable to create gsc /proc dir entry\n"); | 397 | "pcxl_dma_init: Unable to create gsc /proc dir entry\n"); |
398 | else { | 398 | else { |
399 | struct proc_dir_entry* ent; | 399 | struct proc_dir_entry* ent; |
400 | ent = create_proc_entry("pcxl_dma", 0, proc_gsc_root); | 400 | ent = proc_create("pcxl_dma", 0, proc_gsc_root, |
401 | if (ent) | 401 | &proc_pcxl_dma_ops); |
402 | ent->proc_fops = &proc_pcxl_dma_ops; | 402 | if (!ent) |
403 | else | ||
404 | printk(KERN_WARNING | 403 | printk(KERN_WARNING |
405 | "pci-dma.c: Unable to create pcxl_dma /proc entry.\n"); | 404 | "pci-dma.c: Unable to create pcxl_dma /proc entry.\n"); |
406 | } | 405 | } |
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c index f4a811690ab3..9abed07db7fc 100644 --- a/arch/parisc/lib/iomap.c +++ b/arch/parisc/lib/iomap.c | |||
@@ -438,8 +438,8 @@ void ioport_unmap(void __iomem *addr) | |||
438 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ | 438 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ |
439 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 439 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
440 | { | 440 | { |
441 | unsigned long start = pci_resource_start(dev, bar); | 441 | resource_size_t start = pci_resource_start(dev, bar); |
442 | unsigned long len = pci_resource_len(dev, bar); | 442 | resource_size_t len = pci_resource_len(dev, bar); |
443 | unsigned long flags = pci_resource_flags(dev, bar); | 443 | unsigned long flags = pci_resource_flags(dev, bar); |
444 | 444 | ||
445 | if (!len || !start) | 445 | if (!len || !start) |
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index eb80f5e33d7d..1f012843150f 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c | |||
@@ -603,15 +603,18 @@ void show_mem(void) | |||
603 | #ifdef CONFIG_DISCONTIGMEM | 603 | #ifdef CONFIG_DISCONTIGMEM |
604 | { | 604 | { |
605 | struct zonelist *zl; | 605 | struct zonelist *zl; |
606 | int i, j, k; | 606 | int i, j; |
607 | 607 | ||
608 | for (i = 0; i < npmem_ranges; i++) { | 608 | for (i = 0; i < npmem_ranges; i++) { |
609 | zl = node_zonelist(i); | ||
609 | for (j = 0; j < MAX_NR_ZONES; j++) { | 610 | for (j = 0; j < MAX_NR_ZONES; j++) { |
610 | zl = NODE_DATA(i)->node_zonelists + j; | 611 | struct zoneref *z; |
612 | struct zone *zone; | ||
611 | 613 | ||
612 | printk("Zone list for zone %d on node %d: ", j, i); | 614 | printk("Zone list for zone %d on node %d: ", j, i); |
613 | for (k = 0; zl->zones[k] != NULL; k++) | 615 | for_each_zone_zonelist(zone, z, zl, j) |
614 | printk("[%d/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name); | 616 | printk("[%d/%s] ", zone_to_nid(zone), |
617 | zone->name); | ||
615 | printk("\n"); | 618 | printk("\n"); |
616 | } | 619 | } |
617 | } | 620 | } |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 20f45a8b87e3..3934e2659407 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -608,6 +608,19 @@ source "drivers/pcmcia/Kconfig" | |||
608 | 608 | ||
609 | source "drivers/pci/hotplug/Kconfig" | 609 | source "drivers/pci/hotplug/Kconfig" |
610 | 610 | ||
611 | config HAS_RAPIDIO | ||
612 | bool | ||
613 | default n | ||
614 | |||
615 | config RAPIDIO | ||
616 | bool "RapidIO support" | ||
617 | depends on HAS_RAPIDIO | ||
618 | help | ||
619 | If you say Y here, the kernel will include drivers and | ||
620 | infrastructure code to support RapidIO interconnect devices. | ||
621 | |||
622 | source "drivers/rapidio/Kconfig" | ||
623 | |||
611 | endmenu | 624 | endmenu |
612 | 625 | ||
613 | menu "Advanced setup" | 626 | menu "Advanced setup" |
@@ -803,3 +816,4 @@ config PPC_CLOCK | |||
803 | config PPC_LIB_RHEAP | 816 | config PPC_LIB_RHEAP |
804 | bool | 817 | bool |
805 | 818 | ||
819 | source "arch/powerpc/kvm/Kconfig" | ||
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index a86d8d853214..a7d24e692bab 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug | |||
@@ -118,7 +118,6 @@ config XMON_DISASSEMBLY | |||
118 | 118 | ||
119 | config IRQSTACKS | 119 | config IRQSTACKS |
120 | bool "Use separate kernel stacks when processing interrupts" | 120 | bool "Use separate kernel stacks when processing interrupts" |
121 | depends on PPC64 | ||
122 | help | 121 | help |
123 | If you say Y here the kernel will use separate kernel stacks | 122 | If you say Y here the kernel will use separate kernel stacks |
124 | for handling hard and soft interrupts. This can help avoid | 123 | for handling hard and soft interrupts. This can help avoid |
@@ -151,6 +150,9 @@ config BOOTX_TEXT | |||
151 | 150 | ||
152 | config PPC_EARLY_DEBUG | 151 | config PPC_EARLY_DEBUG |
153 | bool "Early debugging (dangerous)" | 152 | bool "Early debugging (dangerous)" |
153 | # PPC_EARLY_DEBUG on 440 leaves AS=1 mappings above the TLB high water | ||
154 | # mark, which doesn't work with current 440 KVM. | ||
155 | depends on !KVM | ||
154 | help | 156 | help |
155 | Say Y to enable some early debugging facilities that may be available | 157 | Say Y to enable some early debugging facilities that may be available |
156 | for your processor/board combination. Those facilities are hacks | 158 | for your processor/board combination. Those facilities are hacks |
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index e2ec4a91ccef..9dcdc036cdf7 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile | |||
@@ -145,6 +145,7 @@ core-y += arch/powerpc/kernel/ \ | |||
145 | arch/powerpc/platforms/ | 145 | arch/powerpc/platforms/ |
146 | core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ | 146 | core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ |
147 | core-$(CONFIG_XMON) += arch/powerpc/xmon/ | 147 | core-$(CONFIG_XMON) += arch/powerpc/xmon/ |
148 | core-$(CONFIG_KVM) += arch/powerpc/kvm/ | ||
148 | 149 | ||
149 | drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ | 150 | drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ |
150 | 151 | ||
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts index 16c947b8a721..1f2f1e0a5571 100644 --- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts +++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts | |||
@@ -45,6 +45,11 @@ | |||
45 | reg = <0x00000000 0x20000000>; // 512M at 0x0 | 45 | reg = <0x00000000 0x20000000>; // 512M at 0x0 |
46 | }; | 46 | }; |
47 | 47 | ||
48 | board-control@e8000000 { | ||
49 | compatible = "fsl,fpga-pixis"; | ||
50 | reg = <0xe8000000 32>; // pixis at 0xe8000000 | ||
51 | }; | ||
52 | |||
48 | soc@e0000000 { | 53 | soc@e0000000 { |
49 | #address-cells = <1>; | 54 | #address-cells = <1>; |
50 | #size-cells = <1>; | 55 | #size-cells = <1>; |
@@ -104,6 +109,13 @@ | |||
104 | interrupt-parent = <&mpic>; | 109 | interrupt-parent = <&mpic>; |
105 | }; | 110 | }; |
106 | 111 | ||
112 | display@2c000 { | ||
113 | compatible = "fsl,diu"; | ||
114 | reg = <0x2c000 100>; | ||
115 | interrupts = <72 2>; | ||
116 | interrupt-parent = <&mpic>; | ||
117 | }; | ||
118 | |||
107 | mpic: interrupt-controller@40000 { | 119 | mpic: interrupt-controller@40000 { |
108 | clock-frequency = <0>; | 120 | clock-frequency = <0>; |
109 | interrupt-controller; | 121 | interrupt-controller; |
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index 7f9b999843ce..1e4bfe9cadb9 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts | |||
@@ -26,6 +26,7 @@ | |||
26 | serial1 = &serial1; | 26 | serial1 = &serial1; |
27 | pci0 = &pci0; | 27 | pci0 = &pci0; |
28 | pci1 = &pci1; | 28 | pci1 = &pci1; |
29 | rapidio0 = &rapidio0; | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | cpus { | 32 | cpus { |
@@ -500,4 +501,15 @@ | |||
500 | 0x0 0x00100000>; | 501 | 0x0 0x00100000>; |
501 | }; | 502 | }; |
502 | }; | 503 | }; |
504 | rapidio0: rapidio@f80c0000 { | ||
505 | #address-cells = <2>; | ||
506 | #size-cells = <2>; | ||
507 | compatible = "fsl,rapidio-delta"; | ||
508 | reg = <0xf80c0000 0x20000>; | ||
509 | ranges = <0 0 0xc0000000 0 0x20000000>; | ||
510 | interrupt-parent = <&mpic>; | ||
511 | /* err_irq bell_outb_irq bell_inb_irq | ||
512 | msg1_tx_irq msg1_rx_irq msg2_tx_irq msg2_rx_irq */ | ||
513 | interrupts = <48 2 49 2 50 2 53 2 54 2 55 2 56 2>; | ||
514 | }; | ||
503 | }; | 515 | }; |
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index a20501f89474..88338a9f5e95 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig | |||
@@ -696,6 +696,7 @@ CONFIG_WINDFARM=y | |||
696 | CONFIG_WINDFARM_PM81=y | 696 | CONFIG_WINDFARM_PM81=y |
697 | CONFIG_WINDFARM_PM91=y | 697 | CONFIG_WINDFARM_PM91=y |
698 | CONFIG_WINDFARM_PM112=y | 698 | CONFIG_WINDFARM_PM112=y |
699 | CONFIG_WINDFARM_PM121=y | ||
699 | # CONFIG_PMAC_RACKMETER is not set | 700 | # CONFIG_PMAC_RACKMETER is not set |
700 | CONFIG_NETDEVICES=y | 701 | CONFIG_NETDEVICES=y |
701 | # CONFIG_NETDEVICES_MULTIQUEUE is not set | 702 | # CONFIG_NETDEVICES_MULTIQUEUE is not set |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 9177b21b1a95..d14cebf62bb0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -73,7 +73,6 @@ pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o | |||
73 | obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \ | 73 | obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \ |
74 | pci-common.o | 74 | pci-common.o |
75 | obj-$(CONFIG_PCI_MSI) += msi.o | 75 | obj-$(CONFIG_PCI_MSI) += msi.o |
76 | obj-$(CONFIG_RAPIDIO) += rio.o | ||
77 | obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ | 76 | obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ |
78 | machine_kexec_$(CONFIG_WORD_SIZE).o | 77 | machine_kexec_$(CONFIG_WORD_SIZE).o |
79 | obj-$(CONFIG_AUDIT) += audit.o | 78 | obj-$(CONFIG_AUDIT) += audit.o |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index adf1d09d726f..ec9228d687b0 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -23,10 +23,14 @@ | |||
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/suspend.h> | 24 | #include <linux/suspend.h> |
25 | #include <linux/hrtimer.h> | 25 | #include <linux/hrtimer.h> |
26 | #ifdef CONFIG_KVM | ||
27 | #include <linux/kvm_host.h> | ||
28 | #endif | ||
26 | #ifdef CONFIG_PPC64 | 29 | #ifdef CONFIG_PPC64 |
27 | #include <linux/time.h> | 30 | #include <linux/time.h> |
28 | #include <linux/hardirq.h> | 31 | #include <linux/hardirq.h> |
29 | #endif | 32 | #endif |
33 | #include <linux/kbuild.h> | ||
30 | 34 | ||
31 | #include <asm/io.h> | 35 | #include <asm/io.h> |
32 | #include <asm/page.h> | 36 | #include <asm/page.h> |
@@ -48,11 +52,6 @@ | |||
48 | #include <asm/iseries/alpaca.h> | 52 | #include <asm/iseries/alpaca.h> |
49 | #endif | 53 | #endif |
50 | 54 | ||
51 | #define DEFINE(sym, val) \ | ||
52 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
53 | |||
54 | #define BLANK() asm volatile("\n->" : : ) | ||
55 | |||
56 | int main(void) | 55 | int main(void) |
57 | { | 56 | { |
58 | DEFINE(THREAD, offsetof(struct task_struct, thread)); | 57 | DEFINE(THREAD, offsetof(struct task_struct, thread)); |
@@ -64,6 +63,7 @@ int main(void) | |||
64 | #endif /* CONFIG_PPC64 */ | 63 | #endif /* CONFIG_PPC64 */ |
65 | 64 | ||
66 | DEFINE(KSP, offsetof(struct thread_struct, ksp)); | 65 | DEFINE(KSP, offsetof(struct thread_struct, ksp)); |
66 | DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit)); | ||
67 | DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); | 67 | DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); |
68 | DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); | 68 | DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); |
69 | DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); | 69 | DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); |
@@ -324,5 +324,30 @@ int main(void) | |||
324 | 324 | ||
325 | DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); | 325 | DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); |
326 | 326 | ||
327 | #ifdef CONFIG_KVM | ||
328 | DEFINE(TLBE_BYTES, sizeof(struct tlbe)); | ||
329 | |||
330 | DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | ||
331 | DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | ||
332 | DEFINE(VCPU_HOST_TLB, offsetof(struct kvm_vcpu, arch.host_tlb)); | ||
333 | DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb)); | ||
334 | DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | ||
335 | DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); | ||
336 | DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); | ||
337 | DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer)); | ||
338 | DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr)); | ||
339 | DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc)); | ||
340 | DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr)); | ||
341 | DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4)); | ||
342 | DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5)); | ||
343 | DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6)); | ||
344 | DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); | ||
345 | DEFINE(VCPU_PID, offsetof(struct kvm_vcpu, arch.pid)); | ||
346 | |||
347 | DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); | ||
348 | DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); | ||
349 | DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); | ||
350 | #endif | ||
351 | |||
327 | return 0; | 352 | return 0; |
328 | } | 353 | } |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 84c868633068..0c8614d9875c 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -137,11 +137,12 @@ transfer_to_handler: | |||
137 | 2: /* if from kernel, check interrupted DOZE/NAP mode and | 137 | 2: /* if from kernel, check interrupted DOZE/NAP mode and |
138 | * check for stack overflow | 138 | * check for stack overflow |
139 | */ | 139 | */ |
140 | lwz r9,THREAD_INFO-THREAD(r12) | 140 | lwz r9,KSP_LIMIT(r12) |
141 | cmplw r1,r9 /* if r1 <= current->thread_info */ | 141 | cmplw r1,r9 /* if r1 <= ksp_limit */ |
142 | ble- stack_ovf /* then the kernel stack overflowed */ | 142 | ble- stack_ovf /* then the kernel stack overflowed */ |
143 | 5: | 143 | 5: |
144 | #ifdef CONFIG_6xx | 144 | #ifdef CONFIG_6xx |
145 | rlwinm r9,r1,0,0,31-THREAD_SHIFT | ||
145 | tophys(r9,r9) /* check local flags */ | 146 | tophys(r9,r9) /* check local flags */ |
146 | lwz r12,TI_LOCAL_FLAGS(r9) | 147 | lwz r12,TI_LOCAL_FLAGS(r9) |
147 | mtcrf 0x01,r12 | 148 | mtcrf 0x01,r12 |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 215973a2c8d5..024805e1747d 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -239,6 +239,10 @@ instruction_access_slb_pSeries: | |||
239 | .globl system_call_pSeries | 239 | .globl system_call_pSeries |
240 | system_call_pSeries: | 240 | system_call_pSeries: |
241 | HMT_MEDIUM | 241 | HMT_MEDIUM |
242 | BEGIN_FTR_SECTION | ||
243 | cmpdi r0,0x1ebe | ||
244 | beq- 1f | ||
245 | END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) | ||
242 | mr r9,r13 | 246 | mr r9,r13 |
243 | mfmsr r10 | 247 | mfmsr r10 |
244 | mfspr r13,SPRN_SPRG3 | 248 | mfspr r13,SPRN_SPRG3 |
@@ -253,6 +257,13 @@ system_call_pSeries: | |||
253 | rfid | 257 | rfid |
254 | b . /* prevent speculative execution */ | 258 | b . /* prevent speculative execution */ |
255 | 259 | ||
260 | /* Fast LE/BE switch system call */ | ||
261 | 1: mfspr r12,SPRN_SRR1 | ||
262 | xori r12,r12,MSR_LE | ||
263 | mtspr SPRN_SRR1,r12 | ||
264 | rfid /* return to userspace */ | ||
265 | b . | ||
266 | |||
256 | STD_EXCEPTION_PSERIES(0xd00, single_step) | 267 | STD_EXCEPTION_PSERIES(0xd00, single_step) |
257 | STD_EXCEPTION_PSERIES(0xe00, trap_0e) | 268 | STD_EXCEPTION_PSERIES(0xe00, trap_0e) |
258 | 269 | ||
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 425616f92d18..2f73f705d564 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -307,6 +307,7 @@ void do_IRQ(struct pt_regs *regs) | |||
307 | if (curtp != irqtp) { | 307 | if (curtp != irqtp) { |
308 | struct irq_desc *desc = irq_desc + irq; | 308 | struct irq_desc *desc = irq_desc + irq; |
309 | void *handler = desc->handle_irq; | 309 | void *handler = desc->handle_irq; |
310 | unsigned long saved_sp_limit = current->thread.ksp_limit; | ||
310 | if (handler == NULL) | 311 | if (handler == NULL) |
311 | handler = &__do_IRQ; | 312 | handler = &__do_IRQ; |
312 | irqtp->task = curtp->task; | 313 | irqtp->task = curtp->task; |
@@ -319,7 +320,10 @@ void do_IRQ(struct pt_regs *regs) | |||
319 | (irqtp->preempt_count & ~SOFTIRQ_MASK) | | 320 | (irqtp->preempt_count & ~SOFTIRQ_MASK) | |
320 | (curtp->preempt_count & SOFTIRQ_MASK); | 321 | (curtp->preempt_count & SOFTIRQ_MASK); |
321 | 322 | ||
323 | current->thread.ksp_limit = (unsigned long)irqtp + | ||
324 | _ALIGN_UP(sizeof(struct thread_info), 16); | ||
322 | call_handle_irq(irq, desc, irqtp, handler); | 325 | call_handle_irq(irq, desc, irqtp, handler); |
326 | current->thread.ksp_limit = saved_sp_limit; | ||
323 | irqtp->task = NULL; | 327 | irqtp->task = NULL; |
324 | 328 | ||
325 | 329 | ||
@@ -352,9 +356,7 @@ void __init init_IRQ(void) | |||
352 | { | 356 | { |
353 | if (ppc_md.init_IRQ) | 357 | if (ppc_md.init_IRQ) |
354 | ppc_md.init_IRQ(); | 358 | ppc_md.init_IRQ(); |
355 | #ifdef CONFIG_PPC64 | ||
356 | irq_ctx_init(); | 359 | irq_ctx_init(); |
357 | #endif | ||
358 | } | 360 | } |
359 | 361 | ||
360 | 362 | ||
@@ -383,11 +385,15 @@ void irq_ctx_init(void) | |||
383 | static inline void do_softirq_onstack(void) | 385 | static inline void do_softirq_onstack(void) |
384 | { | 386 | { |
385 | struct thread_info *curtp, *irqtp; | 387 | struct thread_info *curtp, *irqtp; |
388 | unsigned long saved_sp_limit = current->thread.ksp_limit; | ||
386 | 389 | ||
387 | curtp = current_thread_info(); | 390 | curtp = current_thread_info(); |
388 | irqtp = softirq_ctx[smp_processor_id()]; | 391 | irqtp = softirq_ctx[smp_processor_id()]; |
389 | irqtp->task = curtp->task; | 392 | irqtp->task = curtp->task; |
393 | current->thread.ksp_limit = (unsigned long)irqtp + | ||
394 | _ALIGN_UP(sizeof(struct thread_info), 16); | ||
390 | call_do_softirq(irqtp); | 395 | call_do_softirq(irqtp); |
396 | current->thread.ksp_limit = saved_sp_limit; | ||
391 | irqtp->task = NULL; | 397 | irqtp->task = NULL; |
392 | } | 398 | } |
393 | 399 | ||
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 1ffacc698ffb..1e656b43ad7f 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -591,10 +591,8 @@ int __init lparcfg_init(void) | |||
591 | !firmware_has_feature(FW_FEATURE_ISERIES)) | 591 | !firmware_has_feature(FW_FEATURE_ISERIES)) |
592 | mode |= S_IWUSR; | 592 | mode |= S_IWUSR; |
593 | 593 | ||
594 | ent = create_proc_entry("ppc64/lparcfg", mode, NULL); | 594 | ent = proc_create("ppc64/lparcfg", mode, NULL, &lparcfg_fops); |
595 | if (ent) { | 595 | if (!ent) { |
596 | ent->proc_fops = &lparcfg_fops; | ||
597 | } else { | ||
598 | printk(KERN_ERR "Failed to create ppc64/lparcfg\n"); | 596 | printk(KERN_ERR "Failed to create ppc64/lparcfg\n"); |
599 | return -EIO; | 597 | return -EIO; |
600 | } | 598 | } |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 92ccc6fcc5b0..89aaaa6f3561 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -32,6 +32,31 @@ | |||
32 | 32 | ||
33 | .text | 33 | .text |
34 | 34 | ||
35 | #ifdef CONFIG_IRQSTACKS | ||
36 | _GLOBAL(call_do_softirq) | ||
37 | mflr r0 | ||
38 | stw r0,4(r1) | ||
39 | stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3) | ||
40 | mr r1,r3 | ||
41 | bl __do_softirq | ||
42 | lwz r1,0(r1) | ||
43 | lwz r0,4(r1) | ||
44 | mtlr r0 | ||
45 | blr | ||
46 | |||
47 | _GLOBAL(call_handle_irq) | ||
48 | mflr r0 | ||
49 | stw r0,4(r1) | ||
50 | mtctr r6 | ||
51 | stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5) | ||
52 | mr r1,r5 | ||
53 | bctrl | ||
54 | lwz r1,0(r1) | ||
55 | lwz r0,4(r1) | ||
56 | mtlr r0 | ||
57 | blr | ||
58 | #endif /* CONFIG_IRQSTACKS */ | ||
59 | |||
35 | /* | 60 | /* |
36 | * This returns the high 64 bits of the product of two 64-bit numbers. | 61 | * This returns the high 64 bits of the product of two 64-bit numbers. |
37 | */ | 62 | */ |
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c index f78dfce1b771..c647ddef40dc 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c | |||
@@ -68,12 +68,11 @@ static int __init proc_ppc64_init(void) | |||
68 | { | 68 | { |
69 | struct proc_dir_entry *pde; | 69 | struct proc_dir_entry *pde; |
70 | 70 | ||
71 | pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL); | 71 | pde = proc_create_data("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL, |
72 | &page_map_fops, vdso_data); | ||
72 | if (!pde) | 73 | if (!pde) |
73 | return 1; | 74 | return 1; |
74 | pde->data = vdso_data; | ||
75 | pde->size = PAGE_SIZE; | 75 | pde->size = PAGE_SIZE; |
76 | pde->proc_fops = &page_map_fops; | ||
77 | 76 | ||
78 | return 0; | 77 | return 0; |
79 | } | 78 | } |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 6caad17ea72e..7de41c3948ec 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -589,6 +589,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | |||
589 | kregs = (struct pt_regs *) sp; | 589 | kregs = (struct pt_regs *) sp; |
590 | sp -= STACK_FRAME_OVERHEAD; | 590 | sp -= STACK_FRAME_OVERHEAD; |
591 | p->thread.ksp = sp; | 591 | p->thread.ksp = sp; |
592 | p->thread.ksp_limit = (unsigned long)task_stack_page(p) + | ||
593 | _ALIGN_UP(sizeof(struct thread_info), 16); | ||
592 | 594 | ||
593 | #ifdef CONFIG_PPC64 | 595 | #ifdef CONFIG_PPC64 |
594 | if (cpu_has_feature(CPU_FTR_SLB)) { | 596 | if (cpu_has_feature(CPU_FTR_SLB)) { |
diff --git a/arch/powerpc/kernel/rio.c b/arch/powerpc/kernel/rio.c deleted file mode 100644 index 29487fedfc76..000000000000 --- a/arch/powerpc/kernel/rio.c +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* | ||
2 | * RapidIO PPC32 support | ||
3 | * | ||
4 | * Copyright 2005 MontaVista Software, Inc. | ||
5 | * Matt Porter <mporter@kernel.crashing.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/rio.h> | ||
16 | |||
17 | #include <asm/rio.h> | ||
18 | |||
19 | /** | ||
20 | * platform_rio_init - Do platform specific RIO init | ||
21 | * | ||
22 | * Any platform specific initialization of RapdIO | ||
23 | * hardware is done here as well as registration | ||
24 | * of any active master ports in the system. | ||
25 | */ | ||
26 | void __attribute__ ((weak)) | ||
27 | platform_rio_init(void) | ||
28 | { | ||
29 | printk(KERN_WARNING "RIO: No platform_rio_init() present\n"); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * ppc_rio_init - Do PPC32 RIO init | ||
34 | * | ||
35 | * Calls platform-specific RIO init code and then calls | ||
36 | * rio_init_mports() to initialize any master ports that | ||
37 | * have been registered with the RIO subsystem. | ||
38 | */ | ||
39 | static int __init ppc_rio_init(void) | ||
40 | { | ||
41 | printk(KERN_INFO "RIO: RapidIO init\n"); | ||
42 | |||
43 | /* Platform specific initialization */ | ||
44 | platform_rio_init(); | ||
45 | |||
46 | /* Enumerate all registered ports */ | ||
47 | rio_init_mports(); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | subsys_initcall(ppc_rio_init); | ||
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index f2e3bc714d76..f9c6abc84a94 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c | |||
@@ -255,8 +255,6 @@ static void check_location(struct seq_file *m, const char *c); | |||
255 | 255 | ||
256 | static int __init proc_rtas_init(void) | 256 | static int __init proc_rtas_init(void) |
257 | { | 257 | { |
258 | struct proc_dir_entry *entry; | ||
259 | |||
260 | if (!machine_is(pseries)) | 258 | if (!machine_is(pseries)) |
261 | return -ENODEV; | 259 | return -ENODEV; |
262 | 260 | ||
@@ -264,35 +262,20 @@ static int __init proc_rtas_init(void) | |||
264 | if (rtas_node == NULL) | 262 | if (rtas_node == NULL) |
265 | return -ENODEV; | 263 | return -ENODEV; |
266 | 264 | ||
267 | entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL); | 265 | proc_create("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL, |
268 | if (entry) | 266 | &ppc_rtas_progress_operations); |
269 | entry->proc_fops = &ppc_rtas_progress_operations; | 267 | proc_create("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL, |
270 | 268 | &ppc_rtas_clock_operations); | |
271 | entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL); | 269 | proc_create("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL, |
272 | if (entry) | 270 | &ppc_rtas_poweron_operations); |
273 | entry->proc_fops = &ppc_rtas_clock_operations; | 271 | proc_create("ppc64/rtas/sensors", S_IRUGO, NULL, |
274 | 272 | &ppc_rtas_sensors_operations); | |
275 | entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL); | 273 | proc_create("ppc64/rtas/frequency", S_IWUSR|S_IRUGO, NULL, |
276 | if (entry) | 274 | &ppc_rtas_tone_freq_operations); |
277 | entry->proc_fops = &ppc_rtas_poweron_operations; | 275 | proc_create("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL, |
278 | 276 | &ppc_rtas_tone_volume_operations); | |
279 | entry = create_proc_entry("ppc64/rtas/sensors", S_IRUGO, NULL); | 277 | proc_create("ppc64/rtas/rmo_buffer", S_IRUSR, NULL, |
280 | if (entry) | 278 | &ppc_rtas_rmo_buf_ops); |
281 | entry->proc_fops = &ppc_rtas_sensors_operations; | ||
282 | |||
283 | entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO, | ||
284 | NULL); | ||
285 | if (entry) | ||
286 | entry->proc_fops = &ppc_rtas_tone_freq_operations; | ||
287 | |||
288 | entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL); | ||
289 | if (entry) | ||
290 | entry->proc_fops = &ppc_rtas_tone_volume_operations; | ||
291 | |||
292 | entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL); | ||
293 | if (entry) | ||
294 | entry->proc_fops = &ppc_rtas_rmo_buf_ops; | ||
295 | |||
296 | return 0; | 279 | return 0; |
297 | } | 280 | } |
298 | 281 | ||
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 627f126d1848..0a5e22b22729 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
@@ -704,18 +704,11 @@ static int initialize_flash_pde_data(const char *rtas_call_name, | |||
704 | static struct proc_dir_entry *create_flash_pde(const char *filename, | 704 | static struct proc_dir_entry *create_flash_pde(const char *filename, |
705 | const struct file_operations *fops) | 705 | const struct file_operations *fops) |
706 | { | 706 | { |
707 | struct proc_dir_entry *ent = NULL; | 707 | return proc_create(filename, S_IRUSR | S_IWUSR, NULL, fops); |
708 | |||
709 | ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL); | ||
710 | if (ent != NULL) { | ||
711 | ent->proc_fops = fops; | ||
712 | ent->owner = THIS_MODULE; | ||
713 | } | ||
714 | |||
715 | return ent; | ||
716 | } | 708 | } |
717 | 709 | ||
718 | static const struct file_operations rtas_flash_operations = { | 710 | static const struct file_operations rtas_flash_operations = { |
711 | .owner = THIS_MODULE, | ||
719 | .read = rtas_flash_read, | 712 | .read = rtas_flash_read, |
720 | .write = rtas_flash_write, | 713 | .write = rtas_flash_write, |
721 | .open = rtas_excl_open, | 714 | .open = rtas_excl_open, |
@@ -723,6 +716,7 @@ static const struct file_operations rtas_flash_operations = { | |||
723 | }; | 716 | }; |
724 | 717 | ||
725 | static const struct file_operations manage_flash_operations = { | 718 | static const struct file_operations manage_flash_operations = { |
719 | .owner = THIS_MODULE, | ||
726 | .read = manage_flash_read, | 720 | .read = manage_flash_read, |
727 | .write = manage_flash_write, | 721 | .write = manage_flash_write, |
728 | .open = rtas_excl_open, | 722 | .open = rtas_excl_open, |
@@ -730,6 +724,7 @@ static const struct file_operations manage_flash_operations = { | |||
730 | }; | 724 | }; |
731 | 725 | ||
732 | static const struct file_operations validate_flash_operations = { | 726 | static const struct file_operations validate_flash_operations = { |
727 | .owner = THIS_MODULE, | ||
733 | .read = validate_flash_read, | 728 | .read = validate_flash_read, |
734 | .write = validate_flash_write, | 729 | .write = validate_flash_write, |
735 | .open = rtas_excl_open, | 730 | .open = rtas_excl_open, |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 36f6779c88d4..5112a4aa801d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/root_dev.h> | 16 | #include <linux/root_dev.h> |
17 | #include <linux/cpu.h> | 17 | #include <linux/cpu.h> |
18 | #include <linux/console.h> | 18 | #include <linux/console.h> |
19 | #include <linux/lmb.h> | ||
19 | 20 | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
@@ -229,6 +230,24 @@ int __init ppc_init(void) | |||
229 | 230 | ||
230 | arch_initcall(ppc_init); | 231 | arch_initcall(ppc_init); |
231 | 232 | ||
233 | #ifdef CONFIG_IRQSTACKS | ||
234 | static void __init irqstack_early_init(void) | ||
235 | { | ||
236 | unsigned int i; | ||
237 | |||
238 | /* interrupt stacks must be in lowmem, we get that for free on ppc32 | ||
239 | * as the lmb is limited to lowmem by LMB_REAL_LIMIT */ | ||
240 | for_each_possible_cpu(i) { | ||
241 | softirq_ctx[i] = (struct thread_info *) | ||
242 | __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
243 | hardirq_ctx[i] = (struct thread_info *) | ||
244 | __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
245 | } | ||
246 | } | ||
247 | #else | ||
248 | #define irqstack_early_init() | ||
249 | #endif | ||
250 | |||
232 | /* Warning, IO base is not yet inited */ | 251 | /* Warning, IO base is not yet inited */ |
233 | void __init setup_arch(char **cmdline_p) | 252 | void __init setup_arch(char **cmdline_p) |
234 | { | 253 | { |
@@ -286,6 +305,8 @@ void __init setup_arch(char **cmdline_p) | |||
286 | init_mm.end_data = (unsigned long) _edata; | 305 | init_mm.end_data = (unsigned long) _edata; |
287 | init_mm.brk = klimit; | 306 | init_mm.brk = klimit; |
288 | 307 | ||
308 | irqstack_early_init(); | ||
309 | |||
289 | /* set up the bootmem stuff with available memory */ | 310 | /* set up the bootmem stuff with available memory */ |
290 | do_init_bootmem(); | 311 | do_init_bootmem(); |
291 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); | 312 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); |
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c new file mode 100644 index 000000000000..f5d7a5eab96e --- /dev/null +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kvm_host.h> | ||
23 | #include <linux/highmem.h> | ||
24 | #include <asm/mmu-44x.h> | ||
25 | #include <asm/kvm_ppc.h> | ||
26 | |||
27 | #include "44x_tlb.h" | ||
28 | |||
29 | #define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW) | ||
30 | #define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW) | ||
31 | |||
32 | static unsigned int kvmppc_tlb_44x_pos; | ||
33 | |||
34 | static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode) | ||
35 | { | ||
36 | /* Mask off reserved bits. */ | ||
37 | attrib &= PPC44x_TLB_PERM_MASK|PPC44x_TLB_ATTR_MASK; | ||
38 | |||
39 | if (!usermode) { | ||
40 | /* Guest is in supervisor mode, so we need to translate guest | ||
41 | * supervisor permissions into user permissions. */ | ||
42 | attrib &= ~PPC44x_TLB_USER_PERM_MASK; | ||
43 | attrib |= (attrib & PPC44x_TLB_SUPER_PERM_MASK) << 3; | ||
44 | } | ||
45 | |||
46 | /* Make sure host can always access this memory. */ | ||
47 | attrib |= PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW; | ||
48 | |||
49 | return attrib; | ||
50 | } | ||
51 | |||
52 | /* Search the guest TLB for a matching entry. */ | ||
53 | int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid, | ||
54 | unsigned int as) | ||
55 | { | ||
56 | int i; | ||
57 | |||
58 | /* XXX Replace loop with fancy data structures. */ | ||
59 | for (i = 0; i < PPC44x_TLB_SIZE; i++) { | ||
60 | struct tlbe *tlbe = &vcpu->arch.guest_tlb[i]; | ||
61 | unsigned int tid; | ||
62 | |||
63 | if (eaddr < get_tlb_eaddr(tlbe)) | ||
64 | continue; | ||
65 | |||
66 | if (eaddr > get_tlb_end(tlbe)) | ||
67 | continue; | ||
68 | |||
69 | tid = get_tlb_tid(tlbe); | ||
70 | if (tid && (tid != pid)) | ||
71 | continue; | ||
72 | |||
73 | if (!get_tlb_v(tlbe)) | ||
74 | continue; | ||
75 | |||
76 | if (get_tlb_ts(tlbe) != as) | ||
77 | continue; | ||
78 | |||
79 | return i; | ||
80 | } | ||
81 | |||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr) | ||
86 | { | ||
87 | unsigned int as = !!(vcpu->arch.msr & MSR_IS); | ||
88 | unsigned int index; | ||
89 | |||
90 | index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); | ||
91 | if (index == -1) | ||
92 | return NULL; | ||
93 | return &vcpu->arch.guest_tlb[index]; | ||
94 | } | ||
95 | |||
96 | struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr) | ||
97 | { | ||
98 | unsigned int as = !!(vcpu->arch.msr & MSR_DS); | ||
99 | unsigned int index; | ||
100 | |||
101 | index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as); | ||
102 | if (index == -1) | ||
103 | return NULL; | ||
104 | return &vcpu->arch.guest_tlb[index]; | ||
105 | } | ||
106 | |||
107 | static int kvmppc_44x_tlbe_is_writable(struct tlbe *tlbe) | ||
108 | { | ||
109 | return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW); | ||
110 | } | ||
111 | |||
112 | /* Must be called with mmap_sem locked for writing. */ | ||
113 | static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu, | ||
114 | unsigned int index) | ||
115 | { | ||
116 | struct tlbe *stlbe = &vcpu->arch.shadow_tlb[index]; | ||
117 | struct page *page = vcpu->arch.shadow_pages[index]; | ||
118 | |||
119 | kunmap(vcpu->arch.shadow_pages[index]); | ||
120 | |||
121 | if (get_tlb_v(stlbe)) { | ||
122 | if (kvmppc_44x_tlbe_is_writable(stlbe)) | ||
123 | kvm_release_page_dirty(page); | ||
124 | else | ||
125 | kvm_release_page_clean(page); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* Caller must ensure that the specified guest TLB entry is safe to insert into | ||
130 | * the shadow TLB. */ | ||
131 | void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, | ||
132 | u32 flags) | ||
133 | { | ||
134 | struct page *new_page; | ||
135 | struct tlbe *stlbe; | ||
136 | hpa_t hpaddr; | ||
137 | unsigned int victim; | ||
138 | |||
139 | /* Future optimization: don't overwrite the TLB entry containing the | ||
140 | * current PC (or stack?). */ | ||
141 | victim = kvmppc_tlb_44x_pos++; | ||
142 | if (kvmppc_tlb_44x_pos > tlb_44x_hwater) | ||
143 | kvmppc_tlb_44x_pos = 0; | ||
144 | stlbe = &vcpu->arch.shadow_tlb[victim]; | ||
145 | |||
146 | /* Get reference to new page. */ | ||
147 | down_write(¤t->mm->mmap_sem); | ||
148 | new_page = gfn_to_page(vcpu->kvm, gfn); | ||
149 | if (is_error_page(new_page)) { | ||
150 | printk(KERN_ERR "Couldn't get guest page!\n"); | ||
151 | kvm_release_page_clean(new_page); | ||
152 | return; | ||
153 | } | ||
154 | hpaddr = page_to_phys(new_page); | ||
155 | |||
156 | /* Drop reference to old page. */ | ||
157 | kvmppc_44x_shadow_release(vcpu, victim); | ||
158 | up_write(¤t->mm->mmap_sem); | ||
159 | |||
160 | vcpu->arch.shadow_pages[victim] = new_page; | ||
161 | |||
162 | /* XXX Make sure (va, size) doesn't overlap any other | ||
163 | * entries. 440x6 user manual says the result would be | ||
164 | * "undefined." */ | ||
165 | |||
166 | /* XXX what about AS? */ | ||
167 | |||
168 | stlbe->tid = asid & 0xff; | ||
169 | |||
170 | /* Force TS=1 for all guest mappings. */ | ||
171 | /* For now we hardcode 4KB mappings, but it will be important to | ||
172 | * use host large pages in the future. */ | ||
173 | stlbe->word0 = (gvaddr & PAGE_MASK) | PPC44x_TLB_VALID | PPC44x_TLB_TS | ||
174 | | PPC44x_TLB_4K; | ||
175 | |||
176 | stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf); | ||
177 | stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags, | ||
178 | vcpu->arch.msr & MSR_PR); | ||
179 | } | ||
180 | |||
181 | void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid) | ||
182 | { | ||
183 | unsigned int pid = asid & 0xff; | ||
184 | int i; | ||
185 | |||
186 | /* XXX Replace loop with fancy data structures. */ | ||
187 | down_write(¤t->mm->mmap_sem); | ||
188 | for (i = 0; i <= tlb_44x_hwater; i++) { | ||
189 | struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i]; | ||
190 | unsigned int tid; | ||
191 | |||
192 | if (!get_tlb_v(stlbe)) | ||
193 | continue; | ||
194 | |||
195 | if (eaddr < get_tlb_eaddr(stlbe)) | ||
196 | continue; | ||
197 | |||
198 | if (eaddr > get_tlb_end(stlbe)) | ||
199 | continue; | ||
200 | |||
201 | tid = get_tlb_tid(stlbe); | ||
202 | if (tid && (tid != pid)) | ||
203 | continue; | ||
204 | |||
205 | kvmppc_44x_shadow_release(vcpu, i); | ||
206 | stlbe->word0 = 0; | ||
207 | } | ||
208 | up_write(¤t->mm->mmap_sem); | ||
209 | } | ||
210 | |||
211 | /* Invalidate all mappings, so that when they fault back in they will get the | ||
212 | * proper permission bits. */ | ||
213 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | ||
214 | { | ||
215 | int i; | ||
216 | |||
217 | /* XXX Replace loop with fancy data structures. */ | ||
218 | down_write(¤t->mm->mmap_sem); | ||
219 | for (i = 0; i <= tlb_44x_hwater; i++) { | ||
220 | kvmppc_44x_shadow_release(vcpu, i); | ||
221 | vcpu->arch.shadow_tlb[i].word0 = 0; | ||
222 | } | ||
223 | up_write(¤t->mm->mmap_sem); | ||
224 | } | ||
diff --git a/arch/powerpc/kvm/44x_tlb.h b/arch/powerpc/kvm/44x_tlb.h new file mode 100644 index 000000000000..2ccd46b6f6b7 --- /dev/null +++ b/arch/powerpc/kvm/44x_tlb.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #ifndef __KVM_POWERPC_TLB_H__ | ||
21 | #define __KVM_POWERPC_TLB_H__ | ||
22 | |||
23 | #include <linux/kvm_host.h> | ||
24 | #include <asm/mmu-44x.h> | ||
25 | |||
26 | extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
27 | unsigned int pid, unsigned int as); | ||
28 | extern struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr); | ||
29 | extern struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr); | ||
30 | |||
31 | /* TLB helper functions */ | ||
32 | static inline unsigned int get_tlb_size(const struct tlbe *tlbe) | ||
33 | { | ||
34 | return (tlbe->word0 >> 4) & 0xf; | ||
35 | } | ||
36 | |||
37 | static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe) | ||
38 | { | ||
39 | return tlbe->word0 & 0xfffffc00; | ||
40 | } | ||
41 | |||
42 | static inline gva_t get_tlb_bytes(const struct tlbe *tlbe) | ||
43 | { | ||
44 | unsigned int pgsize = get_tlb_size(tlbe); | ||
45 | return 1 << 10 << (pgsize << 1); | ||
46 | } | ||
47 | |||
48 | static inline gva_t get_tlb_end(const struct tlbe *tlbe) | ||
49 | { | ||
50 | return get_tlb_eaddr(tlbe) + get_tlb_bytes(tlbe) - 1; | ||
51 | } | ||
52 | |||
53 | static inline u64 get_tlb_raddr(const struct tlbe *tlbe) | ||
54 | { | ||
55 | u64 word1 = tlbe->word1; | ||
56 | return ((word1 & 0xf) << 32) | (word1 & 0xfffffc00); | ||
57 | } | ||
58 | |||
59 | static inline unsigned int get_tlb_tid(const struct tlbe *tlbe) | ||
60 | { | ||
61 | return tlbe->tid & 0xff; | ||
62 | } | ||
63 | |||
64 | static inline unsigned int get_tlb_ts(const struct tlbe *tlbe) | ||
65 | { | ||
66 | return (tlbe->word0 >> 8) & 0x1; | ||
67 | } | ||
68 | |||
69 | static inline unsigned int get_tlb_v(const struct tlbe *tlbe) | ||
70 | { | ||
71 | return (tlbe->word0 >> 9) & 0x1; | ||
72 | } | ||
73 | |||
74 | static inline unsigned int get_mmucr_stid(const struct kvm_vcpu *vcpu) | ||
75 | { | ||
76 | return vcpu->arch.mmucr & 0xff; | ||
77 | } | ||
78 | |||
79 | static inline unsigned int get_mmucr_sts(const struct kvm_vcpu *vcpu) | ||
80 | { | ||
81 | return (vcpu->arch.mmucr >> 16) & 0x1; | ||
82 | } | ||
83 | |||
84 | static inline gpa_t tlb_xlate(struct tlbe *tlbe, gva_t eaddr) | ||
85 | { | ||
86 | unsigned int pgmask = get_tlb_bytes(tlbe) - 1; | ||
87 | |||
88 | return get_tlb_raddr(tlbe) | (eaddr & pgmask); | ||
89 | } | ||
90 | |||
91 | #endif /* __KVM_POWERPC_TLB_H__ */ | ||
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig new file mode 100644 index 000000000000..6b076010213b --- /dev/null +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -0,0 +1,42 @@ | |||
1 | # | ||
2 | # KVM configuration | ||
3 | # | ||
4 | |||
5 | menuconfig VIRTUALIZATION | ||
6 | bool "Virtualization" | ||
7 | ---help--- | ||
8 | Say Y here to get to see options for using your Linux host to run | ||
9 | other operating systems inside virtual machines (guests). | ||
10 | This option alone does not add any kernel code. | ||
11 | |||
12 | If you say N, all options in this submenu will be skipped and | ||
13 | disabled. | ||
14 | |||
15 | if VIRTUALIZATION | ||
16 | |||
17 | config KVM | ||
18 | bool "Kernel-based Virtual Machine (KVM) support" | ||
19 | depends on 44x && EXPERIMENTAL | ||
20 | select PREEMPT_NOTIFIERS | ||
21 | select ANON_INODES | ||
22 | # We can only run on Book E hosts so far | ||
23 | select KVM_BOOKE_HOST | ||
24 | ---help--- | ||
25 | Support hosting virtualized guest machines. You will also | ||
26 | need to select one or more of the processor modules below. | ||
27 | |||
28 | This module provides access to the hardware capabilities through | ||
29 | a character device node named /dev/kvm. | ||
30 | |||
31 | If unsure, say N. | ||
32 | |||
33 | config KVM_BOOKE_HOST | ||
34 | bool "KVM host support for Book E PowerPC processors" | ||
35 | depends on KVM && 44x | ||
36 | ---help--- | ||
37 | Provides host support for KVM on Book E PowerPC processors. Currently | ||
38 | this works on 440 processors only. | ||
39 | |||
40 | source drivers/virtio/Kconfig | ||
41 | |||
42 | endif # VIRTUALIZATION | ||
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile new file mode 100644 index 000000000000..d0d358d367ec --- /dev/null +++ b/arch/powerpc/kvm/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | # | ||
2 | # Makefile for Kernel-based Virtual Machine module | ||
3 | # | ||
4 | |||
5 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm | ||
6 | |||
7 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) | ||
8 | |||
9 | kvm-objs := $(common-objs) powerpc.o emulate.o booke_guest.o | ||
10 | obj-$(CONFIG_KVM) += kvm.o | ||
11 | |||
12 | AFLAGS_booke_interrupts.o := -I$(obj) | ||
13 | |||
14 | kvm-booke-host-objs := booke_host.o booke_interrupts.o 44x_tlb.o | ||
15 | obj-$(CONFIG_KVM_BOOKE_HOST) += kvm-booke-host.o | ||
diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c new file mode 100644 index 000000000000..6d9884a6884a --- /dev/null +++ b/arch/powerpc/kvm/booke_guest.c | |||
@@ -0,0 +1,615 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | ||
19 | */ | ||
20 | |||
21 | #include <linux/errno.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <asm/cputable.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/kvm_ppc.h> | ||
30 | |||
31 | #include "44x_tlb.h" | ||
32 | |||
33 | #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM | ||
34 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | ||
35 | |||
36 | struct kvm_stats_debugfs_item debugfs_entries[] = { | ||
37 | { "exits", VCPU_STAT(sum_exits) }, | ||
38 | { "mmio", VCPU_STAT(mmio_exits) }, | ||
39 | { "dcr", VCPU_STAT(dcr_exits) }, | ||
40 | { "sig", VCPU_STAT(signal_exits) }, | ||
41 | { "light", VCPU_STAT(light_exits) }, | ||
42 | { "itlb_r", VCPU_STAT(itlb_real_miss_exits) }, | ||
43 | { "itlb_v", VCPU_STAT(itlb_virt_miss_exits) }, | ||
44 | { "dtlb_r", VCPU_STAT(dtlb_real_miss_exits) }, | ||
45 | { "dtlb_v", VCPU_STAT(dtlb_virt_miss_exits) }, | ||
46 | { "sysc", VCPU_STAT(syscall_exits) }, | ||
47 | { "isi", VCPU_STAT(isi_exits) }, | ||
48 | { "dsi", VCPU_STAT(dsi_exits) }, | ||
49 | { "inst_emu", VCPU_STAT(emulated_inst_exits) }, | ||
50 | { "dec", VCPU_STAT(dec_exits) }, | ||
51 | { "ext_intr", VCPU_STAT(ext_intr_exits) }, | ||
52 | { NULL } | ||
53 | }; | ||
54 | |||
55 | static const u32 interrupt_msr_mask[16] = { | ||
56 | [BOOKE_INTERRUPT_CRITICAL] = MSR_ME, | ||
57 | [BOOKE_INTERRUPT_MACHINE_CHECK] = 0, | ||
58 | [BOOKE_INTERRUPT_DATA_STORAGE] = MSR_CE|MSR_ME|MSR_DE, | ||
59 | [BOOKE_INTERRUPT_INST_STORAGE] = MSR_CE|MSR_ME|MSR_DE, | ||
60 | [BOOKE_INTERRUPT_EXTERNAL] = MSR_CE|MSR_ME|MSR_DE, | ||
61 | [BOOKE_INTERRUPT_ALIGNMENT] = MSR_CE|MSR_ME|MSR_DE, | ||
62 | [BOOKE_INTERRUPT_PROGRAM] = MSR_CE|MSR_ME|MSR_DE, | ||
63 | [BOOKE_INTERRUPT_FP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE, | ||
64 | [BOOKE_INTERRUPT_SYSCALL] = MSR_CE|MSR_ME|MSR_DE, | ||
65 | [BOOKE_INTERRUPT_AP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE, | ||
66 | [BOOKE_INTERRUPT_DECREMENTER] = MSR_CE|MSR_ME|MSR_DE, | ||
67 | [BOOKE_INTERRUPT_FIT] = MSR_CE|MSR_ME|MSR_DE, | ||
68 | [BOOKE_INTERRUPT_WATCHDOG] = MSR_ME, | ||
69 | [BOOKE_INTERRUPT_DTLB_MISS] = MSR_CE|MSR_ME|MSR_DE, | ||
70 | [BOOKE_INTERRUPT_ITLB_MISS] = MSR_CE|MSR_ME|MSR_DE, | ||
71 | [BOOKE_INTERRUPT_DEBUG] = MSR_ME, | ||
72 | }; | ||
73 | |||
74 | const unsigned char exception_priority[] = { | ||
75 | [BOOKE_INTERRUPT_DATA_STORAGE] = 0, | ||
76 | [BOOKE_INTERRUPT_INST_STORAGE] = 1, | ||
77 | [BOOKE_INTERRUPT_ALIGNMENT] = 2, | ||
78 | [BOOKE_INTERRUPT_PROGRAM] = 3, | ||
79 | [BOOKE_INTERRUPT_FP_UNAVAIL] = 4, | ||
80 | [BOOKE_INTERRUPT_SYSCALL] = 5, | ||
81 | [BOOKE_INTERRUPT_AP_UNAVAIL] = 6, | ||
82 | [BOOKE_INTERRUPT_DTLB_MISS] = 7, | ||
83 | [BOOKE_INTERRUPT_ITLB_MISS] = 8, | ||
84 | [BOOKE_INTERRUPT_MACHINE_CHECK] = 9, | ||
85 | [BOOKE_INTERRUPT_DEBUG] = 10, | ||
86 | [BOOKE_INTERRUPT_CRITICAL] = 11, | ||
87 | [BOOKE_INTERRUPT_WATCHDOG] = 12, | ||
88 | [BOOKE_INTERRUPT_EXTERNAL] = 13, | ||
89 | [BOOKE_INTERRUPT_FIT] = 14, | ||
90 | [BOOKE_INTERRUPT_DECREMENTER] = 15, | ||
91 | }; | ||
92 | |||
93 | const unsigned char priority_exception[] = { | ||
94 | BOOKE_INTERRUPT_DATA_STORAGE, | ||
95 | BOOKE_INTERRUPT_INST_STORAGE, | ||
96 | BOOKE_INTERRUPT_ALIGNMENT, | ||
97 | BOOKE_INTERRUPT_PROGRAM, | ||
98 | BOOKE_INTERRUPT_FP_UNAVAIL, | ||
99 | BOOKE_INTERRUPT_SYSCALL, | ||
100 | BOOKE_INTERRUPT_AP_UNAVAIL, | ||
101 | BOOKE_INTERRUPT_DTLB_MISS, | ||
102 | BOOKE_INTERRUPT_ITLB_MISS, | ||
103 | BOOKE_INTERRUPT_MACHINE_CHECK, | ||
104 | BOOKE_INTERRUPT_DEBUG, | ||
105 | BOOKE_INTERRUPT_CRITICAL, | ||
106 | BOOKE_INTERRUPT_WATCHDOG, | ||
107 | BOOKE_INTERRUPT_EXTERNAL, | ||
108 | BOOKE_INTERRUPT_FIT, | ||
109 | BOOKE_INTERRUPT_DECREMENTER, | ||
110 | }; | ||
111 | |||
112 | |||
113 | void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | ||
114 | { | ||
115 | struct tlbe *tlbe; | ||
116 | int i; | ||
117 | |||
118 | printk("vcpu %d TLB dump:\n", vcpu->vcpu_id); | ||
119 | printk("| %2s | %3s | %8s | %8s | %8s |\n", | ||
120 | "nr", "tid", "word0", "word1", "word2"); | ||
121 | |||
122 | for (i = 0; i < PPC44x_TLB_SIZE; i++) { | ||
123 | tlbe = &vcpu->arch.guest_tlb[i]; | ||
124 | if (tlbe->word0 & PPC44x_TLB_VALID) | ||
125 | printk(" G%2d | %02X | %08X | %08X | %08X |\n", | ||
126 | i, tlbe->tid, tlbe->word0, tlbe->word1, | ||
127 | tlbe->word2); | ||
128 | } | ||
129 | |||
130 | for (i = 0; i < PPC44x_TLB_SIZE; i++) { | ||
131 | tlbe = &vcpu->arch.shadow_tlb[i]; | ||
132 | if (tlbe->word0 & PPC44x_TLB_VALID) | ||
133 | printk(" S%2d | %02X | %08X | %08X | %08X |\n", | ||
134 | i, tlbe->tid, tlbe->word0, tlbe->word1, | ||
135 | tlbe->word2); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* TODO: use vcpu_printf() */ | ||
140 | void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | printk("pc: %08x msr: %08x\n", vcpu->arch.pc, vcpu->arch.msr); | ||
145 | printk("lr: %08x ctr: %08x\n", vcpu->arch.lr, vcpu->arch.ctr); | ||
146 | printk("srr0: %08x srr1: %08x\n", vcpu->arch.srr0, vcpu->arch.srr1); | ||
147 | |||
148 | printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions); | ||
149 | |||
150 | for (i = 0; i < 32; i += 4) { | ||
151 | printk("gpr%02d: %08x %08x %08x %08x\n", i, | ||
152 | vcpu->arch.gpr[i], | ||
153 | vcpu->arch.gpr[i+1], | ||
154 | vcpu->arch.gpr[i+2], | ||
155 | vcpu->arch.gpr[i+3]); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* Check if we are ready to deliver the interrupt */ | ||
160 | static int kvmppc_can_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) | ||
161 | { | ||
162 | int r; | ||
163 | |||
164 | switch (interrupt) { | ||
165 | case BOOKE_INTERRUPT_CRITICAL: | ||
166 | r = vcpu->arch.msr & MSR_CE; | ||
167 | break; | ||
168 | case BOOKE_INTERRUPT_MACHINE_CHECK: | ||
169 | r = vcpu->arch.msr & MSR_ME; | ||
170 | break; | ||
171 | case BOOKE_INTERRUPT_EXTERNAL: | ||
172 | r = vcpu->arch.msr & MSR_EE; | ||
173 | break; | ||
174 | case BOOKE_INTERRUPT_DECREMENTER: | ||
175 | r = vcpu->arch.msr & MSR_EE; | ||
176 | break; | ||
177 | case BOOKE_INTERRUPT_FIT: | ||
178 | r = vcpu->arch.msr & MSR_EE; | ||
179 | break; | ||
180 | case BOOKE_INTERRUPT_WATCHDOG: | ||
181 | r = vcpu->arch.msr & MSR_CE; | ||
182 | break; | ||
183 | case BOOKE_INTERRUPT_DEBUG: | ||
184 | r = vcpu->arch.msr & MSR_DE; | ||
185 | break; | ||
186 | default: | ||
187 | r = 1; | ||
188 | } | ||
189 | |||
190 | return r; | ||
191 | } | ||
192 | |||
193 | static void kvmppc_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) | ||
194 | { | ||
195 | switch (interrupt) { | ||
196 | case BOOKE_INTERRUPT_DECREMENTER: | ||
197 | vcpu->arch.tsr |= TSR_DIS; | ||
198 | break; | ||
199 | } | ||
200 | |||
201 | vcpu->arch.srr0 = vcpu->arch.pc; | ||
202 | vcpu->arch.srr1 = vcpu->arch.msr; | ||
203 | vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[interrupt]; | ||
204 | kvmppc_set_msr(vcpu, vcpu->arch.msr & interrupt_msr_mask[interrupt]); | ||
205 | } | ||
206 | |||
207 | /* Check pending exceptions and deliver one, if possible. */ | ||
208 | void kvmppc_check_and_deliver_interrupts(struct kvm_vcpu *vcpu) | ||
209 | { | ||
210 | unsigned long *pending = &vcpu->arch.pending_exceptions; | ||
211 | unsigned int exception; | ||
212 | unsigned int priority; | ||
213 | |||
214 | priority = find_first_bit(pending, BITS_PER_BYTE * sizeof(*pending)); | ||
215 | while (priority <= BOOKE_MAX_INTERRUPT) { | ||
216 | exception = priority_exception[priority]; | ||
217 | if (kvmppc_can_deliver_interrupt(vcpu, exception)) { | ||
218 | kvmppc_clear_exception(vcpu, exception); | ||
219 | kvmppc_deliver_interrupt(vcpu, exception); | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | priority = find_next_bit(pending, | ||
224 | BITS_PER_BYTE * sizeof(*pending), | ||
225 | priority + 1); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||
230 | { | ||
231 | enum emulation_result er; | ||
232 | int r; | ||
233 | |||
234 | er = kvmppc_emulate_instruction(run, vcpu); | ||
235 | switch (er) { | ||
236 | case EMULATE_DONE: | ||
237 | /* Future optimization: only reload non-volatiles if they were | ||
238 | * actually modified. */ | ||
239 | r = RESUME_GUEST_NV; | ||
240 | break; | ||
241 | case EMULATE_DO_MMIO: | ||
242 | run->exit_reason = KVM_EXIT_MMIO; | ||
243 | /* We must reload nonvolatiles because "update" load/store | ||
244 | * instructions modify register state. */ | ||
245 | /* Future optimization: only reload non-volatiles if they were | ||
246 | * actually modified. */ | ||
247 | r = RESUME_HOST_NV; | ||
248 | break; | ||
249 | case EMULATE_FAIL: | ||
250 | /* XXX Deliver Program interrupt to guest. */ | ||
251 | printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__, | ||
252 | vcpu->arch.last_inst); | ||
253 | r = RESUME_HOST; | ||
254 | break; | ||
255 | default: | ||
256 | BUG(); | ||
257 | } | ||
258 | |||
259 | return r; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * kvmppc_handle_exit | ||
264 | * | ||
265 | * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV) | ||
266 | */ | ||
267 | int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
268 | unsigned int exit_nr) | ||
269 | { | ||
270 | enum emulation_result er; | ||
271 | int r = RESUME_HOST; | ||
272 | |||
273 | local_irq_enable(); | ||
274 | |||
275 | run->exit_reason = KVM_EXIT_UNKNOWN; | ||
276 | run->ready_for_interrupt_injection = 1; | ||
277 | |||
278 | switch (exit_nr) { | ||
279 | case BOOKE_INTERRUPT_MACHINE_CHECK: | ||
280 | printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR)); | ||
281 | kvmppc_dump_vcpu(vcpu); | ||
282 | r = RESUME_HOST; | ||
283 | break; | ||
284 | |||
285 | case BOOKE_INTERRUPT_EXTERNAL: | ||
286 | case BOOKE_INTERRUPT_DECREMENTER: | ||
287 | /* Since we switched IVPR back to the host's value, the host | ||
288 | * handled this interrupt the moment we enabled interrupts. | ||
289 | * Now we just offer it a chance to reschedule the guest. */ | ||
290 | |||
291 | /* XXX At this point the TLB still holds our shadow TLB, so if | ||
292 | * we do reschedule the host will fault over it. Perhaps we | ||
293 | * should politely restore the host's entries to minimize | ||
294 | * misses before ceding control. */ | ||
295 | if (need_resched()) | ||
296 | cond_resched(); | ||
297 | if (exit_nr == BOOKE_INTERRUPT_DECREMENTER) | ||
298 | vcpu->stat.dec_exits++; | ||
299 | else | ||
300 | vcpu->stat.ext_intr_exits++; | ||
301 | r = RESUME_GUEST; | ||
302 | break; | ||
303 | |||
304 | case BOOKE_INTERRUPT_PROGRAM: | ||
305 | if (vcpu->arch.msr & MSR_PR) { | ||
306 | /* Program traps generated by user-level software must be handled | ||
307 | * by the guest kernel. */ | ||
308 | vcpu->arch.esr = vcpu->arch.fault_esr; | ||
309 | kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); | ||
310 | r = RESUME_GUEST; | ||
311 | break; | ||
312 | } | ||
313 | |||
314 | er = kvmppc_emulate_instruction(run, vcpu); | ||
315 | switch (er) { | ||
316 | case EMULATE_DONE: | ||
317 | /* Future optimization: only reload non-volatiles if | ||
318 | * they were actually modified by emulation. */ | ||
319 | vcpu->stat.emulated_inst_exits++; | ||
320 | r = RESUME_GUEST_NV; | ||
321 | break; | ||
322 | case EMULATE_DO_DCR: | ||
323 | run->exit_reason = KVM_EXIT_DCR; | ||
324 | r = RESUME_HOST; | ||
325 | break; | ||
326 | case EMULATE_FAIL: | ||
327 | /* XXX Deliver Program interrupt to guest. */ | ||
328 | printk(KERN_CRIT "%s: emulation at %x failed (%08x)\n", | ||
329 | __func__, vcpu->arch.pc, vcpu->arch.last_inst); | ||
330 | /* For debugging, encode the failing instruction and | ||
331 | * report it to userspace. */ | ||
332 | run->hw.hardware_exit_reason = ~0ULL << 32; | ||
333 | run->hw.hardware_exit_reason |= vcpu->arch.last_inst; | ||
334 | r = RESUME_HOST; | ||
335 | break; | ||
336 | default: | ||
337 | BUG(); | ||
338 | } | ||
339 | break; | ||
340 | |||
341 | case BOOKE_INTERRUPT_DATA_STORAGE: | ||
342 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
343 | vcpu->arch.esr = vcpu->arch.fault_esr; | ||
344 | kvmppc_queue_exception(vcpu, exit_nr); | ||
345 | vcpu->stat.dsi_exits++; | ||
346 | r = RESUME_GUEST; | ||
347 | break; | ||
348 | |||
349 | case BOOKE_INTERRUPT_INST_STORAGE: | ||
350 | vcpu->arch.esr = vcpu->arch.fault_esr; | ||
351 | kvmppc_queue_exception(vcpu, exit_nr); | ||
352 | vcpu->stat.isi_exits++; | ||
353 | r = RESUME_GUEST; | ||
354 | break; | ||
355 | |||
356 | case BOOKE_INTERRUPT_SYSCALL: | ||
357 | kvmppc_queue_exception(vcpu, exit_nr); | ||
358 | vcpu->stat.syscall_exits++; | ||
359 | r = RESUME_GUEST; | ||
360 | break; | ||
361 | |||
362 | case BOOKE_INTERRUPT_DTLB_MISS: { | ||
363 | struct tlbe *gtlbe; | ||
364 | unsigned long eaddr = vcpu->arch.fault_dear; | ||
365 | gfn_t gfn; | ||
366 | |||
367 | /* Check the guest TLB. */ | ||
368 | gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr); | ||
369 | if (!gtlbe) { | ||
370 | /* The guest didn't have a mapping for it. */ | ||
371 | kvmppc_queue_exception(vcpu, exit_nr); | ||
372 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
373 | vcpu->arch.esr = vcpu->arch.fault_esr; | ||
374 | vcpu->stat.dtlb_real_miss_exits++; | ||
375 | r = RESUME_GUEST; | ||
376 | break; | ||
377 | } | ||
378 | |||
379 | vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr); | ||
380 | gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT; | ||
381 | |||
382 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { | ||
383 | /* The guest TLB had a mapping, but the shadow TLB | ||
384 | * didn't, and it is RAM. This could be because: | ||
385 | * a) the entry is mapping the host kernel, or | ||
386 | * b) the guest used a large mapping which we're faking | ||
387 | * Either way, we need to satisfy the fault without | ||
388 | * invoking the guest. */ | ||
389 | kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid, | ||
390 | gtlbe->word2); | ||
391 | vcpu->stat.dtlb_virt_miss_exits++; | ||
392 | r = RESUME_GUEST; | ||
393 | } else { | ||
394 | /* Guest has mapped and accessed a page which is not | ||
395 | * actually RAM. */ | ||
396 | r = kvmppc_emulate_mmio(run, vcpu); | ||
397 | } | ||
398 | |||
399 | break; | ||
400 | } | ||
401 | |||
402 | case BOOKE_INTERRUPT_ITLB_MISS: { | ||
403 | struct tlbe *gtlbe; | ||
404 | unsigned long eaddr = vcpu->arch.pc; | ||
405 | gfn_t gfn; | ||
406 | |||
407 | r = RESUME_GUEST; | ||
408 | |||
409 | /* Check the guest TLB. */ | ||
410 | gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr); | ||
411 | if (!gtlbe) { | ||
412 | /* The guest didn't have a mapping for it. */ | ||
413 | kvmppc_queue_exception(vcpu, exit_nr); | ||
414 | vcpu->stat.itlb_real_miss_exits++; | ||
415 | break; | ||
416 | } | ||
417 | |||
418 | vcpu->stat.itlb_virt_miss_exits++; | ||
419 | |||
420 | gfn = tlb_xlate(gtlbe, eaddr) >> PAGE_SHIFT; | ||
421 | |||
422 | if (kvm_is_visible_gfn(vcpu->kvm, gfn)) { | ||
423 | /* The guest TLB had a mapping, but the shadow TLB | ||
424 | * didn't. This could be because: | ||
425 | * a) the entry is mapping the host kernel, or | ||
426 | * b) the guest used a large mapping which we're faking | ||
427 | * Either way, we need to satisfy the fault without | ||
428 | * invoking the guest. */ | ||
429 | kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid, | ||
430 | gtlbe->word2); | ||
431 | } else { | ||
432 | /* Guest mapped and leaped at non-RAM! */ | ||
433 | kvmppc_queue_exception(vcpu, | ||
434 | BOOKE_INTERRUPT_MACHINE_CHECK); | ||
435 | } | ||
436 | |||
437 | break; | ||
438 | } | ||
439 | |||
440 | default: | ||
441 | printk(KERN_EMERG "exit_nr %d\n", exit_nr); | ||
442 | BUG(); | ||
443 | } | ||
444 | |||
445 | local_irq_disable(); | ||
446 | |||
447 | kvmppc_check_and_deliver_interrupts(vcpu); | ||
448 | |||
449 | /* Do some exit accounting. */ | ||
450 | vcpu->stat.sum_exits++; | ||
451 | if (!(r & RESUME_HOST)) { | ||
452 | /* To avoid clobbering exit_reason, only check for signals if | ||
453 | * we aren't already exiting to userspace for some other | ||
454 | * reason. */ | ||
455 | if (signal_pending(current)) { | ||
456 | run->exit_reason = KVM_EXIT_INTR; | ||
457 | r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV); | ||
458 | |||
459 | vcpu->stat.signal_exits++; | ||
460 | } else { | ||
461 | vcpu->stat.light_exits++; | ||
462 | } | ||
463 | } else { | ||
464 | switch (run->exit_reason) { | ||
465 | case KVM_EXIT_MMIO: | ||
466 | vcpu->stat.mmio_exits++; | ||
467 | break; | ||
468 | case KVM_EXIT_DCR: | ||
469 | vcpu->stat.dcr_exits++; | ||
470 | break; | ||
471 | case KVM_EXIT_INTR: | ||
472 | vcpu->stat.signal_exits++; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | return r; | ||
478 | } | ||
479 | |||
480 | /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */ | ||
481 | int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||
482 | { | ||
483 | struct tlbe *tlbe = &vcpu->arch.guest_tlb[0]; | ||
484 | |||
485 | tlbe->tid = 0; | ||
486 | tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID; | ||
487 | tlbe->word1 = 0; | ||
488 | tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR; | ||
489 | |||
490 | tlbe++; | ||
491 | tlbe->tid = 0; | ||
492 | tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID; | ||
493 | tlbe->word1 = 0xef600000; | ||
494 | tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR | ||
495 | | PPC44x_TLB_I | PPC44x_TLB_G; | ||
496 | |||
497 | vcpu->arch.pc = 0; | ||
498 | vcpu->arch.msr = 0; | ||
499 | vcpu->arch.gpr[1] = (16<<20) - 8; /* -8 for the callee-save LR slot */ | ||
500 | |||
501 | /* Eye-catching number so we know if the guest takes an interrupt | ||
502 | * before it's programmed its own IVPR. */ | ||
503 | vcpu->arch.ivpr = 0x55550000; | ||
504 | |||
505 | /* Since the guest can directly access the timebase, it must know the | ||
506 | * real timebase frequency. Accordingly, it must see the state of | ||
507 | * CCR1[TCS]. */ | ||
508 | vcpu->arch.ccr1 = mfspr(SPRN_CCR1); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
514 | { | ||
515 | int i; | ||
516 | |||
517 | regs->pc = vcpu->arch.pc; | ||
518 | regs->cr = vcpu->arch.cr; | ||
519 | regs->ctr = vcpu->arch.ctr; | ||
520 | regs->lr = vcpu->arch.lr; | ||
521 | regs->xer = vcpu->arch.xer; | ||
522 | regs->msr = vcpu->arch.msr; | ||
523 | regs->srr0 = vcpu->arch.srr0; | ||
524 | regs->srr1 = vcpu->arch.srr1; | ||
525 | regs->pid = vcpu->arch.pid; | ||
526 | regs->sprg0 = vcpu->arch.sprg0; | ||
527 | regs->sprg1 = vcpu->arch.sprg1; | ||
528 | regs->sprg2 = vcpu->arch.sprg2; | ||
529 | regs->sprg3 = vcpu->arch.sprg3; | ||
530 | regs->sprg5 = vcpu->arch.sprg4; | ||
531 | regs->sprg6 = vcpu->arch.sprg5; | ||
532 | regs->sprg7 = vcpu->arch.sprg6; | ||
533 | |||
534 | for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||
535 | regs->gpr[i] = vcpu->arch.gpr[i]; | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
541 | { | ||
542 | int i; | ||
543 | |||
544 | vcpu->arch.pc = regs->pc; | ||
545 | vcpu->arch.cr = regs->cr; | ||
546 | vcpu->arch.ctr = regs->ctr; | ||
547 | vcpu->arch.lr = regs->lr; | ||
548 | vcpu->arch.xer = regs->xer; | ||
549 | vcpu->arch.msr = regs->msr; | ||
550 | vcpu->arch.srr0 = regs->srr0; | ||
551 | vcpu->arch.srr1 = regs->srr1; | ||
552 | vcpu->arch.sprg0 = regs->sprg0; | ||
553 | vcpu->arch.sprg1 = regs->sprg1; | ||
554 | vcpu->arch.sprg2 = regs->sprg2; | ||
555 | vcpu->arch.sprg3 = regs->sprg3; | ||
556 | vcpu->arch.sprg5 = regs->sprg4; | ||
557 | vcpu->arch.sprg6 = regs->sprg5; | ||
558 | vcpu->arch.sprg7 = regs->sprg6; | ||
559 | |||
560 | for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++) | ||
561 | vcpu->arch.gpr[i] = regs->gpr[i]; | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||
567 | struct kvm_sregs *sregs) | ||
568 | { | ||
569 | return -ENOTSUPP; | ||
570 | } | ||
571 | |||
572 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||
573 | struct kvm_sregs *sregs) | ||
574 | { | ||
575 | return -ENOTSUPP; | ||
576 | } | ||
577 | |||
578 | int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
579 | { | ||
580 | return -ENOTSUPP; | ||
581 | } | ||
582 | |||
583 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
584 | { | ||
585 | return -ENOTSUPP; | ||
586 | } | ||
587 | |||
588 | /* 'linear_address' is actually an encoding of AS|PID|EADDR . */ | ||
589 | int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||
590 | struct kvm_translation *tr) | ||
591 | { | ||
592 | struct tlbe *gtlbe; | ||
593 | int index; | ||
594 | gva_t eaddr; | ||
595 | u8 pid; | ||
596 | u8 as; | ||
597 | |||
598 | eaddr = tr->linear_address; | ||
599 | pid = (tr->linear_address >> 32) & 0xff; | ||
600 | as = (tr->linear_address >> 40) & 0x1; | ||
601 | |||
602 | index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as); | ||
603 | if (index == -1) { | ||
604 | tr->valid = 0; | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | gtlbe = &vcpu->arch.guest_tlb[index]; | ||
609 | |||
610 | tr->physical_address = tlb_xlate(gtlbe, eaddr); | ||
611 | /* XXX what does "writeable" and "usermode" even mean? */ | ||
612 | tr->valid = 1; | ||
613 | |||
614 | return 0; | ||
615 | } | ||
diff --git a/arch/powerpc/kvm/booke_host.c b/arch/powerpc/kvm/booke_host.c new file mode 100644 index 000000000000..b480341bc31e --- /dev/null +++ b/arch/powerpc/kvm/booke_host.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2008 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/errno.h> | ||
21 | #include <linux/kvm_host.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <asm/cacheflush.h> | ||
24 | #include <asm/kvm_ppc.h> | ||
25 | |||
26 | unsigned long kvmppc_booke_handlers; | ||
27 | |||
28 | static int kvmppc_booke_init(void) | ||
29 | { | ||
30 | unsigned long ivor[16]; | ||
31 | unsigned long max_ivor = 0; | ||
32 | int i; | ||
33 | |||
34 | /* We install our own exception handlers by hijacking IVPR. IVPR must | ||
35 | * be 16-bit aligned, so we need a 64KB allocation. */ | ||
36 | kvmppc_booke_handlers = __get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
37 | VCPU_SIZE_ORDER); | ||
38 | if (!kvmppc_booke_handlers) | ||
39 | return -ENOMEM; | ||
40 | |||
41 | /* XXX make sure our handlers are smaller than Linux's */ | ||
42 | |||
43 | /* Copy our interrupt handlers to match host IVORs. That way we don't | ||
44 | * have to swap the IVORs on every guest/host transition. */ | ||
45 | ivor[0] = mfspr(SPRN_IVOR0); | ||
46 | ivor[1] = mfspr(SPRN_IVOR1); | ||
47 | ivor[2] = mfspr(SPRN_IVOR2); | ||
48 | ivor[3] = mfspr(SPRN_IVOR3); | ||
49 | ivor[4] = mfspr(SPRN_IVOR4); | ||
50 | ivor[5] = mfspr(SPRN_IVOR5); | ||
51 | ivor[6] = mfspr(SPRN_IVOR6); | ||
52 | ivor[7] = mfspr(SPRN_IVOR7); | ||
53 | ivor[8] = mfspr(SPRN_IVOR8); | ||
54 | ivor[9] = mfspr(SPRN_IVOR9); | ||
55 | ivor[10] = mfspr(SPRN_IVOR10); | ||
56 | ivor[11] = mfspr(SPRN_IVOR11); | ||
57 | ivor[12] = mfspr(SPRN_IVOR12); | ||
58 | ivor[13] = mfspr(SPRN_IVOR13); | ||
59 | ivor[14] = mfspr(SPRN_IVOR14); | ||
60 | ivor[15] = mfspr(SPRN_IVOR15); | ||
61 | |||
62 | for (i = 0; i < 16; i++) { | ||
63 | if (ivor[i] > max_ivor) | ||
64 | max_ivor = ivor[i]; | ||
65 | |||
66 | memcpy((void *)kvmppc_booke_handlers + ivor[i], | ||
67 | kvmppc_handlers_start + i * kvmppc_handler_len, | ||
68 | kvmppc_handler_len); | ||
69 | } | ||
70 | flush_icache_range(kvmppc_booke_handlers, | ||
71 | kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | ||
72 | |||
73 | return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE); | ||
74 | } | ||
75 | |||
76 | static void __exit kvmppc_booke_exit(void) | ||
77 | { | ||
78 | free_pages(kvmppc_booke_handlers, VCPU_SIZE_ORDER); | ||
79 | kvm_exit(); | ||
80 | } | ||
81 | |||
82 | module_init(kvmppc_booke_init) | ||
83 | module_exit(kvmppc_booke_exit) | ||
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S new file mode 100644 index 000000000000..3b653b5309b8 --- /dev/null +++ b/arch/powerpc/kvm/booke_interrupts.S | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #include <asm/ppc_asm.h> | ||
21 | #include <asm/kvm_asm.h> | ||
22 | #include <asm/reg.h> | ||
23 | #include <asm/mmu-44x.h> | ||
24 | #include <asm/page.h> | ||
25 | #include <asm/asm-offsets.h> | ||
26 | |||
27 | #define KVMPPC_MSR_MASK (MSR_CE|MSR_EE|MSR_PR|MSR_DE|MSR_ME|MSR_IS|MSR_DS) | ||
28 | |||
29 | #define VCPU_GPR(n) (VCPU_GPRS + (n * 4)) | ||
30 | |||
31 | /* The host stack layout: */ | ||
32 | #define HOST_R1 0 /* Implied by stwu. */ | ||
33 | #define HOST_CALLEE_LR 4 | ||
34 | #define HOST_RUN 8 | ||
35 | /* r2 is special: it holds 'current', and it made nonvolatile in the | ||
36 | * kernel with the -ffixed-r2 gcc option. */ | ||
37 | #define HOST_R2 12 | ||
38 | #define HOST_NV_GPRS 16 | ||
39 | #define HOST_NV_GPR(n) (HOST_NV_GPRS + ((n - 14) * 4)) | ||
40 | #define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + 4) | ||
41 | #define HOST_STACK_SIZE (((HOST_MIN_STACK_SIZE + 15) / 16) * 16) /* Align. */ | ||
42 | #define HOST_STACK_LR (HOST_STACK_SIZE + 4) /* In caller stack frame. */ | ||
43 | |||
44 | #define NEED_INST_MASK ((1<<BOOKE_INTERRUPT_PROGRAM) | \ | ||
45 | (1<<BOOKE_INTERRUPT_DTLB_MISS)) | ||
46 | |||
47 | #define NEED_DEAR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \ | ||
48 | (1<<BOOKE_INTERRUPT_DTLB_MISS)) | ||
49 | |||
50 | #define NEED_ESR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \ | ||
51 | (1<<BOOKE_INTERRUPT_INST_STORAGE) | \ | ||
52 | (1<<BOOKE_INTERRUPT_PROGRAM) | \ | ||
53 | (1<<BOOKE_INTERRUPT_DTLB_MISS)) | ||
54 | |||
55 | .macro KVM_HANDLER ivor_nr | ||
56 | _GLOBAL(kvmppc_handler_\ivor_nr) | ||
57 | /* Get pointer to vcpu and record exit number. */ | ||
58 | mtspr SPRN_SPRG0, r4 | ||
59 | mfspr r4, SPRN_SPRG1 | ||
60 | stw r5, VCPU_GPR(r5)(r4) | ||
61 | stw r6, VCPU_GPR(r6)(r4) | ||
62 | mfctr r5 | ||
63 | lis r6, kvmppc_resume_host@h | ||
64 | stw r5, VCPU_CTR(r4) | ||
65 | li r5, \ivor_nr | ||
66 | ori r6, r6, kvmppc_resume_host@l | ||
67 | mtctr r6 | ||
68 | bctr | ||
69 | .endm | ||
70 | |||
71 | _GLOBAL(kvmppc_handlers_start) | ||
72 | KVM_HANDLER BOOKE_INTERRUPT_CRITICAL | ||
73 | KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK | ||
74 | KVM_HANDLER BOOKE_INTERRUPT_DATA_STORAGE | ||
75 | KVM_HANDLER BOOKE_INTERRUPT_INST_STORAGE | ||
76 | KVM_HANDLER BOOKE_INTERRUPT_EXTERNAL | ||
77 | KVM_HANDLER BOOKE_INTERRUPT_ALIGNMENT | ||
78 | KVM_HANDLER BOOKE_INTERRUPT_PROGRAM | ||
79 | KVM_HANDLER BOOKE_INTERRUPT_FP_UNAVAIL | ||
80 | KVM_HANDLER BOOKE_INTERRUPT_SYSCALL | ||
81 | KVM_HANDLER BOOKE_INTERRUPT_AP_UNAVAIL | ||
82 | KVM_HANDLER BOOKE_INTERRUPT_DECREMENTER | ||
83 | KVM_HANDLER BOOKE_INTERRUPT_FIT | ||
84 | KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG | ||
85 | KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS | ||
86 | KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS | ||
87 | KVM_HANDLER BOOKE_INTERRUPT_DEBUG | ||
88 | |||
89 | _GLOBAL(kvmppc_handler_len) | ||
90 | .long kvmppc_handler_1 - kvmppc_handler_0 | ||
91 | |||
92 | |||
93 | /* Registers: | ||
94 | * SPRG0: guest r4 | ||
95 | * r4: vcpu pointer | ||
96 | * r5: KVM exit number | ||
97 | */ | ||
98 | _GLOBAL(kvmppc_resume_host) | ||
99 | stw r3, VCPU_GPR(r3)(r4) | ||
100 | mfcr r3 | ||
101 | stw r3, VCPU_CR(r4) | ||
102 | stw r7, VCPU_GPR(r7)(r4) | ||
103 | stw r8, VCPU_GPR(r8)(r4) | ||
104 | stw r9, VCPU_GPR(r9)(r4) | ||
105 | |||
106 | li r6, 1 | ||
107 | slw r6, r6, r5 | ||
108 | |||
109 | /* Save the faulting instruction and all GPRs for emulation. */ | ||
110 | andi. r7, r6, NEED_INST_MASK | ||
111 | beq ..skip_inst_copy | ||
112 | mfspr r9, SPRN_SRR0 | ||
113 | mfmsr r8 | ||
114 | ori r7, r8, MSR_DS | ||
115 | mtmsr r7 | ||
116 | isync | ||
117 | lwz r9, 0(r9) | ||
118 | mtmsr r8 | ||
119 | isync | ||
120 | stw r9, VCPU_LAST_INST(r4) | ||
121 | |||
122 | stw r15, VCPU_GPR(r15)(r4) | ||
123 | stw r16, VCPU_GPR(r16)(r4) | ||
124 | stw r17, VCPU_GPR(r17)(r4) | ||
125 | stw r18, VCPU_GPR(r18)(r4) | ||
126 | stw r19, VCPU_GPR(r19)(r4) | ||
127 | stw r20, VCPU_GPR(r20)(r4) | ||
128 | stw r21, VCPU_GPR(r21)(r4) | ||
129 | stw r22, VCPU_GPR(r22)(r4) | ||
130 | stw r23, VCPU_GPR(r23)(r4) | ||
131 | stw r24, VCPU_GPR(r24)(r4) | ||
132 | stw r25, VCPU_GPR(r25)(r4) | ||
133 | stw r26, VCPU_GPR(r26)(r4) | ||
134 | stw r27, VCPU_GPR(r27)(r4) | ||
135 | stw r28, VCPU_GPR(r28)(r4) | ||
136 | stw r29, VCPU_GPR(r29)(r4) | ||
137 | stw r30, VCPU_GPR(r30)(r4) | ||
138 | stw r31, VCPU_GPR(r31)(r4) | ||
139 | ..skip_inst_copy: | ||
140 | |||
141 | /* Also grab DEAR and ESR before the host can clobber them. */ | ||
142 | |||
143 | andi. r7, r6, NEED_DEAR_MASK | ||
144 | beq ..skip_dear | ||
145 | mfspr r9, SPRN_DEAR | ||
146 | stw r9, VCPU_FAULT_DEAR(r4) | ||
147 | ..skip_dear: | ||
148 | |||
149 | andi. r7, r6, NEED_ESR_MASK | ||
150 | beq ..skip_esr | ||
151 | mfspr r9, SPRN_ESR | ||
152 | stw r9, VCPU_FAULT_ESR(r4) | ||
153 | ..skip_esr: | ||
154 | |||
155 | /* Save remaining volatile guest register state to vcpu. */ | ||
156 | stw r0, VCPU_GPR(r0)(r4) | ||
157 | stw r1, VCPU_GPR(r1)(r4) | ||
158 | stw r2, VCPU_GPR(r2)(r4) | ||
159 | stw r10, VCPU_GPR(r10)(r4) | ||
160 | stw r11, VCPU_GPR(r11)(r4) | ||
161 | stw r12, VCPU_GPR(r12)(r4) | ||
162 | stw r13, VCPU_GPR(r13)(r4) | ||
163 | stw r14, VCPU_GPR(r14)(r4) /* We need a NV GPR below. */ | ||
164 | mflr r3 | ||
165 | stw r3, VCPU_LR(r4) | ||
166 | mfxer r3 | ||
167 | stw r3, VCPU_XER(r4) | ||
168 | mfspr r3, SPRN_SPRG0 | ||
169 | stw r3, VCPU_GPR(r4)(r4) | ||
170 | mfspr r3, SPRN_SRR0 | ||
171 | stw r3, VCPU_PC(r4) | ||
172 | |||
173 | /* Restore host stack pointer and PID before IVPR, since the host | ||
174 | * exception handlers use them. */ | ||
175 | lwz r1, VCPU_HOST_STACK(r4) | ||
176 | lwz r3, VCPU_HOST_PID(r4) | ||
177 | mtspr SPRN_PID, r3 | ||
178 | |||
179 | /* Restore host IVPR before re-enabling interrupts. We cheat and know | ||
180 | * that Linux IVPR is always 0xc0000000. */ | ||
181 | lis r3, 0xc000 | ||
182 | mtspr SPRN_IVPR, r3 | ||
183 | |||
184 | /* Switch to kernel stack and jump to handler. */ | ||
185 | LOAD_REG_ADDR(r3, kvmppc_handle_exit) | ||
186 | mtctr r3 | ||
187 | lwz r3, HOST_RUN(r1) | ||
188 | lwz r2, HOST_R2(r1) | ||
189 | mr r14, r4 /* Save vcpu pointer. */ | ||
190 | |||
191 | bctrl /* kvmppc_handle_exit() */ | ||
192 | |||
193 | /* Restore vcpu pointer and the nonvolatiles we used. */ | ||
194 | mr r4, r14 | ||
195 | lwz r14, VCPU_GPR(r14)(r4) | ||
196 | |||
197 | /* Sometimes instruction emulation must restore complete GPR state. */ | ||
198 | andi. r5, r3, RESUME_FLAG_NV | ||
199 | beq ..skip_nv_load | ||
200 | lwz r15, VCPU_GPR(r15)(r4) | ||
201 | lwz r16, VCPU_GPR(r16)(r4) | ||
202 | lwz r17, VCPU_GPR(r17)(r4) | ||
203 | lwz r18, VCPU_GPR(r18)(r4) | ||
204 | lwz r19, VCPU_GPR(r19)(r4) | ||
205 | lwz r20, VCPU_GPR(r20)(r4) | ||
206 | lwz r21, VCPU_GPR(r21)(r4) | ||
207 | lwz r22, VCPU_GPR(r22)(r4) | ||
208 | lwz r23, VCPU_GPR(r23)(r4) | ||
209 | lwz r24, VCPU_GPR(r24)(r4) | ||
210 | lwz r25, VCPU_GPR(r25)(r4) | ||
211 | lwz r26, VCPU_GPR(r26)(r4) | ||
212 | lwz r27, VCPU_GPR(r27)(r4) | ||
213 | lwz r28, VCPU_GPR(r28)(r4) | ||
214 | lwz r29, VCPU_GPR(r29)(r4) | ||
215 | lwz r30, VCPU_GPR(r30)(r4) | ||
216 | lwz r31, VCPU_GPR(r31)(r4) | ||
217 | ..skip_nv_load: | ||
218 | |||
219 | /* Should we return to the guest? */ | ||
220 | andi. r5, r3, RESUME_FLAG_HOST | ||
221 | beq lightweight_exit | ||
222 | |||
223 | srawi r3, r3, 2 /* Shift -ERR back down. */ | ||
224 | |||
225 | heavyweight_exit: | ||
226 | /* Not returning to guest. */ | ||
227 | |||
228 | /* We already saved guest volatile register state; now save the | ||
229 | * non-volatiles. */ | ||
230 | stw r15, VCPU_GPR(r15)(r4) | ||
231 | stw r16, VCPU_GPR(r16)(r4) | ||
232 | stw r17, VCPU_GPR(r17)(r4) | ||
233 | stw r18, VCPU_GPR(r18)(r4) | ||
234 | stw r19, VCPU_GPR(r19)(r4) | ||
235 | stw r20, VCPU_GPR(r20)(r4) | ||
236 | stw r21, VCPU_GPR(r21)(r4) | ||
237 | stw r22, VCPU_GPR(r22)(r4) | ||
238 | stw r23, VCPU_GPR(r23)(r4) | ||
239 | stw r24, VCPU_GPR(r24)(r4) | ||
240 | stw r25, VCPU_GPR(r25)(r4) | ||
241 | stw r26, VCPU_GPR(r26)(r4) | ||
242 | stw r27, VCPU_GPR(r27)(r4) | ||
243 | stw r28, VCPU_GPR(r28)(r4) | ||
244 | stw r29, VCPU_GPR(r29)(r4) | ||
245 | stw r30, VCPU_GPR(r30)(r4) | ||
246 | stw r31, VCPU_GPR(r31)(r4) | ||
247 | |||
248 | /* Load host non-volatile register state from host stack. */ | ||
249 | lwz r14, HOST_NV_GPR(r14)(r1) | ||
250 | lwz r15, HOST_NV_GPR(r15)(r1) | ||
251 | lwz r16, HOST_NV_GPR(r16)(r1) | ||
252 | lwz r17, HOST_NV_GPR(r17)(r1) | ||
253 | lwz r18, HOST_NV_GPR(r18)(r1) | ||
254 | lwz r19, HOST_NV_GPR(r19)(r1) | ||
255 | lwz r20, HOST_NV_GPR(r20)(r1) | ||
256 | lwz r21, HOST_NV_GPR(r21)(r1) | ||
257 | lwz r22, HOST_NV_GPR(r22)(r1) | ||
258 | lwz r23, HOST_NV_GPR(r23)(r1) | ||
259 | lwz r24, HOST_NV_GPR(r24)(r1) | ||
260 | lwz r25, HOST_NV_GPR(r25)(r1) | ||
261 | lwz r26, HOST_NV_GPR(r26)(r1) | ||
262 | lwz r27, HOST_NV_GPR(r27)(r1) | ||
263 | lwz r28, HOST_NV_GPR(r28)(r1) | ||
264 | lwz r29, HOST_NV_GPR(r29)(r1) | ||
265 | lwz r30, HOST_NV_GPR(r30)(r1) | ||
266 | lwz r31, HOST_NV_GPR(r31)(r1) | ||
267 | |||
268 | /* Return to kvm_vcpu_run(). */ | ||
269 | lwz r4, HOST_STACK_LR(r1) | ||
270 | addi r1, r1, HOST_STACK_SIZE | ||
271 | mtlr r4 | ||
272 | /* r3 still contains the return code from kvmppc_handle_exit(). */ | ||
273 | blr | ||
274 | |||
275 | |||
276 | /* Registers: | ||
277 | * r3: kvm_run pointer | ||
278 | * r4: vcpu pointer | ||
279 | */ | ||
280 | _GLOBAL(__kvmppc_vcpu_run) | ||
281 | stwu r1, -HOST_STACK_SIZE(r1) | ||
282 | stw r1, VCPU_HOST_STACK(r4) /* Save stack pointer to vcpu. */ | ||
283 | |||
284 | /* Save host state to stack. */ | ||
285 | stw r3, HOST_RUN(r1) | ||
286 | mflr r3 | ||
287 | stw r3, HOST_STACK_LR(r1) | ||
288 | |||
289 | /* Save host non-volatile register state to stack. */ | ||
290 | stw r14, HOST_NV_GPR(r14)(r1) | ||
291 | stw r15, HOST_NV_GPR(r15)(r1) | ||
292 | stw r16, HOST_NV_GPR(r16)(r1) | ||
293 | stw r17, HOST_NV_GPR(r17)(r1) | ||
294 | stw r18, HOST_NV_GPR(r18)(r1) | ||
295 | stw r19, HOST_NV_GPR(r19)(r1) | ||
296 | stw r20, HOST_NV_GPR(r20)(r1) | ||
297 | stw r21, HOST_NV_GPR(r21)(r1) | ||
298 | stw r22, HOST_NV_GPR(r22)(r1) | ||
299 | stw r23, HOST_NV_GPR(r23)(r1) | ||
300 | stw r24, HOST_NV_GPR(r24)(r1) | ||
301 | stw r25, HOST_NV_GPR(r25)(r1) | ||
302 | stw r26, HOST_NV_GPR(r26)(r1) | ||
303 | stw r27, HOST_NV_GPR(r27)(r1) | ||
304 | stw r28, HOST_NV_GPR(r28)(r1) | ||
305 | stw r29, HOST_NV_GPR(r29)(r1) | ||
306 | stw r30, HOST_NV_GPR(r30)(r1) | ||
307 | stw r31, HOST_NV_GPR(r31)(r1) | ||
308 | |||
309 | /* Load guest non-volatiles. */ | ||
310 | lwz r14, VCPU_GPR(r14)(r4) | ||
311 | lwz r15, VCPU_GPR(r15)(r4) | ||
312 | lwz r16, VCPU_GPR(r16)(r4) | ||
313 | lwz r17, VCPU_GPR(r17)(r4) | ||
314 | lwz r18, VCPU_GPR(r18)(r4) | ||
315 | lwz r19, VCPU_GPR(r19)(r4) | ||
316 | lwz r20, VCPU_GPR(r20)(r4) | ||
317 | lwz r21, VCPU_GPR(r21)(r4) | ||
318 | lwz r22, VCPU_GPR(r22)(r4) | ||
319 | lwz r23, VCPU_GPR(r23)(r4) | ||
320 | lwz r24, VCPU_GPR(r24)(r4) | ||
321 | lwz r25, VCPU_GPR(r25)(r4) | ||
322 | lwz r26, VCPU_GPR(r26)(r4) | ||
323 | lwz r27, VCPU_GPR(r27)(r4) | ||
324 | lwz r28, VCPU_GPR(r28)(r4) | ||
325 | lwz r29, VCPU_GPR(r29)(r4) | ||
326 | lwz r30, VCPU_GPR(r30)(r4) | ||
327 | lwz r31, VCPU_GPR(r31)(r4) | ||
328 | |||
329 | lightweight_exit: | ||
330 | stw r2, HOST_R2(r1) | ||
331 | |||
332 | mfspr r3, SPRN_PID | ||
333 | stw r3, VCPU_HOST_PID(r4) | ||
334 | lwz r3, VCPU_PID(r4) | ||
335 | mtspr SPRN_PID, r3 | ||
336 | |||
337 | /* Prevent all TLB updates. */ | ||
338 | mfmsr r5 | ||
339 | lis r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@h | ||
340 | ori r6, r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l | ||
341 | andc r6, r5, r6 | ||
342 | mtmsr r6 | ||
343 | |||
344 | /* Save the host's non-pinned TLB mappings, and load the guest mappings | ||
345 | * over them. Leave the host's "pinned" kernel mappings in place. */ | ||
346 | /* XXX optimization: use generation count to avoid swapping unmodified | ||
347 | * entries. */ | ||
348 | mfspr r10, SPRN_MMUCR /* Save host MMUCR. */ | ||
349 | lis r8, tlb_44x_hwater@ha | ||
350 | lwz r8, tlb_44x_hwater@l(r8) | ||
351 | addi r3, r4, VCPU_HOST_TLB - 4 | ||
352 | addi r9, r4, VCPU_SHADOW_TLB - 4 | ||
353 | li r6, 0 | ||
354 | 1: | ||
355 | /* Save host entry. */ | ||
356 | tlbre r7, r6, PPC44x_TLB_PAGEID | ||
357 | mfspr r5, SPRN_MMUCR | ||
358 | stwu r5, 4(r3) | ||
359 | stwu r7, 4(r3) | ||
360 | tlbre r7, r6, PPC44x_TLB_XLAT | ||
361 | stwu r7, 4(r3) | ||
362 | tlbre r7, r6, PPC44x_TLB_ATTRIB | ||
363 | stwu r7, 4(r3) | ||
364 | /* Load guest entry. */ | ||
365 | lwzu r7, 4(r9) | ||
366 | mtspr SPRN_MMUCR, r7 | ||
367 | lwzu r7, 4(r9) | ||
368 | tlbwe r7, r6, PPC44x_TLB_PAGEID | ||
369 | lwzu r7, 4(r9) | ||
370 | tlbwe r7, r6, PPC44x_TLB_XLAT | ||
371 | lwzu r7, 4(r9) | ||
372 | tlbwe r7, r6, PPC44x_TLB_ATTRIB | ||
373 | /* Increment index. */ | ||
374 | addi r6, r6, 1 | ||
375 | cmpw r6, r8 | ||
376 | blt 1b | ||
377 | mtspr SPRN_MMUCR, r10 /* Restore host MMUCR. */ | ||
378 | |||
379 | iccci 0, 0 /* XXX hack */ | ||
380 | |||
381 | /* Load some guest volatiles. */ | ||
382 | lwz r0, VCPU_GPR(r0)(r4) | ||
383 | lwz r2, VCPU_GPR(r2)(r4) | ||
384 | lwz r9, VCPU_GPR(r9)(r4) | ||
385 | lwz r10, VCPU_GPR(r10)(r4) | ||
386 | lwz r11, VCPU_GPR(r11)(r4) | ||
387 | lwz r12, VCPU_GPR(r12)(r4) | ||
388 | lwz r13, VCPU_GPR(r13)(r4) | ||
389 | lwz r3, VCPU_LR(r4) | ||
390 | mtlr r3 | ||
391 | lwz r3, VCPU_XER(r4) | ||
392 | mtxer r3 | ||
393 | |||
394 | /* Switch the IVPR. XXX If we take a TLB miss after this we're screwed, | ||
395 | * so how do we make sure vcpu won't fault? */ | ||
396 | lis r8, kvmppc_booke_handlers@ha | ||
397 | lwz r8, kvmppc_booke_handlers@l(r8) | ||
398 | mtspr SPRN_IVPR, r8 | ||
399 | |||
400 | /* Save vcpu pointer for the exception handlers. */ | ||
401 | mtspr SPRN_SPRG1, r4 | ||
402 | |||
403 | /* Can't switch the stack pointer until after IVPR is switched, | ||
404 | * because host interrupt handlers would get confused. */ | ||
405 | lwz r1, VCPU_GPR(r1)(r4) | ||
406 | |||
407 | /* XXX handle USPRG0 */ | ||
408 | /* Host interrupt handlers may have clobbered these guest-readable | ||
409 | * SPRGs, so we need to reload them here with the guest's values. */ | ||
410 | lwz r3, VCPU_SPRG4(r4) | ||
411 | mtspr SPRN_SPRG4, r3 | ||
412 | lwz r3, VCPU_SPRG5(r4) | ||
413 | mtspr SPRN_SPRG5, r3 | ||
414 | lwz r3, VCPU_SPRG6(r4) | ||
415 | mtspr SPRN_SPRG6, r3 | ||
416 | lwz r3, VCPU_SPRG7(r4) | ||
417 | mtspr SPRN_SPRG7, r3 | ||
418 | |||
419 | /* Finish loading guest volatiles and jump to guest. */ | ||
420 | lwz r3, VCPU_CTR(r4) | ||
421 | mtctr r3 | ||
422 | lwz r3, VCPU_CR(r4) | ||
423 | mtcr r3 | ||
424 | lwz r5, VCPU_GPR(r5)(r4) | ||
425 | lwz r6, VCPU_GPR(r6)(r4) | ||
426 | lwz r7, VCPU_GPR(r7)(r4) | ||
427 | lwz r8, VCPU_GPR(r8)(r4) | ||
428 | lwz r3, VCPU_PC(r4) | ||
429 | mtsrr0 r3 | ||
430 | lwz r3, VCPU_MSR(r4) | ||
431 | oris r3, r3, KVMPPC_MSR_MASK@h | ||
432 | ori r3, r3, KVMPPC_MSR_MASK@l | ||
433 | mtsrr1 r3 | ||
434 | lwz r3, VCPU_GPR(r3)(r4) | ||
435 | lwz r4, VCPU_GPR(r4)(r4) | ||
436 | rfi | ||
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c new file mode 100644 index 000000000000..a03fe0c80698 --- /dev/null +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -0,0 +1,760 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/kvm_host.h> | ||
25 | |||
26 | #include <asm/dcr.h> | ||
27 | #include <asm/dcr-regs.h> | ||
28 | #include <asm/time.h> | ||
29 | #include <asm/byteorder.h> | ||
30 | #include <asm/kvm_ppc.h> | ||
31 | |||
32 | #include "44x_tlb.h" | ||
33 | |||
34 | /* Instruction decoding */ | ||
35 | static inline unsigned int get_op(u32 inst) | ||
36 | { | ||
37 | return inst >> 26; | ||
38 | } | ||
39 | |||
40 | static inline unsigned int get_xop(u32 inst) | ||
41 | { | ||
42 | return (inst >> 1) & 0x3ff; | ||
43 | } | ||
44 | |||
45 | static inline unsigned int get_sprn(u32 inst) | ||
46 | { | ||
47 | return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0); | ||
48 | } | ||
49 | |||
50 | static inline unsigned int get_dcrn(u32 inst) | ||
51 | { | ||
52 | return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0); | ||
53 | } | ||
54 | |||
55 | static inline unsigned int get_rt(u32 inst) | ||
56 | { | ||
57 | return (inst >> 21) & 0x1f; | ||
58 | } | ||
59 | |||
60 | static inline unsigned int get_rs(u32 inst) | ||
61 | { | ||
62 | return (inst >> 21) & 0x1f; | ||
63 | } | ||
64 | |||
65 | static inline unsigned int get_ra(u32 inst) | ||
66 | { | ||
67 | return (inst >> 16) & 0x1f; | ||
68 | } | ||
69 | |||
70 | static inline unsigned int get_rb(u32 inst) | ||
71 | { | ||
72 | return (inst >> 11) & 0x1f; | ||
73 | } | ||
74 | |||
75 | static inline unsigned int get_rc(u32 inst) | ||
76 | { | ||
77 | return inst & 0x1; | ||
78 | } | ||
79 | |||
80 | static inline unsigned int get_ws(u32 inst) | ||
81 | { | ||
82 | return (inst >> 11) & 0x1f; | ||
83 | } | ||
84 | |||
85 | static inline unsigned int get_d(u32 inst) | ||
86 | { | ||
87 | return inst & 0xffff; | ||
88 | } | ||
89 | |||
90 | static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | ||
91 | const struct tlbe *tlbe) | ||
92 | { | ||
93 | gpa_t gpa; | ||
94 | |||
95 | if (!get_tlb_v(tlbe)) | ||
96 | return 0; | ||
97 | |||
98 | /* Does it match current guest AS? */ | ||
99 | /* XXX what about IS != DS? */ | ||
100 | if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS)) | ||
101 | return 0; | ||
102 | |||
103 | gpa = get_tlb_raddr(tlbe); | ||
104 | if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT)) | ||
105 | /* Mapping is not for RAM. */ | ||
106 | return 0; | ||
107 | |||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst) | ||
112 | { | ||
113 | u64 eaddr; | ||
114 | u64 raddr; | ||
115 | u64 asid; | ||
116 | u32 flags; | ||
117 | struct tlbe *tlbe; | ||
118 | unsigned int ra; | ||
119 | unsigned int rs; | ||
120 | unsigned int ws; | ||
121 | unsigned int index; | ||
122 | |||
123 | ra = get_ra(inst); | ||
124 | rs = get_rs(inst); | ||
125 | ws = get_ws(inst); | ||
126 | |||
127 | index = vcpu->arch.gpr[ra]; | ||
128 | if (index > PPC44x_TLB_SIZE) { | ||
129 | printk("%s: index %d\n", __func__, index); | ||
130 | kvmppc_dump_vcpu(vcpu); | ||
131 | return EMULATE_FAIL; | ||
132 | } | ||
133 | |||
134 | tlbe = &vcpu->arch.guest_tlb[index]; | ||
135 | |||
136 | /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */ | ||
137 | if (tlbe->word0 & PPC44x_TLB_VALID) { | ||
138 | eaddr = get_tlb_eaddr(tlbe); | ||
139 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
140 | kvmppc_mmu_invalidate(vcpu, eaddr, asid); | ||
141 | } | ||
142 | |||
143 | switch (ws) { | ||
144 | case PPC44x_TLB_PAGEID: | ||
145 | tlbe->tid = vcpu->arch.mmucr & 0xff; | ||
146 | tlbe->word0 = vcpu->arch.gpr[rs]; | ||
147 | break; | ||
148 | |||
149 | case PPC44x_TLB_XLAT: | ||
150 | tlbe->word1 = vcpu->arch.gpr[rs]; | ||
151 | break; | ||
152 | |||
153 | case PPC44x_TLB_ATTRIB: | ||
154 | tlbe->word2 = vcpu->arch.gpr[rs]; | ||
155 | break; | ||
156 | |||
157 | default: | ||
158 | return EMULATE_FAIL; | ||
159 | } | ||
160 | |||
161 | if (tlbe_is_host_safe(vcpu, tlbe)) { | ||
162 | eaddr = get_tlb_eaddr(tlbe); | ||
163 | raddr = get_tlb_raddr(tlbe); | ||
164 | asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid; | ||
165 | flags = tlbe->word2 & 0xffff; | ||
166 | |||
167 | /* Create a 4KB mapping on the host. If the guest wanted a | ||
168 | * large page, only the first 4KB is mapped here and the rest | ||
169 | * are mapped on the fly. */ | ||
170 | kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags); | ||
171 | } | ||
172 | |||
173 | return EMULATE_DONE; | ||
174 | } | ||
175 | |||
176 | static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | ||
177 | { | ||
178 | if (vcpu->arch.tcr & TCR_DIE) { | ||
179 | /* The decrementer ticks at the same rate as the timebase, so | ||
180 | * that's how we convert the guest DEC value to the number of | ||
181 | * host ticks. */ | ||
182 | unsigned long nr_jiffies; | ||
183 | |||
184 | nr_jiffies = vcpu->arch.dec / tb_ticks_per_jiffy; | ||
185 | mod_timer(&vcpu->arch.dec_timer, | ||
186 | get_jiffies_64() + nr_jiffies); | ||
187 | } else { | ||
188 | del_timer(&vcpu->arch.dec_timer); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) | ||
193 | { | ||
194 | vcpu->arch.pc = vcpu->arch.srr0; | ||
195 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||
196 | } | ||
197 | |||
198 | /* XXX to do: | ||
199 | * lhax | ||
200 | * lhaux | ||
201 | * lswx | ||
202 | * lswi | ||
203 | * stswx | ||
204 | * stswi | ||
205 | * lha | ||
206 | * lhau | ||
207 | * lmw | ||
208 | * stmw | ||
209 | * | ||
210 | * XXX is_bigendian should depend on MMU mapping or MSR[LE] | ||
211 | */ | ||
212 | int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||
213 | { | ||
214 | u32 inst = vcpu->arch.last_inst; | ||
215 | u32 ea; | ||
216 | int ra; | ||
217 | int rb; | ||
218 | int rc; | ||
219 | int rs; | ||
220 | int rt; | ||
221 | int sprn; | ||
222 | int dcrn; | ||
223 | enum emulation_result emulated = EMULATE_DONE; | ||
224 | int advance = 1; | ||
225 | |||
226 | switch (get_op(inst)) { | ||
227 | case 3: /* trap */ | ||
228 | printk("trap!\n"); | ||
229 | kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); | ||
230 | advance = 0; | ||
231 | break; | ||
232 | |||
233 | case 19: | ||
234 | switch (get_xop(inst)) { | ||
235 | case 50: /* rfi */ | ||
236 | kvmppc_emul_rfi(vcpu); | ||
237 | advance = 0; | ||
238 | break; | ||
239 | |||
240 | default: | ||
241 | emulated = EMULATE_FAIL; | ||
242 | break; | ||
243 | } | ||
244 | break; | ||
245 | |||
246 | case 31: | ||
247 | switch (get_xop(inst)) { | ||
248 | |||
249 | case 83: /* mfmsr */ | ||
250 | rt = get_rt(inst); | ||
251 | vcpu->arch.gpr[rt] = vcpu->arch.msr; | ||
252 | break; | ||
253 | |||
254 | case 87: /* lbzx */ | ||
255 | rt = get_rt(inst); | ||
256 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | ||
257 | break; | ||
258 | |||
259 | case 131: /* wrtee */ | ||
260 | rs = get_rs(inst); | ||
261 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
262 | | (vcpu->arch.gpr[rs] & MSR_EE); | ||
263 | break; | ||
264 | |||
265 | case 146: /* mtmsr */ | ||
266 | rs = get_rs(inst); | ||
267 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]); | ||
268 | break; | ||
269 | |||
270 | case 163: /* wrteei */ | ||
271 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | ||
272 | | (inst & MSR_EE); | ||
273 | break; | ||
274 | |||
275 | case 215: /* stbx */ | ||
276 | rs = get_rs(inst); | ||
277 | emulated = kvmppc_handle_store(run, vcpu, | ||
278 | vcpu->arch.gpr[rs], | ||
279 | 1, 1); | ||
280 | break; | ||
281 | |||
282 | case 247: /* stbux */ | ||
283 | rs = get_rs(inst); | ||
284 | ra = get_ra(inst); | ||
285 | rb = get_rb(inst); | ||
286 | |||
287 | ea = vcpu->arch.gpr[rb]; | ||
288 | if (ra) | ||
289 | ea += vcpu->arch.gpr[ra]; | ||
290 | |||
291 | emulated = kvmppc_handle_store(run, vcpu, | ||
292 | vcpu->arch.gpr[rs], | ||
293 | 1, 1); | ||
294 | vcpu->arch.gpr[rs] = ea; | ||
295 | break; | ||
296 | |||
297 | case 279: /* lhzx */ | ||
298 | rt = get_rt(inst); | ||
299 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | ||
300 | break; | ||
301 | |||
302 | case 311: /* lhzux */ | ||
303 | rt = get_rt(inst); | ||
304 | ra = get_ra(inst); | ||
305 | rb = get_rb(inst); | ||
306 | |||
307 | ea = vcpu->arch.gpr[rb]; | ||
308 | if (ra) | ||
309 | ea += vcpu->arch.gpr[ra]; | ||
310 | |||
311 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | ||
312 | vcpu->arch.gpr[ra] = ea; | ||
313 | break; | ||
314 | |||
315 | case 323: /* mfdcr */ | ||
316 | dcrn = get_dcrn(inst); | ||
317 | rt = get_rt(inst); | ||
318 | |||
319 | /* The guest may access CPR0 registers to determine the timebase | ||
320 | * frequency, and it must know the real host frequency because it | ||
321 | * can directly access the timebase registers. | ||
322 | * | ||
323 | * It would be possible to emulate those accesses in userspace, | ||
324 | * but userspace can really only figure out the end frequency. | ||
325 | * We could decompose that into the factors that compute it, but | ||
326 | * that's tricky math, and it's easier to just report the real | ||
327 | * CPR0 values. | ||
328 | */ | ||
329 | switch (dcrn) { | ||
330 | case DCRN_CPR0_CONFIG_ADDR: | ||
331 | vcpu->arch.gpr[rt] = vcpu->arch.cpr0_cfgaddr; | ||
332 | break; | ||
333 | case DCRN_CPR0_CONFIG_DATA: | ||
334 | local_irq_disable(); | ||
335 | mtdcr(DCRN_CPR0_CONFIG_ADDR, | ||
336 | vcpu->arch.cpr0_cfgaddr); | ||
337 | vcpu->arch.gpr[rt] = mfdcr(DCRN_CPR0_CONFIG_DATA); | ||
338 | local_irq_enable(); | ||
339 | break; | ||
340 | default: | ||
341 | run->dcr.dcrn = dcrn; | ||
342 | run->dcr.data = 0; | ||
343 | run->dcr.is_write = 0; | ||
344 | vcpu->arch.io_gpr = rt; | ||
345 | vcpu->arch.dcr_needed = 1; | ||
346 | emulated = EMULATE_DO_DCR; | ||
347 | } | ||
348 | |||
349 | break; | ||
350 | |||
351 | case 339: /* mfspr */ | ||
352 | sprn = get_sprn(inst); | ||
353 | rt = get_rt(inst); | ||
354 | |||
355 | switch (sprn) { | ||
356 | case SPRN_SRR0: | ||
357 | vcpu->arch.gpr[rt] = vcpu->arch.srr0; break; | ||
358 | case SPRN_SRR1: | ||
359 | vcpu->arch.gpr[rt] = vcpu->arch.srr1; break; | ||
360 | case SPRN_MMUCR: | ||
361 | vcpu->arch.gpr[rt] = vcpu->arch.mmucr; break; | ||
362 | case SPRN_PID: | ||
363 | vcpu->arch.gpr[rt] = vcpu->arch.pid; break; | ||
364 | case SPRN_IVPR: | ||
365 | vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break; | ||
366 | case SPRN_CCR0: | ||
367 | vcpu->arch.gpr[rt] = vcpu->arch.ccr0; break; | ||
368 | case SPRN_CCR1: | ||
369 | vcpu->arch.gpr[rt] = vcpu->arch.ccr1; break; | ||
370 | case SPRN_PVR: | ||
371 | vcpu->arch.gpr[rt] = vcpu->arch.pvr; break; | ||
372 | case SPRN_DEAR: | ||
373 | vcpu->arch.gpr[rt] = vcpu->arch.dear; break; | ||
374 | case SPRN_ESR: | ||
375 | vcpu->arch.gpr[rt] = vcpu->arch.esr; break; | ||
376 | case SPRN_DBCR0: | ||
377 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break; | ||
378 | case SPRN_DBCR1: | ||
379 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break; | ||
380 | |||
381 | /* Note: mftb and TBRL/TBWL are user-accessible, so | ||
382 | * the guest can always access the real TB anyways. | ||
383 | * In fact, we probably will never see these traps. */ | ||
384 | case SPRN_TBWL: | ||
385 | vcpu->arch.gpr[rt] = mftbl(); break; | ||
386 | case SPRN_TBWU: | ||
387 | vcpu->arch.gpr[rt] = mftbu(); break; | ||
388 | |||
389 | case SPRN_SPRG0: | ||
390 | vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break; | ||
391 | case SPRN_SPRG1: | ||
392 | vcpu->arch.gpr[rt] = vcpu->arch.sprg1; break; | ||
393 | case SPRN_SPRG2: | ||
394 | vcpu->arch.gpr[rt] = vcpu->arch.sprg2; break; | ||
395 | case SPRN_SPRG3: | ||
396 | vcpu->arch.gpr[rt] = vcpu->arch.sprg3; break; | ||
397 | /* Note: SPRG4-7 are user-readable, so we don't get | ||
398 | * a trap. */ | ||
399 | |||
400 | case SPRN_IVOR0: | ||
401 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[0]; break; | ||
402 | case SPRN_IVOR1: | ||
403 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[1]; break; | ||
404 | case SPRN_IVOR2: | ||
405 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[2]; break; | ||
406 | case SPRN_IVOR3: | ||
407 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[3]; break; | ||
408 | case SPRN_IVOR4: | ||
409 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[4]; break; | ||
410 | case SPRN_IVOR5: | ||
411 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[5]; break; | ||
412 | case SPRN_IVOR6: | ||
413 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[6]; break; | ||
414 | case SPRN_IVOR7: | ||
415 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[7]; break; | ||
416 | case SPRN_IVOR8: | ||
417 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[8]; break; | ||
418 | case SPRN_IVOR9: | ||
419 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[9]; break; | ||
420 | case SPRN_IVOR10: | ||
421 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[10]; break; | ||
422 | case SPRN_IVOR11: | ||
423 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[11]; break; | ||
424 | case SPRN_IVOR12: | ||
425 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[12]; break; | ||
426 | case SPRN_IVOR13: | ||
427 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[13]; break; | ||
428 | case SPRN_IVOR14: | ||
429 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[14]; break; | ||
430 | case SPRN_IVOR15: | ||
431 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[15]; break; | ||
432 | |||
433 | default: | ||
434 | printk("mfspr: unknown spr %x\n", sprn); | ||
435 | vcpu->arch.gpr[rt] = 0; | ||
436 | break; | ||
437 | } | ||
438 | break; | ||
439 | |||
440 | case 407: /* sthx */ | ||
441 | rs = get_rs(inst); | ||
442 | ra = get_ra(inst); | ||
443 | rb = get_rb(inst); | ||
444 | |||
445 | emulated = kvmppc_handle_store(run, vcpu, | ||
446 | vcpu->arch.gpr[rs], | ||
447 | 2, 1); | ||
448 | break; | ||
449 | |||
450 | case 439: /* sthux */ | ||
451 | rs = get_rs(inst); | ||
452 | ra = get_ra(inst); | ||
453 | rb = get_rb(inst); | ||
454 | |||
455 | ea = vcpu->arch.gpr[rb]; | ||
456 | if (ra) | ||
457 | ea += vcpu->arch.gpr[ra]; | ||
458 | |||
459 | emulated = kvmppc_handle_store(run, vcpu, | ||
460 | vcpu->arch.gpr[rs], | ||
461 | 2, 1); | ||
462 | vcpu->arch.gpr[ra] = ea; | ||
463 | break; | ||
464 | |||
465 | case 451: /* mtdcr */ | ||
466 | dcrn = get_dcrn(inst); | ||
467 | rs = get_rs(inst); | ||
468 | |||
469 | /* emulate some access in kernel */ | ||
470 | switch (dcrn) { | ||
471 | case DCRN_CPR0_CONFIG_ADDR: | ||
472 | vcpu->arch.cpr0_cfgaddr = vcpu->arch.gpr[rs]; | ||
473 | break; | ||
474 | default: | ||
475 | run->dcr.dcrn = dcrn; | ||
476 | run->dcr.data = vcpu->arch.gpr[rs]; | ||
477 | run->dcr.is_write = 1; | ||
478 | vcpu->arch.dcr_needed = 1; | ||
479 | emulated = EMULATE_DO_DCR; | ||
480 | } | ||
481 | |||
482 | break; | ||
483 | |||
484 | case 467: /* mtspr */ | ||
485 | sprn = get_sprn(inst); | ||
486 | rs = get_rs(inst); | ||
487 | switch (sprn) { | ||
488 | case SPRN_SRR0: | ||
489 | vcpu->arch.srr0 = vcpu->arch.gpr[rs]; break; | ||
490 | case SPRN_SRR1: | ||
491 | vcpu->arch.srr1 = vcpu->arch.gpr[rs]; break; | ||
492 | case SPRN_MMUCR: | ||
493 | vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break; | ||
494 | case SPRN_PID: | ||
495 | vcpu->arch.pid = vcpu->arch.gpr[rs]; break; | ||
496 | case SPRN_CCR0: | ||
497 | vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break; | ||
498 | case SPRN_CCR1: | ||
499 | vcpu->arch.ccr1 = vcpu->arch.gpr[rs]; break; | ||
500 | case SPRN_DEAR: | ||
501 | vcpu->arch.dear = vcpu->arch.gpr[rs]; break; | ||
502 | case SPRN_ESR: | ||
503 | vcpu->arch.esr = vcpu->arch.gpr[rs]; break; | ||
504 | case SPRN_DBCR0: | ||
505 | vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break; | ||
506 | case SPRN_DBCR1: | ||
507 | vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break; | ||
508 | |||
509 | /* XXX We need to context-switch the timebase for | ||
510 | * watchdog and FIT. */ | ||
511 | case SPRN_TBWL: break; | ||
512 | case SPRN_TBWU: break; | ||
513 | |||
514 | case SPRN_DEC: | ||
515 | vcpu->arch.dec = vcpu->arch.gpr[rs]; | ||
516 | kvmppc_emulate_dec(vcpu); | ||
517 | break; | ||
518 | |||
519 | case SPRN_TSR: | ||
520 | vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break; | ||
521 | |||
522 | case SPRN_TCR: | ||
523 | vcpu->arch.tcr = vcpu->arch.gpr[rs]; | ||
524 | kvmppc_emulate_dec(vcpu); | ||
525 | break; | ||
526 | |||
527 | case SPRN_SPRG0: | ||
528 | vcpu->arch.sprg0 = vcpu->arch.gpr[rs]; break; | ||
529 | case SPRN_SPRG1: | ||
530 | vcpu->arch.sprg1 = vcpu->arch.gpr[rs]; break; | ||
531 | case SPRN_SPRG2: | ||
532 | vcpu->arch.sprg2 = vcpu->arch.gpr[rs]; break; | ||
533 | case SPRN_SPRG3: | ||
534 | vcpu->arch.sprg3 = vcpu->arch.gpr[rs]; break; | ||
535 | |||
536 | /* Note: SPRG4-7 are user-readable. These values are | ||
537 | * loaded into the real SPRGs when resuming the | ||
538 | * guest. */ | ||
539 | case SPRN_SPRG4: | ||
540 | vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break; | ||
541 | case SPRN_SPRG5: | ||
542 | vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break; | ||
543 | case SPRN_SPRG6: | ||
544 | vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break; | ||
545 | case SPRN_SPRG7: | ||
546 | vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break; | ||
547 | |||
548 | case SPRN_IVPR: | ||
549 | vcpu->arch.ivpr = vcpu->arch.gpr[rs]; break; | ||
550 | case SPRN_IVOR0: | ||
551 | vcpu->arch.ivor[0] = vcpu->arch.gpr[rs]; break; | ||
552 | case SPRN_IVOR1: | ||
553 | vcpu->arch.ivor[1] = vcpu->arch.gpr[rs]; break; | ||
554 | case SPRN_IVOR2: | ||
555 | vcpu->arch.ivor[2] = vcpu->arch.gpr[rs]; break; | ||
556 | case SPRN_IVOR3: | ||
557 | vcpu->arch.ivor[3] = vcpu->arch.gpr[rs]; break; | ||
558 | case SPRN_IVOR4: | ||
559 | vcpu->arch.ivor[4] = vcpu->arch.gpr[rs]; break; | ||
560 | case SPRN_IVOR5: | ||
561 | vcpu->arch.ivor[5] = vcpu->arch.gpr[rs]; break; | ||
562 | case SPRN_IVOR6: | ||
563 | vcpu->arch.ivor[6] = vcpu->arch.gpr[rs]; break; | ||
564 | case SPRN_IVOR7: | ||
565 | vcpu->arch.ivor[7] = vcpu->arch.gpr[rs]; break; | ||
566 | case SPRN_IVOR8: | ||
567 | vcpu->arch.ivor[8] = vcpu->arch.gpr[rs]; break; | ||
568 | case SPRN_IVOR9: | ||
569 | vcpu->arch.ivor[9] = vcpu->arch.gpr[rs]; break; | ||
570 | case SPRN_IVOR10: | ||
571 | vcpu->arch.ivor[10] = vcpu->arch.gpr[rs]; break; | ||
572 | case SPRN_IVOR11: | ||
573 | vcpu->arch.ivor[11] = vcpu->arch.gpr[rs]; break; | ||
574 | case SPRN_IVOR12: | ||
575 | vcpu->arch.ivor[12] = vcpu->arch.gpr[rs]; break; | ||
576 | case SPRN_IVOR13: | ||
577 | vcpu->arch.ivor[13] = vcpu->arch.gpr[rs]; break; | ||
578 | case SPRN_IVOR14: | ||
579 | vcpu->arch.ivor[14] = vcpu->arch.gpr[rs]; break; | ||
580 | case SPRN_IVOR15: | ||
581 | vcpu->arch.ivor[15] = vcpu->arch.gpr[rs]; break; | ||
582 | |||
583 | default: | ||
584 | printk("mtspr: unknown spr %x\n", sprn); | ||
585 | emulated = EMULATE_FAIL; | ||
586 | break; | ||
587 | } | ||
588 | break; | ||
589 | |||
590 | case 470: /* dcbi */ | ||
591 | /* Do nothing. The guest is performing dcbi because | ||
592 | * hardware DMA is not snooped by the dcache, but | ||
593 | * emulated DMA either goes through the dcache as | ||
594 | * normal writes, or the host kernel has handled dcache | ||
595 | * coherence. */ | ||
596 | break; | ||
597 | |||
598 | case 534: /* lwbrx */ | ||
599 | rt = get_rt(inst); | ||
600 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0); | ||
601 | break; | ||
602 | |||
603 | case 566: /* tlbsync */ | ||
604 | break; | ||
605 | |||
606 | case 662: /* stwbrx */ | ||
607 | rs = get_rs(inst); | ||
608 | ra = get_ra(inst); | ||
609 | rb = get_rb(inst); | ||
610 | |||
611 | emulated = kvmppc_handle_store(run, vcpu, | ||
612 | vcpu->arch.gpr[rs], | ||
613 | 4, 0); | ||
614 | break; | ||
615 | |||
616 | case 978: /* tlbwe */ | ||
617 | emulated = kvmppc_emul_tlbwe(vcpu, inst); | ||
618 | break; | ||
619 | |||
620 | case 914: { /* tlbsx */ | ||
621 | int index; | ||
622 | unsigned int as = get_mmucr_sts(vcpu); | ||
623 | unsigned int pid = get_mmucr_stid(vcpu); | ||
624 | |||
625 | rt = get_rt(inst); | ||
626 | ra = get_ra(inst); | ||
627 | rb = get_rb(inst); | ||
628 | rc = get_rc(inst); | ||
629 | |||
630 | ea = vcpu->arch.gpr[rb]; | ||
631 | if (ra) | ||
632 | ea += vcpu->arch.gpr[ra]; | ||
633 | |||
634 | index = kvmppc_44x_tlb_index(vcpu, ea, pid, as); | ||
635 | if (rc) { | ||
636 | if (index < 0) | ||
637 | vcpu->arch.cr &= ~0x20000000; | ||
638 | else | ||
639 | vcpu->arch.cr |= 0x20000000; | ||
640 | } | ||
641 | vcpu->arch.gpr[rt] = index; | ||
642 | |||
643 | } | ||
644 | break; | ||
645 | |||
646 | case 790: /* lhbrx */ | ||
647 | rt = get_rt(inst); | ||
648 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0); | ||
649 | break; | ||
650 | |||
651 | case 918: /* sthbrx */ | ||
652 | rs = get_rs(inst); | ||
653 | ra = get_ra(inst); | ||
654 | rb = get_rb(inst); | ||
655 | |||
656 | emulated = kvmppc_handle_store(run, vcpu, | ||
657 | vcpu->arch.gpr[rs], | ||
658 | 2, 0); | ||
659 | break; | ||
660 | |||
661 | case 966: /* iccci */ | ||
662 | break; | ||
663 | |||
664 | default: | ||
665 | printk("unknown: op %d xop %d\n", get_op(inst), | ||
666 | get_xop(inst)); | ||
667 | emulated = EMULATE_FAIL; | ||
668 | break; | ||
669 | } | ||
670 | break; | ||
671 | |||
672 | case 32: /* lwz */ | ||
673 | rt = get_rt(inst); | ||
674 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); | ||
675 | break; | ||
676 | |||
677 | case 33: /* lwzu */ | ||
678 | ra = get_ra(inst); | ||
679 | rt = get_rt(inst); | ||
680 | emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); | ||
681 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
682 | break; | ||
683 | |||
684 | case 34: /* lbz */ | ||
685 | rt = get_rt(inst); | ||
686 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | ||
687 | break; | ||
688 | |||
689 | case 35: /* lbzu */ | ||
690 | ra = get_ra(inst); | ||
691 | rt = get_rt(inst); | ||
692 | emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | ||
693 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
694 | break; | ||
695 | |||
696 | case 36: /* stw */ | ||
697 | rs = get_rs(inst); | ||
698 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
699 | 4, 1); | ||
700 | break; | ||
701 | |||
702 | case 37: /* stwu */ | ||
703 | ra = get_ra(inst); | ||
704 | rs = get_rs(inst); | ||
705 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
706 | 4, 1); | ||
707 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
708 | break; | ||
709 | |||
710 | case 38: /* stb */ | ||
711 | rs = get_rs(inst); | ||
712 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
713 | 1, 1); | ||
714 | break; | ||
715 | |||
716 | case 39: /* stbu */ | ||
717 | ra = get_ra(inst); | ||
718 | rs = get_rs(inst); | ||
719 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
720 | 1, 1); | ||
721 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
722 | break; | ||
723 | |||
724 | case 40: /* lhz */ | ||
725 | rt = get_rt(inst); | ||
726 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | ||
727 | break; | ||
728 | |||
729 | case 41: /* lhzu */ | ||
730 | ra = get_ra(inst); | ||
731 | rt = get_rt(inst); | ||
732 | emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | ||
733 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
734 | break; | ||
735 | |||
736 | case 44: /* sth */ | ||
737 | rs = get_rs(inst); | ||
738 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
739 | 2, 1); | ||
740 | break; | ||
741 | |||
742 | case 45: /* sthu */ | ||
743 | ra = get_ra(inst); | ||
744 | rs = get_rs(inst); | ||
745 | emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs], | ||
746 | 2, 1); | ||
747 | vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed; | ||
748 | break; | ||
749 | |||
750 | default: | ||
751 | printk("unknown op %d\n", get_op(inst)); | ||
752 | emulated = EMULATE_FAIL; | ||
753 | break; | ||
754 | } | ||
755 | |||
756 | if (advance) | ||
757 | vcpu->arch.pc += 4; /* Advance past emulated instruction. */ | ||
758 | |||
759 | return emulated; | ||
760 | } | ||
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c new file mode 100644 index 000000000000..bad40bd2d3ac --- /dev/null +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright IBM Corp. 2007 | ||
16 | * | ||
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
18 | * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | ||
19 | */ | ||
20 | |||
21 | #include <linux/errno.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/fs.h> | ||
27 | #include <asm/cputable.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/kvm_ppc.h> | ||
30 | |||
31 | |||
32 | gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | ||
33 | { | ||
34 | return gfn; | ||
35 | } | ||
36 | |||
37 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v) | ||
38 | { | ||
39 | /* XXX implement me */ | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) | ||
44 | { | ||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | |||
49 | int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||
50 | { | ||
51 | enum emulation_result er; | ||
52 | int r; | ||
53 | |||
54 | er = kvmppc_emulate_instruction(run, vcpu); | ||
55 | switch (er) { | ||
56 | case EMULATE_DONE: | ||
57 | /* Future optimization: only reload non-volatiles if they were | ||
58 | * actually modified. */ | ||
59 | r = RESUME_GUEST_NV; | ||
60 | break; | ||
61 | case EMULATE_DO_MMIO: | ||
62 | run->exit_reason = KVM_EXIT_MMIO; | ||
63 | /* We must reload nonvolatiles because "update" load/store | ||
64 | * instructions modify register state. */ | ||
65 | /* Future optimization: only reload non-volatiles if they were | ||
66 | * actually modified. */ | ||
67 | r = RESUME_HOST_NV; | ||
68 | break; | ||
69 | case EMULATE_FAIL: | ||
70 | /* XXX Deliver Program interrupt to guest. */ | ||
71 | printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__, | ||
72 | vcpu->arch.last_inst); | ||
73 | r = RESUME_HOST; | ||
74 | break; | ||
75 | default: | ||
76 | BUG(); | ||
77 | } | ||
78 | |||
79 | return r; | ||
80 | } | ||
81 | |||
82 | void kvm_arch_hardware_enable(void *garbage) | ||
83 | { | ||
84 | } | ||
85 | |||
86 | void kvm_arch_hardware_disable(void *garbage) | ||
87 | { | ||
88 | } | ||
89 | |||
90 | int kvm_arch_hardware_setup(void) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | void kvm_arch_hardware_unsetup(void) | ||
96 | { | ||
97 | } | ||
98 | |||
99 | void kvm_arch_check_processor_compat(void *rtn) | ||
100 | { | ||
101 | int r; | ||
102 | |||
103 | if (strcmp(cur_cpu_spec->platform, "ppc440") == 0) | ||
104 | r = 0; | ||
105 | else | ||
106 | r = -ENOTSUPP; | ||
107 | |||
108 | *(int *)rtn = r; | ||
109 | } | ||
110 | |||
111 | struct kvm *kvm_arch_create_vm(void) | ||
112 | { | ||
113 | struct kvm *kvm; | ||
114 | |||
115 | kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); | ||
116 | if (!kvm) | ||
117 | return ERR_PTR(-ENOMEM); | ||
118 | |||
119 | return kvm; | ||
120 | } | ||
121 | |||
122 | static void kvmppc_free_vcpus(struct kvm *kvm) | ||
123 | { | ||
124 | unsigned int i; | ||
125 | |||
126 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { | ||
127 | if (kvm->vcpus[i]) { | ||
128 | kvm_arch_vcpu_free(kvm->vcpus[i]); | ||
129 | kvm->vcpus[i] = NULL; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | void kvm_arch_destroy_vm(struct kvm *kvm) | ||
135 | { | ||
136 | kvmppc_free_vcpus(kvm); | ||
137 | kvm_free_physmem(kvm); | ||
138 | kfree(kvm); | ||
139 | } | ||
140 | |||
141 | int kvm_dev_ioctl_check_extension(long ext) | ||
142 | { | ||
143 | int r; | ||
144 | |||
145 | switch (ext) { | ||
146 | case KVM_CAP_USER_MEMORY: | ||
147 | r = 1; | ||
148 | break; | ||
149 | default: | ||
150 | r = 0; | ||
151 | break; | ||
152 | } | ||
153 | return r; | ||
154 | |||
155 | } | ||
156 | |||
157 | long kvm_arch_dev_ioctl(struct file *filp, | ||
158 | unsigned int ioctl, unsigned long arg) | ||
159 | { | ||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | int kvm_arch_set_memory_region(struct kvm *kvm, | ||
164 | struct kvm_userspace_memory_region *mem, | ||
165 | struct kvm_memory_slot old, | ||
166 | int user_alloc) | ||
167 | { | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | ||
172 | { | ||
173 | struct kvm_vcpu *vcpu; | ||
174 | int err; | ||
175 | |||
176 | vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); | ||
177 | if (!vcpu) { | ||
178 | err = -ENOMEM; | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | err = kvm_vcpu_init(vcpu, kvm, id); | ||
183 | if (err) | ||
184 | goto free_vcpu; | ||
185 | |||
186 | return vcpu; | ||
187 | |||
188 | free_vcpu: | ||
189 | kmem_cache_free(kvm_vcpu_cache, vcpu); | ||
190 | out: | ||
191 | return ERR_PTR(err); | ||
192 | } | ||
193 | |||
194 | void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) | ||
195 | { | ||
196 | kvm_vcpu_uninit(vcpu); | ||
197 | kmem_cache_free(kvm_vcpu_cache, vcpu); | ||
198 | } | ||
199 | |||
200 | void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) | ||
201 | { | ||
202 | kvm_arch_vcpu_free(vcpu); | ||
203 | } | ||
204 | |||
205 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | ||
206 | { | ||
207 | unsigned int priority = exception_priority[BOOKE_INTERRUPT_DECREMENTER]; | ||
208 | |||
209 | return test_bit(priority, &vcpu->arch.pending_exceptions); | ||
210 | } | ||
211 | |||
212 | static void kvmppc_decrementer_func(unsigned long data) | ||
213 | { | ||
214 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; | ||
215 | |||
216 | kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_DECREMENTER); | ||
217 | } | ||
218 | |||
219 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | ||
220 | { | ||
221 | setup_timer(&vcpu->arch.dec_timer, kvmppc_decrementer_func, | ||
222 | (unsigned long)vcpu); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | ||
228 | { | ||
229 | } | ||
230 | |||
231 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
232 | { | ||
233 | } | ||
234 | |||
235 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | ||
236 | { | ||
237 | } | ||
238 | |||
239 | void decache_vcpus_on_cpu(int cpu) | ||
240 | { | ||
241 | } | ||
242 | |||
243 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | ||
244 | struct kvm_debug_guest *dbg) | ||
245 | { | ||
246 | return -ENOTSUPP; | ||
247 | } | ||
248 | |||
249 | static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, | ||
250 | struct kvm_run *run) | ||
251 | { | ||
252 | u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr]; | ||
253 | *gpr = run->dcr.data; | ||
254 | } | ||
255 | |||
256 | static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, | ||
257 | struct kvm_run *run) | ||
258 | { | ||
259 | u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr]; | ||
260 | |||
261 | if (run->mmio.len > sizeof(*gpr)) { | ||
262 | printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | if (vcpu->arch.mmio_is_bigendian) { | ||
267 | switch (run->mmio.len) { | ||
268 | case 4: *gpr = *(u32 *)run->mmio.data; break; | ||
269 | case 2: *gpr = *(u16 *)run->mmio.data; break; | ||
270 | case 1: *gpr = *(u8 *)run->mmio.data; break; | ||
271 | } | ||
272 | } else { | ||
273 | /* Convert BE data from userland back to LE. */ | ||
274 | switch (run->mmio.len) { | ||
275 | case 4: *gpr = ld_le32((u32 *)run->mmio.data); break; | ||
276 | case 2: *gpr = ld_le16((u16 *)run->mmio.data); break; | ||
277 | case 1: *gpr = *(u8 *)run->mmio.data; break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
283 | unsigned int rt, unsigned int bytes, int is_bigendian) | ||
284 | { | ||
285 | if (bytes > sizeof(run->mmio.data)) { | ||
286 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, | ||
287 | run->mmio.len); | ||
288 | } | ||
289 | |||
290 | run->mmio.phys_addr = vcpu->arch.paddr_accessed; | ||
291 | run->mmio.len = bytes; | ||
292 | run->mmio.is_write = 0; | ||
293 | |||
294 | vcpu->arch.io_gpr = rt; | ||
295 | vcpu->arch.mmio_is_bigendian = is_bigendian; | ||
296 | vcpu->mmio_needed = 1; | ||
297 | vcpu->mmio_is_write = 0; | ||
298 | |||
299 | return EMULATE_DO_MMIO; | ||
300 | } | ||
301 | |||
302 | int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
303 | u32 val, unsigned int bytes, int is_bigendian) | ||
304 | { | ||
305 | void *data = run->mmio.data; | ||
306 | |||
307 | if (bytes > sizeof(run->mmio.data)) { | ||
308 | printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, | ||
309 | run->mmio.len); | ||
310 | } | ||
311 | |||
312 | run->mmio.phys_addr = vcpu->arch.paddr_accessed; | ||
313 | run->mmio.len = bytes; | ||
314 | run->mmio.is_write = 1; | ||
315 | vcpu->mmio_needed = 1; | ||
316 | vcpu->mmio_is_write = 1; | ||
317 | |||
318 | /* Store the value at the lowest bytes in 'data'. */ | ||
319 | if (is_bigendian) { | ||
320 | switch (bytes) { | ||
321 | case 4: *(u32 *)data = val; break; | ||
322 | case 2: *(u16 *)data = val; break; | ||
323 | case 1: *(u8 *)data = val; break; | ||
324 | } | ||
325 | } else { | ||
326 | /* Store LE value into 'data'. */ | ||
327 | switch (bytes) { | ||
328 | case 4: st_le32(data, val); break; | ||
329 | case 2: st_le16(data, val); break; | ||
330 | case 1: *(u8 *)data = val; break; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | return EMULATE_DO_MMIO; | ||
335 | } | ||
336 | |||
337 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
338 | { | ||
339 | int r; | ||
340 | sigset_t sigsaved; | ||
341 | |||
342 | if (vcpu->sigset_active) | ||
343 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); | ||
344 | |||
345 | if (vcpu->mmio_needed) { | ||
346 | if (!vcpu->mmio_is_write) | ||
347 | kvmppc_complete_mmio_load(vcpu, run); | ||
348 | vcpu->mmio_needed = 0; | ||
349 | } else if (vcpu->arch.dcr_needed) { | ||
350 | if (!vcpu->arch.dcr_is_write) | ||
351 | kvmppc_complete_dcr_load(vcpu, run); | ||
352 | vcpu->arch.dcr_needed = 0; | ||
353 | } | ||
354 | |||
355 | kvmppc_check_and_deliver_interrupts(vcpu); | ||
356 | |||
357 | local_irq_disable(); | ||
358 | kvm_guest_enter(); | ||
359 | r = __kvmppc_vcpu_run(run, vcpu); | ||
360 | kvm_guest_exit(); | ||
361 | local_irq_enable(); | ||
362 | |||
363 | if (vcpu->sigset_active) | ||
364 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
365 | |||
366 | return r; | ||
367 | } | ||
368 | |||
369 | int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) | ||
370 | { | ||
371 | kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_EXTERNAL); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | ||
376 | struct kvm_mp_state *mp_state) | ||
377 | { | ||
378 | return -EINVAL; | ||
379 | } | ||
380 | |||
381 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | ||
382 | struct kvm_mp_state *mp_state) | ||
383 | { | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | |||
387 | long kvm_arch_vcpu_ioctl(struct file *filp, | ||
388 | unsigned int ioctl, unsigned long arg) | ||
389 | { | ||
390 | struct kvm_vcpu *vcpu = filp->private_data; | ||
391 | void __user *argp = (void __user *)arg; | ||
392 | long r; | ||
393 | |||
394 | switch (ioctl) { | ||
395 | case KVM_INTERRUPT: { | ||
396 | struct kvm_interrupt irq; | ||
397 | r = -EFAULT; | ||
398 | if (copy_from_user(&irq, argp, sizeof(irq))) | ||
399 | goto out; | ||
400 | r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); | ||
401 | break; | ||
402 | } | ||
403 | default: | ||
404 | r = -EINVAL; | ||
405 | } | ||
406 | |||
407 | out: | ||
408 | return r; | ||
409 | } | ||
410 | |||
411 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||
412 | { | ||
413 | return -ENOTSUPP; | ||
414 | } | ||
415 | |||
416 | long kvm_arch_vm_ioctl(struct file *filp, | ||
417 | unsigned int ioctl, unsigned long arg) | ||
418 | { | ||
419 | long r; | ||
420 | |||
421 | switch (ioctl) { | ||
422 | default: | ||
423 | r = -EINVAL; | ||
424 | } | ||
425 | |||
426 | return r; | ||
427 | } | ||
428 | |||
429 | int kvm_arch_init(void *opaque) | ||
430 | { | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | void kvm_arch_exit(void) | ||
435 | { | ||
436 | } | ||
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 5ccb579b81e4..f67e118116fa 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -110,15 +110,6 @@ EXPORT_SYMBOL(phys_mem_access_prot); | |||
110 | 110 | ||
111 | #ifdef CONFIG_MEMORY_HOTPLUG | 111 | #ifdef CONFIG_MEMORY_HOTPLUG |
112 | 112 | ||
113 | void online_page(struct page *page) | ||
114 | { | ||
115 | ClearPageReserved(page); | ||
116 | init_page_count(page); | ||
117 | __free_page(page); | ||
118 | totalram_pages++; | ||
119 | num_physpages++; | ||
120 | } | ||
121 | |||
122 | #ifdef CONFIG_NUMA | 113 | #ifdef CONFIG_NUMA |
123 | int memory_add_physaddr_to_nid(u64 start) | 114 | int memory_add_physaddr_to_nid(u64 start) |
124 | { | 115 | { |
@@ -163,19 +154,35 @@ out: | |||
163 | 154 | ||
164 | /* | 155 | /* |
165 | * walk_memory_resource() needs to make sure there is no holes in a given | 156 | * walk_memory_resource() needs to make sure there is no holes in a given |
166 | * memory range. On PPC64, since this range comes from /sysfs, the range | 157 | * memory range. PPC64 does not maintain the memory layout in /proc/iomem. |
167 | * is guaranteed to be valid, non-overlapping and can not contain any | 158 | * Instead it maintains it in lmb.memory structures. Walk through the |
168 | * holes. By the time we get here (memory add or remove), /proc/device-tree | 159 | * memory regions, find holes and callback for contiguous regions. |
169 | * is updated and correct. Only reason we need to check against device-tree | ||
170 | * would be if we allow user-land to specify a memory range through a | ||
171 | * system call/ioctl etc. instead of doing offline/online through /sysfs. | ||
172 | */ | 160 | */ |
173 | int | 161 | int |
174 | walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, | 162 | walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, |
175 | int (*func)(unsigned long, unsigned long, void *)) | 163 | int (*func)(unsigned long, unsigned long, void *)) |
176 | { | 164 | { |
177 | return (*func)(start_pfn, nr_pages, arg); | 165 | struct lmb_property res; |
166 | unsigned long pfn, len; | ||
167 | u64 end; | ||
168 | int ret = -1; | ||
169 | |||
170 | res.base = (u64) start_pfn << PAGE_SHIFT; | ||
171 | res.size = (u64) nr_pages << PAGE_SHIFT; | ||
172 | |||
173 | end = res.base + res.size - 1; | ||
174 | while ((res.base < end) && (lmb_find(&res) >= 0)) { | ||
175 | pfn = (unsigned long)(res.base >> PAGE_SHIFT); | ||
176 | len = (unsigned long)(res.size >> PAGE_SHIFT); | ||
177 | ret = (*func)(pfn, len, arg); | ||
178 | if (ret) | ||
179 | break; | ||
180 | res.base += (res.size + 1); | ||
181 | res.size = (end - res.base + 1); | ||
182 | } | ||
183 | return ret; | ||
178 | } | 184 | } |
185 | EXPORT_SYMBOL_GPL(walk_memory_resource); | ||
179 | 186 | ||
180 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 187 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
181 | 188 | ||
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 7442c58d44f5..053f49a1dcae 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -8,6 +8,7 @@ config MPC8641_HPCN | |||
8 | select PPC_I8259 | 8 | select PPC_I8259 |
9 | select DEFAULT_UIMAGE | 9 | select DEFAULT_UIMAGE |
10 | select FSL_ULI1575 | 10 | select FSL_ULI1575 |
11 | select HAS_RAPIDIO | ||
11 | help | 12 | help |
12 | This option enables support for the MPC8641 HPCN board. | 13 | This option enables support for the MPC8641 HPCN board. |
13 | 14 | ||
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 18b8ebe930d5..5e1e8cf14e75 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c | |||
@@ -3,11 +3,12 @@ | |||
3 | * | 3 | * |
4 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> | 4 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> |
5 | * Recode: Jason Jin <jason.jin@freescale.com> | 5 | * Recode: Jason Jin <jason.jin@freescale.com> |
6 | * York Sun <yorksun@freescale.com> | ||
6 | * | 7 | * |
7 | * Rewrite the interrupt routing. remove the 8259PIC support, | 8 | * Rewrite the interrupt routing. remove the 8259PIC support, |
8 | * All the integrated device in ULI use sideband interrupt. | 9 | * All the integrated device in ULI use sideband interrupt. |
9 | * | 10 | * |
10 | * Copyright 2007 Freescale Semiconductor Inc. | 11 | * Copyright 2008 Freescale Semiconductor Inc. |
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 13 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 14 | * under the terms of the GNU General Public License as published by the |
@@ -38,6 +39,8 @@ | |||
38 | #include <sysdev/fsl_pci.h> | 39 | #include <sysdev/fsl_pci.h> |
39 | #include <sysdev/fsl_soc.h> | 40 | #include <sysdev/fsl_soc.h> |
40 | 41 | ||
42 | static unsigned char *pixis_bdcfg0, *pixis_arch; | ||
43 | |||
41 | static struct of_device_id __initdata mpc8610_ids[] = { | 44 | static struct of_device_id __initdata mpc8610_ids[] = { |
42 | { .compatible = "fsl,mpc8610-immr", }, | 45 | { .compatible = "fsl,mpc8610-immr", }, |
43 | {} | 46 | {} |
@@ -52,8 +55,7 @@ static int __init mpc8610_declare_of_platform_devices(void) | |||
52 | } | 55 | } |
53 | machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); | 56 | machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); |
54 | 57 | ||
55 | static void __init | 58 | static void __init mpc86xx_hpcd_init_irq(void) |
56 | mpc86xx_hpcd_init_irq(void) | ||
57 | { | 59 | { |
58 | struct mpic *mpic1; | 60 | struct mpic *mpic1; |
59 | struct device_node *np; | 61 | struct device_node *np; |
@@ -161,12 +163,159 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); | |||
161 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288); | 163 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288); |
162 | #endif /* CONFIG_PCI */ | 164 | #endif /* CONFIG_PCI */ |
163 | 165 | ||
164 | static void __init | 166 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) |
165 | mpc86xx_hpcd_setup_arch(void) | 167 | |
168 | static u32 get_busfreq(void) | ||
166 | { | 169 | { |
167 | #ifdef CONFIG_PCI | 170 | struct device_node *node; |
168 | struct device_node *np; | 171 | |
172 | u32 fs_busfreq = 0; | ||
173 | node = of_find_node_by_type(NULL, "cpu"); | ||
174 | if (node) { | ||
175 | unsigned int size; | ||
176 | const unsigned int *prop = | ||
177 | of_get_property(node, "bus-frequency", &size); | ||
178 | if (prop) | ||
179 | fs_busfreq = *prop; | ||
180 | of_node_put(node); | ||
181 | }; | ||
182 | return fs_busfreq; | ||
183 | } | ||
184 | |||
185 | unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, | ||
186 | int monitor_port) | ||
187 | { | ||
188 | static const unsigned long pixelformat[][3] = { | ||
189 | {0x88882317, 0x88083218, 0x65052119}, | ||
190 | {0x88883316, 0x88082219, 0x65053118}, | ||
191 | }; | ||
192 | unsigned int pix_fmt, arch_monitor; | ||
193 | |||
194 | arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; | ||
195 | /* DVI port for board version 0x01 */ | ||
196 | |||
197 | if (bits_per_pixel == 32) | ||
198 | pix_fmt = pixelformat[arch_monitor][0]; | ||
199 | else if (bits_per_pixel == 24) | ||
200 | pix_fmt = pixelformat[arch_monitor][1]; | ||
201 | else if (bits_per_pixel == 16) | ||
202 | pix_fmt = pixelformat[arch_monitor][2]; | ||
203 | else | ||
204 | pix_fmt = pixelformat[1][0]; | ||
205 | |||
206 | return pix_fmt; | ||
207 | } | ||
208 | |||
209 | void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) | ||
210 | { | ||
211 | int i; | ||
212 | if (monitor_port == 2) { /* dual link LVDS */ | ||
213 | for (i = 0; i < 256*3; i++) | ||
214 | gamma_table_base[i] = (gamma_table_base[i] << 2) | | ||
215 | ((gamma_table_base[i] >> 6) & 0x03); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void mpc8610hpcd_set_monitor_port(int monitor_port) | ||
220 | { | ||
221 | static const u8 bdcfg[] = {0xBD, 0xB5, 0xA5}; | ||
222 | if (monitor_port < 3) | ||
223 | *pixis_bdcfg0 = bdcfg[monitor_port]; | ||
224 | } | ||
225 | |||
226 | void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) | ||
227 | { | ||
228 | u32 __iomem *clkdvdr; | ||
229 | u32 temp; | ||
230 | /* variables for pixel clock calcs */ | ||
231 | ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock; | ||
232 | ulong pixval; | ||
233 | long err; | ||
234 | int i; | ||
235 | |||
236 | clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32)); | ||
237 | if (!clkdvdr) { | ||
238 | printk(KERN_ERR "Err: can't map clock divider register!\n"); | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | /* Pixel Clock configuration */ | ||
243 | pr_debug("DIU: Bus Frequency = %d\n", get_busfreq()); | ||
244 | speed_ccb = get_busfreq(); | ||
245 | |||
246 | /* Calculate the pixel clock with the smallest error */ | ||
247 | /* calculate the following in steps to avoid overflow */ | ||
248 | pr_debug("DIU pixclock in ps - %d\n", pixclock); | ||
249 | temp = 1000000000/pixclock; | ||
250 | temp *= 1000; | ||
251 | pixclock = temp; | ||
252 | pr_debug("DIU pixclock freq - %u\n", pixclock); | ||
253 | |||
254 | temp = pixclock * 5 / 100; | ||
255 | pr_debug("deviation = %d\n", temp); | ||
256 | minpixclock = pixclock - temp; | ||
257 | maxpixclock = pixclock + temp; | ||
258 | pr_debug("DIU minpixclock - %lu\n", minpixclock); | ||
259 | pr_debug("DIU maxpixclock - %lu\n", maxpixclock); | ||
260 | pixval = speed_ccb/pixclock; | ||
261 | pr_debug("DIU pixval = %lu\n", pixval); | ||
262 | |||
263 | err = 100000000; | ||
264 | bestval = pixval; | ||
265 | pr_debug("DIU bestval = %lu\n", bestval); | ||
266 | |||
267 | bestfreq = 0; | ||
268 | for (i = -1; i <= 1; i++) { | ||
269 | temp = speed_ccb / ((pixval+i) + 1); | ||
270 | pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n", | ||
271 | i, pixval, temp); | ||
272 | if ((temp < minpixclock) || (temp > maxpixclock)) | ||
273 | pr_debug("DIU exceeds monitor range (%lu to %lu)\n", | ||
274 | minpixclock, maxpixclock); | ||
275 | else if (abs(temp - pixclock) < err) { | ||
276 | pr_debug("Entered the else if block %d\n", i); | ||
277 | err = abs(temp - pixclock); | ||
278 | bestval = pixval+i; | ||
279 | bestfreq = temp; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | pr_debug("DIU chose = %lx\n", bestval); | ||
284 | pr_debug("DIU error = %ld\n NomPixClk ", err); | ||
285 | pr_debug("DIU: Best Freq = %lx\n", bestfreq); | ||
286 | /* Modify PXCLK in GUTS CLKDVDR */ | ||
287 | pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr)); | ||
288 | temp = (*clkdvdr) & 0x2000FFFF; | ||
289 | *clkdvdr = temp; /* turn off clock */ | ||
290 | *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16); | ||
291 | pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr)); | ||
292 | iounmap(clkdvdr); | ||
293 | } | ||
294 | |||
295 | ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) | ||
296 | { | ||
297 | return snprintf(buf, PAGE_SIZE, | ||
298 | "%c0 - DVI\n" | ||
299 | "%c1 - Single link LVDS\n" | ||
300 | "%c2 - Dual link LVDS\n", | ||
301 | monitor_port == 0 ? '*' : ' ', | ||
302 | monitor_port == 1 ? '*' : ' ', | ||
303 | monitor_port == 2 ? '*' : ' '); | ||
304 | } | ||
305 | |||
306 | int mpc8610hpcd_set_sysfs_monitor_port(int val) | ||
307 | { | ||
308 | return val < 3 ? val : 0; | ||
309 | } | ||
310 | |||
169 | #endif | 311 | #endif |
312 | |||
313 | static void __init mpc86xx_hpcd_setup_arch(void) | ||
314 | { | ||
315 | struct resource r; | ||
316 | struct device_node *np; | ||
317 | unsigned char *pixis; | ||
318 | |||
170 | if (ppc_md.progress) | 319 | if (ppc_md.progress) |
171 | ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); | 320 | ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); |
172 | 321 | ||
@@ -183,6 +332,30 @@ mpc86xx_hpcd_setup_arch(void) | |||
183 | } | 332 | } |
184 | } | 333 | } |
185 | #endif | 334 | #endif |
335 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) | ||
336 | preallocate_diu_videomemory(); | ||
337 | diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; | ||
338 | diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; | ||
339 | diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; | ||
340 | diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; | ||
341 | diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port; | ||
342 | diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; | ||
343 | #endif | ||
344 | |||
345 | np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); | ||
346 | if (np) { | ||
347 | of_address_to_resource(np, 0, &r); | ||
348 | of_node_put(np); | ||
349 | pixis = ioremap(r.start, 32); | ||
350 | if (!pixis) { | ||
351 | printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); | ||
352 | return; | ||
353 | } | ||
354 | pixis_bdcfg0 = pixis + 8; | ||
355 | pixis_arch = pixis + 1; | ||
356 | } else | ||
357 | printk(KERN_ERR "Err: " | ||
358 | "can't find device node 'fsl,fpga-pixis'\n"); | ||
186 | 359 | ||
187 | printk("MPC86xx HPCD board from Freescale Semiconductor\n"); | 360 | printk("MPC86xx HPCD board from Freescale Semiconductor\n"); |
188 | } | 361 | } |
@@ -200,8 +373,7 @@ static int __init mpc86xx_hpcd_probe(void) | |||
200 | return 0; | 373 | return 0; |
201 | } | 374 | } |
202 | 375 | ||
203 | static long __init | 376 | static long __init mpc86xx_time_init(void) |
204 | mpc86xx_time_init(void) | ||
205 | { | 377 | { |
206 | unsigned int temp; | 378 | unsigned int temp; |
207 | 379 | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index f947f555fd46..f13704aabbea 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | |||
@@ -221,6 +221,7 @@ mpc86xx_time_init(void) | |||
221 | 221 | ||
222 | static __initdata struct of_device_id of_bus_ids[] = { | 222 | static __initdata struct of_device_id of_bus_ids[] = { |
223 | { .compatible = "simple-bus", }, | 223 | { .compatible = "simple-bus", }, |
224 | { .compatible = "fsl,rapidio-delta", }, | ||
224 | {}, | 225 | {}, |
225 | }; | 226 | }; |
226 | 227 | ||
diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c index ab24d94baab6..31da84c458d2 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c | |||
@@ -36,8 +36,8 @@ | |||
36 | #include "celleb_scc.h" | 36 | #include "celleb_scc.h" |
37 | #include "celleb_pci.h" | 37 | #include "celleb_pci.h" |
38 | 38 | ||
39 | #define PEX_IN(base, off) in_be32((void *)(base) + (off)) | 39 | #define PEX_IN(base, off) in_be32((void __iomem *)(base) + (off)) |
40 | #define PEX_OUT(base, off, data) out_be32((void *)(base) + (off), (data)) | 40 | #define PEX_OUT(base, off, data) out_be32((void __iomem *)(base) + (off), (data)) |
41 | 41 | ||
42 | static void scc_pciex_io_flush(struct iowa_bus *bus) | 42 | static void scc_pciex_io_flush(struct iowa_bus *bus) |
43 | { | 43 | { |
@@ -304,7 +304,7 @@ static int __init scc_pciex_iowa_init(struct iowa_bus *bus, void *data) | |||
304 | ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT) | 304 | ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT) |
305 | #define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size)) | 305 | #define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size)) |
306 | 306 | ||
307 | static uint32_t config_read_pciex_dev(unsigned int *base, | 307 | static uint32_t config_read_pciex_dev(unsigned int __iomem *base, |
308 | uint64_t bus_no, uint64_t dev_no, uint64_t func_no, | 308 | uint64_t bus_no, uint64_t dev_no, uint64_t func_no, |
309 | uint64_t off, uint64_t size) | 309 | uint64_t off, uint64_t size) |
310 | { | 310 | { |
@@ -320,7 +320,7 @@ static uint32_t config_read_pciex_dev(unsigned int *base, | |||
320 | return ret; | 320 | return ret; |
321 | } | 321 | } |
322 | 322 | ||
323 | static void config_write_pciex_dev(unsigned int *base, uint64_t bus_no, | 323 | static void config_write_pciex_dev(unsigned int __iomem *base, uint64_t bus_no, |
324 | uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size, | 324 | uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size, |
325 | uint32_t data) | 325 | uint32_t data) |
326 | { | 326 | { |
@@ -338,7 +338,7 @@ static void config_write_pciex_dev(unsigned int *base, uint64_t bus_no, | |||
338 | ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT) | 338 | ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT) |
339 | #define MK_PEXCADRS(cmd, addr, size) \ | 339 | #define MK_PEXCADRS(cmd, addr, size) \ |
340 | ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3)) | 340 | ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3)) |
341 | static uint32_t config_read_pciex_rc(unsigned int *base, | 341 | static uint32_t config_read_pciex_rc(unsigned int __iomem *base, |
342 | uint32_t where, uint32_t size) | 342 | uint32_t where, uint32_t size) |
343 | { | 343 | { |
344 | PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size)); | 344 | PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size)); |
@@ -346,7 +346,7 @@ static uint32_t config_read_pciex_rc(unsigned int *base, | |||
346 | >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1); | 346 | >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1); |
347 | } | 347 | } |
348 | 348 | ||
349 | static void config_write_pciex_rc(unsigned int *base, uint32_t where, | 349 | static void config_write_pciex_rc(unsigned int __iomem *base, uint32_t where, |
350 | uint32_t size, uint32_t val) | 350 | uint32_t size, uint32_t val) |
351 | { | 351 | { |
352 | uint32_t data; | 352 | uint32_t data; |
@@ -410,7 +410,7 @@ static struct pci_ops scc_pciex_pci_ops = { | |||
410 | scc_pciex_write_config, | 410 | scc_pciex_write_config, |
411 | }; | 411 | }; |
412 | 412 | ||
413 | static void pciex_clear_intr_all(unsigned int *base) | 413 | static void pciex_clear_intr_all(unsigned int __iomem *base) |
414 | { | 414 | { |
415 | PEX_OUT(base, PEXAERRSTS, 0xffffffff); | 415 | PEX_OUT(base, PEXAERRSTS, 0xffffffff); |
416 | PEX_OUT(base, PEXPRERRSTS, 0xffffffff); | 416 | PEX_OUT(base, PEXPRERRSTS, 0xffffffff); |
@@ -427,7 +427,7 @@ static void pciex_disable_intr_all(unsigned int *base) | |||
427 | } | 427 | } |
428 | #endif | 428 | #endif |
429 | 429 | ||
430 | static void pciex_enable_intr_all(unsigned int *base) | 430 | static void pciex_enable_intr_all(unsigned int __iomem *base) |
431 | { | 431 | { |
432 | PEX_OUT(base, PEXINTMASK, 0x0000e7f1); | 432 | PEX_OUT(base, PEXINTMASK, 0x0000e7f1); |
433 | PEX_OUT(base, PEXAERRMASK, 0x03ff01ff); | 433 | PEX_OUT(base, PEXAERRMASK, 0x03ff01ff); |
@@ -435,7 +435,7 @@ static void pciex_enable_intr_all(unsigned int *base) | |||
435 | PEX_OUT(base, PEXVDMASK, 0x00000001); | 435 | PEX_OUT(base, PEXVDMASK, 0x00000001); |
436 | } | 436 | } |
437 | 437 | ||
438 | static void pciex_check_status(unsigned int *base) | 438 | static void pciex_check_status(unsigned int __iomem *base) |
439 | { | 439 | { |
440 | uint32_t err = 0; | 440 | uint32_t err = 0; |
441 | uint32_t intsts, aerr, prerr, rcvcp, lenerr; | 441 | uint32_t intsts, aerr, prerr, rcvcp, lenerr; |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 00528ef84ad2..45dcd2693502 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -1063,10 +1063,9 @@ int __init spu_sched_init(void) | |||
1063 | 1063 | ||
1064 | mod_timer(&spuloadavg_timer, 0); | 1064 | mod_timer(&spuloadavg_timer, 0); |
1065 | 1065 | ||
1066 | entry = create_proc_entry("spu_loadavg", 0, NULL); | 1066 | entry = proc_create("spu_loadavg", 0, NULL, &spu_loadavg_fops); |
1067 | if (!entry) | 1067 | if (!entry) |
1068 | goto out_stop_kthread; | 1068 | goto out_stop_kthread; |
1069 | entry->proc_fops = &spu_loadavg_fops; | ||
1070 | 1069 | ||
1071 | pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n", | 1070 | pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n", |
1072 | SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE); | 1071 | SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE); |
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c index 79aa773f3c99..aea5286f1245 100644 --- a/arch/powerpc/platforms/cell/spufs/sputrace.c +++ b/arch/powerpc/platforms/cell/spufs/sputrace.c | |||
@@ -201,10 +201,9 @@ static int __init sputrace_init(void) | |||
201 | if (!sputrace_log) | 201 | if (!sputrace_log) |
202 | goto out; | 202 | goto out; |
203 | 203 | ||
204 | entry = create_proc_entry("sputrace", S_IRUSR, NULL); | 204 | entry = proc_create("sputrace", S_IRUSR, NULL, &sputrace_fops); |
205 | if (!entry) | 205 | if (!entry) |
206 | goto out_free_log; | 206 | goto out_free_log; |
207 | entry->proc_fops = &sputrace_fops; | ||
208 | 207 | ||
209 | for (i = 0; i < ARRAY_SIZE(spu_probes); i++) { | 208 | for (i = 0; i < ARRAY_SIZE(spu_probes); i++) { |
210 | struct spu_probe *p = &spu_probes[i]; | 209 | struct spu_probe *p = &spu_probes[i]; |
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index e5b40e3e0082..b0f8a857ec02 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c | |||
@@ -330,15 +330,11 @@ static const struct file_operations proc_lpevents_operations = { | |||
330 | 330 | ||
331 | static int __init proc_lpevents_init(void) | 331 | static int __init proc_lpevents_init(void) |
332 | { | 332 | { |
333 | struct proc_dir_entry *e; | ||
334 | |||
335 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 333 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
336 | return 0; | 334 | return 0; |
337 | 335 | ||
338 | e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL); | 336 | proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL, |
339 | if (e) | 337 | &proc_lpevents_operations); |
340 | e->proc_fops = &proc_lpevents_operations; | ||
341 | |||
342 | return 0; | 338 | return 0; |
343 | } | 339 | } |
344 | __initcall(proc_lpevents_init); | 340 | __initcall(proc_lpevents_init); |
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index c0f2433bc16e..1dc7295746da 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c | |||
@@ -1255,11 +1255,11 @@ static int __init mf_proc_init(void) | |||
1255 | if (i == 3) /* no vmlinux entry for 'D' */ | 1255 | if (i == 3) /* no vmlinux entry for 'D' */ |
1256 | continue; | 1256 | continue; |
1257 | 1257 | ||
1258 | ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); | 1258 | ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf, |
1259 | &proc_vmlinux_operations, | ||
1260 | (void *)(long)i); | ||
1259 | if (!ent) | 1261 | if (!ent) |
1260 | return 1; | 1262 | return 1; |
1261 | ent->data = (void *)(long)i; | ||
1262 | ent->proc_fops = &proc_vmlinux_operations; | ||
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); | 1265 | ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); |
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c index f2cde4180204..91f4c6cd4b99 100644 --- a/arch/powerpc/platforms/iseries/proc.c +++ b/arch/powerpc/platforms/iseries/proc.c | |||
@@ -110,15 +110,11 @@ static const struct file_operations proc_titantod_operations = { | |||
110 | 110 | ||
111 | static int __init iseries_proc_init(void) | 111 | static int __init iseries_proc_init(void) |
112 | { | 112 | { |
113 | struct proc_dir_entry *e; | ||
114 | |||
115 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 113 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
116 | return 0; | 114 | return 0; |
117 | 115 | ||
118 | e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL); | 116 | proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL, |
119 | if (e) | 117 | &proc_titantod_operations); |
120 | e->proc_fops = &proc_titantod_operations; | ||
121 | |||
122 | return 0; | 118 | return 0; |
123 | } | 119 | } |
124 | __initcall(iseries_proc_init); | 120 | __initcall(iseries_proc_init); |
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index df23331eb25c..49ff4dc422b7 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c | |||
@@ -180,15 +180,10 @@ static const struct file_operations proc_viopath_operations = { | |||
180 | 180 | ||
181 | static int __init vio_proc_init(void) | 181 | static int __init vio_proc_init(void) |
182 | { | 182 | { |
183 | struct proc_dir_entry *e; | ||
184 | |||
185 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 183 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
186 | return 0; | 184 | return 0; |
187 | 185 | ||
188 | e = create_proc_entry("iSeries/config", 0, NULL); | 186 | proc_create("iSeries/config", 0, NULL, &proc_viopath_operations); |
189 | if (e) | ||
190 | e->proc_fops = &proc_viopath_operations; | ||
191 | |||
192 | return 0; | 187 | return 0; |
193 | } | 188 | } |
194 | __initcall(vio_proc_init); | 189 | __initcall(vio_proc_init); |
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 78093d7f97af..4d72c8f72159 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile | |||
@@ -6,7 +6,10 @@ obj-y += pic.o setup.o time.o feature.o pci.o \ | |||
6 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o | 6 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o |
7 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o | 7 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o |
8 | obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o | 8 | obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o |
9 | obj-$(CONFIG_NVRAM) += nvram.o | 9 | # CONFIG_NVRAM is an arch. independant tristate symbol, for pmac32 we really |
10 | # need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really | ||
11 | # CONFIG_NVRAM=y | ||
12 | obj-$(CONFIG_NVRAM:m=y) += nvram.o | ||
10 | # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff | 13 | # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff |
11 | obj-$(CONFIG_PPC64) += nvram.o | 14 | obj-$(CONFIG_PPC64) += nvram.o |
12 | obj-$(CONFIG_PPC32) += bootx_init.o | 15 | obj-$(CONFIG_PPC32) += bootx_init.o |
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index bf44c5441a36..00bd0166d07f 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -337,7 +337,8 @@ static void __init pmac_setup_arch(void) | |||
337 | find_via_pmu(); | 337 | find_via_pmu(); |
338 | smu_init(); | 338 | smu_init(); |
339 | 339 | ||
340 | #if defined(CONFIG_NVRAM) || defined(CONFIG_PPC64) | 340 | #if defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) || \ |
341 | defined(CONFIG_PPC64) | ||
341 | pmac_nvram_init(); | 342 | pmac_nvram_init(); |
342 | #endif | 343 | #endif |
343 | 344 | ||
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index bd2593ed28dd..554c6e42ef2a 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_PCI) += pci.o pci_dlpar.o | |||
18 | obj-$(CONFIG_PCI_MSI) += msi.o | 18 | obj-$(CONFIG_PCI_MSI) += msi.o |
19 | 19 | ||
20 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o | 20 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o |
21 | obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o | ||
21 | 22 | ||
22 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 23 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
23 | obj-$(CONFIG_HVCS) += hvcserver.o | 24 | obj-$(CONFIG_HVCS) += hvcserver.o |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index a3fd56b186e6..6f544ba4b37f 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -1259,14 +1259,8 @@ static const struct file_operations proc_eeh_operations = { | |||
1259 | 1259 | ||
1260 | static int __init eeh_init_proc(void) | 1260 | static int __init eeh_init_proc(void) |
1261 | { | 1261 | { |
1262 | struct proc_dir_entry *e; | 1262 | if (machine_is(pseries)) |
1263 | 1263 | proc_create("ppc64/eeh", 0, NULL, &proc_eeh_operations); | |
1264 | if (machine_is(pseries)) { | ||
1265 | e = create_proc_entry("ppc64/eeh", 0, NULL); | ||
1266 | if (e) | ||
1267 | e->proc_fops = &proc_eeh_operations; | ||
1268 | } | ||
1269 | |||
1270 | return 0; | 1264 | return 0; |
1271 | } | 1265 | } |
1272 | __initcall(eeh_init_proc); | 1266 | __initcall(eeh_init_proc); |
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c new file mode 100644 index 000000000000..3c5727dd5aa5 --- /dev/null +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * pseries Memory Hotplug infrastructure. | ||
3 | * | ||
4 | * Copyright (C) 2008 Badari Pulavarty, IBM Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/of.h> | ||
13 | #include <linux/lmb.h> | ||
14 | #include <asm/firmware.h> | ||
15 | #include <asm/machdep.h> | ||
16 | #include <asm/pSeries_reconfig.h> | ||
17 | |||
18 | static int pseries_remove_memory(struct device_node *np) | ||
19 | { | ||
20 | const char *type; | ||
21 | const unsigned int *my_index; | ||
22 | const unsigned int *regs; | ||
23 | u64 start_pfn, start; | ||
24 | struct zone *zone; | ||
25 | int ret = -EINVAL; | ||
26 | |||
27 | /* | ||
28 | * Check to see if we are actually removing memory | ||
29 | */ | ||
30 | type = of_get_property(np, "device_type", NULL); | ||
31 | if (type == NULL || strcmp(type, "memory") != 0) | ||
32 | return 0; | ||
33 | |||
34 | /* | ||
35 | * Find the memory index and size of the removing section | ||
36 | */ | ||
37 | my_index = of_get_property(np, "ibm,my-drc-index", NULL); | ||
38 | if (!my_index) | ||
39 | return ret; | ||
40 | |||
41 | regs = of_get_property(np, "reg", NULL); | ||
42 | if (!regs) | ||
43 | return ret; | ||
44 | |||
45 | start_pfn = section_nr_to_pfn(*my_index & 0xffff); | ||
46 | zone = page_zone(pfn_to_page(start_pfn)); | ||
47 | |||
48 | /* | ||
49 | * Remove section mappings and sysfs entries for the | ||
50 | * section of the memory we are removing. | ||
51 | * | ||
52 | * NOTE: Ideally, this should be done in generic code like | ||
53 | * remove_memory(). But remove_memory() gets called by writing | ||
54 | * to sysfs "state" file and we can't remove sysfs entries | ||
55 | * while writing to it. So we have to defer it to here. | ||
56 | */ | ||
57 | ret = __remove_pages(zone, start_pfn, regs[3] >> PAGE_SHIFT); | ||
58 | if (ret) | ||
59 | return ret; | ||
60 | |||
61 | /* | ||
62 | * Update memory regions for memory remove | ||
63 | */ | ||
64 | lmb_remove(start_pfn << PAGE_SHIFT, regs[3]); | ||
65 | |||
66 | /* | ||
67 | * Remove htab bolted mappings for this section of memory | ||
68 | */ | ||
69 | start = (unsigned long)__va(start_pfn << PAGE_SHIFT); | ||
70 | ret = remove_section_mapping(start, start + regs[3]); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | static int pseries_add_memory(struct device_node *np) | ||
75 | { | ||
76 | const char *type; | ||
77 | const unsigned int *my_index; | ||
78 | const unsigned int *regs; | ||
79 | u64 start_pfn; | ||
80 | int ret = -EINVAL; | ||
81 | |||
82 | /* | ||
83 | * Check to see if we are actually adding memory | ||
84 | */ | ||
85 | type = of_get_property(np, "device_type", NULL); | ||
86 | if (type == NULL || strcmp(type, "memory") != 0) | ||
87 | return 0; | ||
88 | |||
89 | /* | ||
90 | * Find the memory index and size of the added section | ||
91 | */ | ||
92 | my_index = of_get_property(np, "ibm,my-drc-index", NULL); | ||
93 | if (!my_index) | ||
94 | return ret; | ||
95 | |||
96 | regs = of_get_property(np, "reg", NULL); | ||
97 | if (!regs) | ||
98 | return ret; | ||
99 | |||
100 | start_pfn = section_nr_to_pfn(*my_index & 0xffff); | ||
101 | |||
102 | /* | ||
103 | * Update memory region to represent the memory add | ||
104 | */ | ||
105 | lmb_add(start_pfn << PAGE_SHIFT, regs[3]); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int pseries_memory_notifier(struct notifier_block *nb, | ||
110 | unsigned long action, void *node) | ||
111 | { | ||
112 | int err = NOTIFY_OK; | ||
113 | |||
114 | switch (action) { | ||
115 | case PSERIES_RECONFIG_ADD: | ||
116 | if (pseries_add_memory(node)) | ||
117 | err = NOTIFY_BAD; | ||
118 | break; | ||
119 | case PSERIES_RECONFIG_REMOVE: | ||
120 | if (pseries_remove_memory(node)) | ||
121 | err = NOTIFY_BAD; | ||
122 | break; | ||
123 | default: | ||
124 | err = NOTIFY_DONE; | ||
125 | break; | ||
126 | } | ||
127 | return err; | ||
128 | } | ||
129 | |||
130 | static struct notifier_block pseries_mem_nb = { | ||
131 | .notifier_call = pseries_memory_notifier, | ||
132 | }; | ||
133 | |||
134 | static int __init pseries_memory_hotplug_init(void) | ||
135 | { | ||
136 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
137 | pSeries_reconfig_notifier_register(&pseries_mem_nb); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | machine_device_initcall(pseries, pseries_memory_hotplug_init); | ||
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index ac75c10de278..75769aae41d5 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -512,12 +512,9 @@ static int proc_ppc64_create_ofdt(void) | |||
512 | if (!machine_is(pseries)) | 512 | if (!machine_is(pseries)) |
513 | return 0; | 513 | return 0; |
514 | 514 | ||
515 | ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); | 515 | ent = proc_create("ppc64/ofdt", S_IWUSR, NULL, &ofdt_fops); |
516 | if (ent) { | 516 | if (ent) |
517 | ent->data = NULL; | ||
518 | ent->size = 0; | 517 | ent->size = 0; |
519 | ent->proc_fops = &ofdt_fops; | ||
520 | } | ||
521 | 518 | ||
522 | return 0; | 519 | return 0; |
523 | } | 520 | } |
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index befadd4f9524..7d3e2b0bd4d2 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c | |||
@@ -468,10 +468,9 @@ static int __init rtas_init(void) | |||
468 | return -ENOMEM; | 468 | return -ENOMEM; |
469 | } | 469 | } |
470 | 470 | ||
471 | entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); | 471 | entry = proc_create("ppc64/rtas/error_log", S_IRUSR, NULL, |
472 | if (entry) | 472 | &proc_rtas_log_operations); |
473 | entry->proc_fops = &proc_rtas_log_operations; | 473 | if (!entry) |
474 | else | ||
475 | printk(KERN_ERR "Failed to create error_log proc entry\n"); | 474 | printk(KERN_ERR "Failed to create error_log proc entry\n"); |
476 | 475 | ||
477 | if (kernel_thread(rtasd, NULL, CLONE_FS) < 0) | 476 | if (kernel_thread(rtasd, NULL, CLONE_FS) < 0) |
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index d359d6e92975..7f59188cd9a1 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c | |||
@@ -143,7 +143,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) | |||
143 | */ | 143 | */ |
144 | static int | 144 | static int |
145 | axon_ram_direct_access(struct block_device *device, sector_t sector, | 145 | axon_ram_direct_access(struct block_device *device, sector_t sector, |
146 | unsigned long *data) | 146 | void **kaddr, unsigned long *pfn) |
147 | { | 147 | { |
148 | struct axon_ram_bank *bank = device->bd_disk->private_data; | 148 | struct axon_ram_bank *bank = device->bd_disk->private_data; |
149 | loff_t offset; | 149 | loff_t offset; |
@@ -154,7 +154,8 @@ axon_ram_direct_access(struct block_device *device, sector_t sector, | |||
154 | return -ERANGE; | 154 | return -ERANGE; |
155 | } | 155 | } |
156 | 156 | ||
157 | *data = bank->ph_addr + offset; | 157 | *kaddr = (void *)(bank->ph_addr + offset); |
158 | *pfn = virt_to_phys(kaddr) >> PAGE_SHIFT; | ||
158 | 159 | ||
159 | return 0; | 160 | return 0; |
160 | } | 161 | } |
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index af2425e4655f..3d920376f58e 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
@@ -1,5 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * MPC85xx RapidIO support | 2 | * Freescale MPC85xx/MPC86xx RapidIO support |
3 | * | ||
4 | * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. | ||
5 | * Zhang Wei <wei.zhang@freescale.com> | ||
3 | * | 6 | * |
4 | * Copyright 2005 MontaVista Software, Inc. | 7 | * Copyright 2005 MontaVista Software, Inc. |
5 | * Matt Porter <mporter@kernel.crashing.org> | 8 | * Matt Porter <mporter@kernel.crashing.org> |
@@ -17,12 +20,23 @@ | |||
17 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
18 | #include <linux/rio.h> | 21 | #include <linux/rio.h> |
19 | #include <linux/rio_drv.h> | 22 | #include <linux/rio_drv.h> |
23 | #include <linux/of_platform.h> | ||
24 | #include <linux/delay.h> | ||
20 | 25 | ||
21 | #include <asm/io.h> | 26 | #include <asm/io.h> |
22 | 27 | ||
23 | #define RIO_REGS_BASE (CCSRBAR + 0xc0000) | 28 | /* RapidIO definition irq, which read from OF-tree */ |
29 | #define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq) | ||
30 | #define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq) | ||
31 | #define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) | ||
32 | |||
24 | #define RIO_ATMU_REGS_OFFSET 0x10c00 | 33 | #define RIO_ATMU_REGS_OFFSET 0x10c00 |
25 | #define RIO_MSG_REGS_OFFSET 0x11000 | 34 | #define RIO_P_MSG_REGS_OFFSET 0x11000 |
35 | #define RIO_S_MSG_REGS_OFFSET 0x13000 | ||
36 | #define RIO_ESCSR 0x158 | ||
37 | #define RIO_CCSR 0x15c | ||
38 | #define RIO_ISR_AACR 0x10120 | ||
39 | #define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ | ||
26 | #define RIO_MAINT_WIN_SIZE 0x400000 | 40 | #define RIO_MAINT_WIN_SIZE 0x400000 |
27 | #define RIO_DBELL_WIN_SIZE 0x1000 | 41 | #define RIO_DBELL_WIN_SIZE 0x1000 |
28 | 42 | ||
@@ -50,18 +64,18 @@ | |||
50 | #define DOORBELL_DSR_TE 0x00000080 | 64 | #define DOORBELL_DSR_TE 0x00000080 |
51 | #define DOORBELL_DSR_QFI 0x00000010 | 65 | #define DOORBELL_DSR_QFI 0x00000010 |
52 | #define DOORBELL_DSR_DIQI 0x00000001 | 66 | #define DOORBELL_DSR_DIQI 0x00000001 |
53 | #define DOORBELL_TID_OFFSET 0x03 | 67 | #define DOORBELL_TID_OFFSET 0x02 |
54 | #define DOORBELL_SID_OFFSET 0x05 | 68 | #define DOORBELL_SID_OFFSET 0x04 |
55 | #define DOORBELL_INFO_OFFSET 0x06 | 69 | #define DOORBELL_INFO_OFFSET 0x06 |
56 | 70 | ||
57 | #define DOORBELL_MESSAGE_SIZE 0x08 | 71 | #define DOORBELL_MESSAGE_SIZE 0x08 |
58 | #define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET)) | 72 | #define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET)) |
59 | #define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) | 73 | #define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET)) |
60 | #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) | 74 | #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) |
61 | 75 | ||
62 | struct rio_atmu_regs { | 76 | struct rio_atmu_regs { |
63 | u32 rowtar; | 77 | u32 rowtar; |
64 | u32 pad1; | 78 | u32 rowtear; |
65 | u32 rowbar; | 79 | u32 rowbar; |
66 | u32 pad2; | 80 | u32 pad2; |
67 | u32 rowar; | 81 | u32 rowar; |
@@ -87,7 +101,15 @@ struct rio_msg_regs { | |||
87 | u32 ifqdpar; | 101 | u32 ifqdpar; |
88 | u32 pad6; | 102 | u32 pad6; |
89 | u32 ifqepar; | 103 | u32 ifqepar; |
90 | u32 pad7[250]; | 104 | u32 pad7[226]; |
105 | u32 odmr; | ||
106 | u32 odsr; | ||
107 | u32 res0[4]; | ||
108 | u32 oddpr; | ||
109 | u32 oddatr; | ||
110 | u32 res1[3]; | ||
111 | u32 odretcr; | ||
112 | u32 res2[12]; | ||
91 | u32 dmr; | 113 | u32 dmr; |
92 | u32 dsr; | 114 | u32 dsr; |
93 | u32 pad8; | 115 | u32 pad8; |
@@ -112,20 +134,12 @@ struct rio_tx_desc { | |||
112 | u32 res4; | 134 | u32 res4; |
113 | }; | 135 | }; |
114 | 136 | ||
115 | static u32 regs_win; | 137 | struct rio_dbell_ring { |
116 | static struct rio_atmu_regs *atmu_regs; | ||
117 | static struct rio_atmu_regs *maint_atmu_regs; | ||
118 | static struct rio_atmu_regs *dbell_atmu_regs; | ||
119 | static u32 dbell_win; | ||
120 | static u32 maint_win; | ||
121 | static struct rio_msg_regs *msg_regs; | ||
122 | |||
123 | static struct rio_dbell_ring { | ||
124 | void *virt; | 138 | void *virt; |
125 | dma_addr_t phys; | 139 | dma_addr_t phys; |
126 | } dbell_ring; | 140 | }; |
127 | 141 | ||
128 | static struct rio_msg_tx_ring { | 142 | struct rio_msg_tx_ring { |
129 | void *virt; | 143 | void *virt; |
130 | dma_addr_t phys; | 144 | dma_addr_t phys; |
131 | void *virt_buffer[RIO_MAX_TX_RING_SIZE]; | 145 | void *virt_buffer[RIO_MAX_TX_RING_SIZE]; |
@@ -133,19 +147,35 @@ static struct rio_msg_tx_ring { | |||
133 | int tx_slot; | 147 | int tx_slot; |
134 | int size; | 148 | int size; |
135 | void *dev_id; | 149 | void *dev_id; |
136 | } msg_tx_ring; | 150 | }; |
137 | 151 | ||
138 | static struct rio_msg_rx_ring { | 152 | struct rio_msg_rx_ring { |
139 | void *virt; | 153 | void *virt; |
140 | dma_addr_t phys; | 154 | dma_addr_t phys; |
141 | void *virt_buffer[RIO_MAX_RX_RING_SIZE]; | 155 | void *virt_buffer[RIO_MAX_RX_RING_SIZE]; |
142 | int rx_slot; | 156 | int rx_slot; |
143 | int size; | 157 | int size; |
144 | void *dev_id; | 158 | void *dev_id; |
145 | } msg_rx_ring; | 159 | }; |
160 | |||
161 | struct rio_priv { | ||
162 | void __iomem *regs_win; | ||
163 | struct rio_atmu_regs __iomem *atmu_regs; | ||
164 | struct rio_atmu_regs __iomem *maint_atmu_regs; | ||
165 | struct rio_atmu_regs __iomem *dbell_atmu_regs; | ||
166 | void __iomem *dbell_win; | ||
167 | void __iomem *maint_win; | ||
168 | struct rio_msg_regs __iomem *msg_regs; | ||
169 | struct rio_dbell_ring dbell_ring; | ||
170 | struct rio_msg_tx_ring msg_tx_ring; | ||
171 | struct rio_msg_rx_ring msg_rx_ring; | ||
172 | int bellirq; | ||
173 | int txirq; | ||
174 | int rxirq; | ||
175 | }; | ||
146 | 176 | ||
147 | /** | 177 | /** |
148 | * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message | 178 | * fsl_rio_doorbell_send - Send a MPC85xx doorbell message |
149 | * @index: ID of RapidIO interface | 179 | * @index: ID of RapidIO interface |
150 | * @destid: Destination ID of target device | 180 | * @destid: Destination ID of target device |
151 | * @data: 16-bit info field of RapidIO doorbell message | 181 | * @data: 16-bit info field of RapidIO doorbell message |
@@ -153,18 +183,34 @@ static struct rio_msg_rx_ring { | |||
153 | * Sends a MPC85xx doorbell message. Returns %0 on success or | 183 | * Sends a MPC85xx doorbell message. Returns %0 on success or |
154 | * %-EINVAL on failure. | 184 | * %-EINVAL on failure. |
155 | */ | 185 | */ |
156 | static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) | 186 | static int fsl_rio_doorbell_send(struct rio_mport *mport, |
187 | int index, u16 destid, u16 data) | ||
157 | { | 188 | { |
158 | pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n", | 189 | struct rio_priv *priv = mport->priv; |
190 | pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n", | ||
159 | index, destid, data); | 191 | index, destid, data); |
160 | out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22); | 192 | switch (mport->phy_type) { |
161 | out_be16((void *)(dbell_win), data); | 193 | case RIO_PHY_PARALLEL: |
194 | out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22); | ||
195 | out_be16(priv->dbell_win, data); | ||
196 | break; | ||
197 | case RIO_PHY_SERIAL: | ||
198 | /* In the serial version silicons, such as MPC8548, MPC8641, | ||
199 | * below operations is must be. | ||
200 | */ | ||
201 | out_be32(&priv->msg_regs->odmr, 0x00000000); | ||
202 | out_be32(&priv->msg_regs->odretcr, 0x00000004); | ||
203 | out_be32(&priv->msg_regs->oddpr, destid << 16); | ||
204 | out_be32(&priv->msg_regs->oddatr, data); | ||
205 | out_be32(&priv->msg_regs->odmr, 0x00000001); | ||
206 | break; | ||
207 | } | ||
162 | 208 | ||
163 | return 0; | 209 | return 0; |
164 | } | 210 | } |
165 | 211 | ||
166 | /** | 212 | /** |
167 | * mpc85xx_local_config_read - Generate a MPC85xx local config space read | 213 | * fsl_local_config_read - Generate a MPC85xx local config space read |
168 | * @index: ID of RapdiIO interface | 214 | * @index: ID of RapdiIO interface |
169 | * @offset: Offset into configuration space | 215 | * @offset: Offset into configuration space |
170 | * @len: Length (in bytes) of the maintenance transaction | 216 | * @len: Length (in bytes) of the maintenance transaction |
@@ -173,17 +219,19 @@ static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) | |||
173 | * Generates a MPC85xx local configuration space read. Returns %0 on | 219 | * Generates a MPC85xx local configuration space read. Returns %0 on |
174 | * success or %-EINVAL on failure. | 220 | * success or %-EINVAL on failure. |
175 | */ | 221 | */ |
176 | static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) | 222 | static int fsl_local_config_read(struct rio_mport *mport, |
223 | int index, u32 offset, int len, u32 *data) | ||
177 | { | 224 | { |
178 | pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index, | 225 | struct rio_priv *priv = mport->priv; |
226 | pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, | ||
179 | offset); | 227 | offset); |
180 | *data = in_be32((void *)(regs_win + offset)); | 228 | *data = in_be32(priv->regs_win + offset); |
181 | 229 | ||
182 | return 0; | 230 | return 0; |
183 | } | 231 | } |
184 | 232 | ||
185 | /** | 233 | /** |
186 | * mpc85xx_local_config_write - Generate a MPC85xx local config space write | 234 | * fsl_local_config_write - Generate a MPC85xx local config space write |
187 | * @index: ID of RapdiIO interface | 235 | * @index: ID of RapdiIO interface |
188 | * @offset: Offset into configuration space | 236 | * @offset: Offset into configuration space |
189 | * @len: Length (in bytes) of the maintenance transaction | 237 | * @len: Length (in bytes) of the maintenance transaction |
@@ -192,18 +240,20 @@ static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) | |||
192 | * Generates a MPC85xx local configuration space write. Returns %0 on | 240 | * Generates a MPC85xx local configuration space write. Returns %0 on |
193 | * success or %-EINVAL on failure. | 241 | * success or %-EINVAL on failure. |
194 | */ | 242 | */ |
195 | static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) | 243 | static int fsl_local_config_write(struct rio_mport *mport, |
244 | int index, u32 offset, int len, u32 data) | ||
196 | { | 245 | { |
246 | struct rio_priv *priv = mport->priv; | ||
197 | pr_debug | 247 | pr_debug |
198 | ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n", | 248 | ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", |
199 | index, offset, data); | 249 | index, offset, data); |
200 | out_be32((void *)(regs_win + offset), data); | 250 | out_be32(priv->regs_win + offset, data); |
201 | 251 | ||
202 | return 0; | 252 | return 0; |
203 | } | 253 | } |
204 | 254 | ||
205 | /** | 255 | /** |
206 | * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction | 256 | * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction |
207 | * @index: ID of RapdiIO interface | 257 | * @index: ID of RapdiIO interface |
208 | * @destid: Destination ID of transaction | 258 | * @destid: Destination ID of transaction |
209 | * @hopcount: Number of hops to target device | 259 | * @hopcount: Number of hops to target device |
@@ -215,18 +265,19 @@ static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) | |||
215 | * success or %-EINVAL on failure. | 265 | * success or %-EINVAL on failure. |
216 | */ | 266 | */ |
217 | static int | 267 | static int |
218 | mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, | 268 | fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, |
219 | u32 * val) | 269 | u8 hopcount, u32 offset, int len, u32 *val) |
220 | { | 270 | { |
271 | struct rio_priv *priv = mport->priv; | ||
221 | u8 *data; | 272 | u8 *data; |
222 | 273 | ||
223 | pr_debug | 274 | pr_debug |
224 | ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", | 275 | ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", |
225 | index, destid, hopcount, offset, len); | 276 | index, destid, hopcount, offset, len); |
226 | out_be32((void *)&maint_atmu_regs->rowtar, | 277 | out_be32(&priv->maint_atmu_regs->rowtar, |
227 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); | 278 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); |
228 | 279 | ||
229 | data = (u8 *) maint_win + offset; | 280 | data = (u8 *) priv->maint_win + offset; |
230 | switch (len) { | 281 | switch (len) { |
231 | case 1: | 282 | case 1: |
232 | *val = in_8((u8 *) data); | 283 | *val = in_8((u8 *) data); |
@@ -243,7 +294,7 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, | |||
243 | } | 294 | } |
244 | 295 | ||
245 | /** | 296 | /** |
246 | * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction | 297 | * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction |
247 | * @index: ID of RapdiIO interface | 298 | * @index: ID of RapdiIO interface |
248 | * @destid: Destination ID of transaction | 299 | * @destid: Destination ID of transaction |
249 | * @hopcount: Number of hops to target device | 300 | * @hopcount: Number of hops to target device |
@@ -255,17 +306,18 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, | |||
255 | * success or %-EINVAL on failure. | 306 | * success or %-EINVAL on failure. |
256 | */ | 307 | */ |
257 | static int | 308 | static int |
258 | mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset, | 309 | fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, |
259 | int len, u32 val) | 310 | u8 hopcount, u32 offset, int len, u32 val) |
260 | { | 311 | { |
312 | struct rio_priv *priv = mport->priv; | ||
261 | u8 *data; | 313 | u8 *data; |
262 | pr_debug | 314 | pr_debug |
263 | ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", | 315 | ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", |
264 | index, destid, hopcount, offset, len, val); | 316 | index, destid, hopcount, offset, len, val); |
265 | out_be32((void *)&maint_atmu_regs->rowtar, | 317 | out_be32(&priv->maint_atmu_regs->rowtar, |
266 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); | 318 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); |
267 | 319 | ||
268 | data = (u8 *) maint_win + offset; | 320 | data = (u8 *) priv->maint_win + offset; |
269 | switch (len) { | 321 | switch (len) { |
270 | case 1: | 322 | case 1: |
271 | out_8((u8 *) data, val); | 323 | out_8((u8 *) data, val); |
@@ -296,9 +348,10 @@ int | |||
296 | rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | 348 | rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, |
297 | void *buffer, size_t len) | 349 | void *buffer, size_t len) |
298 | { | 350 | { |
351 | struct rio_priv *priv = mport->priv; | ||
299 | u32 omr; | 352 | u32 omr; |
300 | struct rio_tx_desc *desc = | 353 | struct rio_tx_desc *desc = (struct rio_tx_desc *)priv->msg_tx_ring.virt |
301 | (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot; | 354 | + priv->msg_tx_ring.tx_slot; |
302 | int ret = 0; | 355 | int ret = 0; |
303 | 356 | ||
304 | pr_debug | 357 | pr_debug |
@@ -311,31 +364,43 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | |||
311 | } | 364 | } |
312 | 365 | ||
313 | /* Copy and clear rest of buffer */ | 366 | /* Copy and clear rest of buffer */ |
314 | memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len); | 367 | memcpy(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot], buffer, |
368 | len); | ||
315 | if (len < (RIO_MAX_MSG_SIZE - 4)) | 369 | if (len < (RIO_MAX_MSG_SIZE - 4)) |
316 | memset((void *)((u32) msg_tx_ring. | 370 | memset(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot] |
317 | virt_buffer[msg_tx_ring.tx_slot] + len), 0, | 371 | + len, 0, RIO_MAX_MSG_SIZE - len); |
318 | RIO_MAX_MSG_SIZE - len); | ||
319 | 372 | ||
320 | /* Set mbox field for message */ | 373 | switch (mport->phy_type) { |
321 | desc->dport = mbox & 0x3; | 374 | case RIO_PHY_PARALLEL: |
375 | /* Set mbox field for message */ | ||
376 | desc->dport = mbox & 0x3; | ||
322 | 377 | ||
323 | /* Enable EOMI interrupt, set priority, and set destid */ | 378 | /* Enable EOMI interrupt, set priority, and set destid */ |
324 | desc->dattr = 0x28000000 | (rdev->destid << 2); | 379 | desc->dattr = 0x28000000 | (rdev->destid << 2); |
380 | break; | ||
381 | case RIO_PHY_SERIAL: | ||
382 | /* Set mbox field for message, and set destid */ | ||
383 | desc->dport = (rdev->destid << 16) | (mbox & 0x3); | ||
384 | |||
385 | /* Enable EOMI interrupt and priority */ | ||
386 | desc->dattr = 0x28000000; | ||
387 | break; | ||
388 | } | ||
325 | 389 | ||
326 | /* Set transfer size aligned to next power of 2 (in double words) */ | 390 | /* Set transfer size aligned to next power of 2 (in double words) */ |
327 | desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); | 391 | desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); |
328 | 392 | ||
329 | /* Set snooping and source buffer address */ | 393 | /* Set snooping and source buffer address */ |
330 | desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot]; | 394 | desc->saddr = 0x00000004 |
395 | | priv->msg_tx_ring.phys_buffer[priv->msg_tx_ring.tx_slot]; | ||
331 | 396 | ||
332 | /* Increment enqueue pointer */ | 397 | /* Increment enqueue pointer */ |
333 | omr = in_be32((void *)&msg_regs->omr); | 398 | omr = in_be32(&priv->msg_regs->omr); |
334 | out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI); | 399 | out_be32(&priv->msg_regs->omr, omr | RIO_MSG_OMR_MUI); |
335 | 400 | ||
336 | /* Go to next descriptor */ | 401 | /* Go to next descriptor */ |
337 | if (++msg_tx_ring.tx_slot == msg_tx_ring.size) | 402 | if (++priv->msg_tx_ring.tx_slot == priv->msg_tx_ring.size) |
338 | msg_tx_ring.tx_slot = 0; | 403 | priv->msg_tx_ring.tx_slot = 0; |
339 | 404 | ||
340 | out: | 405 | out: |
341 | return ret; | 406 | return ret; |
@@ -344,7 +409,7 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | |||
344 | EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); | 409 | EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); |
345 | 410 | ||
346 | /** | 411 | /** |
347 | * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler | 412 | * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler |
348 | * @irq: Linux interrupt number | 413 | * @irq: Linux interrupt number |
349 | * @dev_instance: Pointer to interrupt-specific data | 414 | * @dev_instance: Pointer to interrupt-specific data |
350 | * | 415 | * |
@@ -352,32 +417,34 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); | |||
352 | * mailbox event handler and acks the interrupt occurrence. | 417 | * mailbox event handler and acks the interrupt occurrence. |
353 | */ | 418 | */ |
354 | static irqreturn_t | 419 | static irqreturn_t |
355 | mpc85xx_rio_tx_handler(int irq, void *dev_instance) | 420 | fsl_rio_tx_handler(int irq, void *dev_instance) |
356 | { | 421 | { |
357 | int osr; | 422 | int osr; |
358 | struct rio_mport *port = (struct rio_mport *)dev_instance; | 423 | struct rio_mport *port = (struct rio_mport *)dev_instance; |
424 | struct rio_priv *priv = port->priv; | ||
359 | 425 | ||
360 | osr = in_be32((void *)&msg_regs->osr); | 426 | osr = in_be32(&priv->msg_regs->osr); |
361 | 427 | ||
362 | if (osr & RIO_MSG_OSR_TE) { | 428 | if (osr & RIO_MSG_OSR_TE) { |
363 | pr_info("RIO: outbound message transmission error\n"); | 429 | pr_info("RIO: outbound message transmission error\n"); |
364 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE); | 430 | out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_TE); |
365 | goto out; | 431 | goto out; |
366 | } | 432 | } |
367 | 433 | ||
368 | if (osr & RIO_MSG_OSR_QOI) { | 434 | if (osr & RIO_MSG_OSR_QOI) { |
369 | pr_info("RIO: outbound message queue overflow\n"); | 435 | pr_info("RIO: outbound message queue overflow\n"); |
370 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI); | 436 | out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_QOI); |
371 | goto out; | 437 | goto out; |
372 | } | 438 | } |
373 | 439 | ||
374 | if (osr & RIO_MSG_OSR_EOMI) { | 440 | if (osr & RIO_MSG_OSR_EOMI) { |
375 | u32 dqp = in_be32((void *)&msg_regs->odqdpar); | 441 | u32 dqp = in_be32(&priv->msg_regs->odqdpar); |
376 | int slot = (dqp - msg_tx_ring.phys) >> 5; | 442 | int slot = (dqp - priv->msg_tx_ring.phys) >> 5; |
377 | port->outb_msg[0].mcback(port, msg_tx_ring.dev_id, -1, slot); | 443 | port->outb_msg[0].mcback(port, priv->msg_tx_ring.dev_id, -1, |
444 | slot); | ||
378 | 445 | ||
379 | /* Ack the end-of-message interrupt */ | 446 | /* Ack the end-of-message interrupt */ |
380 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI); | 447 | out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_EOMI); |
381 | } | 448 | } |
382 | 449 | ||
383 | out: | 450 | out: |
@@ -398,6 +465,7 @@ mpc85xx_rio_tx_handler(int irq, void *dev_instance) | |||
398 | int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | 465 | int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) |
399 | { | 466 | { |
400 | int i, j, rc = 0; | 467 | int i, j, rc = 0; |
468 | struct rio_priv *priv = mport->priv; | ||
401 | 469 | ||
402 | if ((entries < RIO_MIN_TX_RING_SIZE) || | 470 | if ((entries < RIO_MIN_TX_RING_SIZE) || |
403 | (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { | 471 | (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { |
@@ -406,54 +474,53 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr | |||
406 | } | 474 | } |
407 | 475 | ||
408 | /* Initialize shadow copy ring */ | 476 | /* Initialize shadow copy ring */ |
409 | msg_tx_ring.dev_id = dev_id; | 477 | priv->msg_tx_ring.dev_id = dev_id; |
410 | msg_tx_ring.size = entries; | 478 | priv->msg_tx_ring.size = entries; |
411 | 479 | ||
412 | for (i = 0; i < msg_tx_ring.size; i++) { | 480 | for (i = 0; i < priv->msg_tx_ring.size; i++) { |
413 | if (! | 481 | priv->msg_tx_ring.virt_buffer[i] = |
414 | (msg_tx_ring.virt_buffer[i] = | 482 | dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE, |
415 | dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE, | 483 | &priv->msg_tx_ring.phys_buffer[i], GFP_KERNEL); |
416 | &msg_tx_ring.phys_buffer[i], | 484 | if (!priv->msg_tx_ring.virt_buffer[i]) { |
417 | GFP_KERNEL))) { | ||
418 | rc = -ENOMEM; | 485 | rc = -ENOMEM; |
419 | for (j = 0; j < msg_tx_ring.size; j++) | 486 | for (j = 0; j < priv->msg_tx_ring.size; j++) |
420 | if (msg_tx_ring.virt_buffer[j]) | 487 | if (priv->msg_tx_ring.virt_buffer[j]) |
421 | dma_free_coherent(NULL, | 488 | dma_free_coherent(NULL, |
422 | RIO_MSG_BUFFER_SIZE, | 489 | RIO_MSG_BUFFER_SIZE, |
423 | msg_tx_ring. | 490 | priv->msg_tx_ring. |
424 | virt_buffer[j], | 491 | virt_buffer[j], |
425 | msg_tx_ring. | 492 | priv->msg_tx_ring. |
426 | phys_buffer[j]); | 493 | phys_buffer[j]); |
427 | goto out; | 494 | goto out; |
428 | } | 495 | } |
429 | } | 496 | } |
430 | 497 | ||
431 | /* Initialize outbound message descriptor ring */ | 498 | /* Initialize outbound message descriptor ring */ |
432 | if (!(msg_tx_ring.virt = dma_alloc_coherent(NULL, | 499 | priv->msg_tx_ring.virt = dma_alloc_coherent(NULL, |
433 | msg_tx_ring.size * | 500 | priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE, |
434 | RIO_MSG_DESC_SIZE, | 501 | &priv->msg_tx_ring.phys, GFP_KERNEL); |
435 | &msg_tx_ring.phys, | 502 | if (!priv->msg_tx_ring.virt) { |
436 | GFP_KERNEL))) { | ||
437 | rc = -ENOMEM; | 503 | rc = -ENOMEM; |
438 | goto out_dma; | 504 | goto out_dma; |
439 | } | 505 | } |
440 | memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE); | 506 | memset(priv->msg_tx_ring.virt, 0, |
441 | msg_tx_ring.tx_slot = 0; | 507 | priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE); |
508 | priv->msg_tx_ring.tx_slot = 0; | ||
442 | 509 | ||
443 | /* Point dequeue/enqueue pointers at first entry in ring */ | 510 | /* Point dequeue/enqueue pointers at first entry in ring */ |
444 | out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys); | 511 | out_be32(&priv->msg_regs->odqdpar, priv->msg_tx_ring.phys); |
445 | out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys); | 512 | out_be32(&priv->msg_regs->odqepar, priv->msg_tx_ring.phys); |
446 | 513 | ||
447 | /* Configure for snooping */ | 514 | /* Configure for snooping */ |
448 | out_be32((void *)&msg_regs->osar, 0x00000004); | 515 | out_be32(&priv->msg_regs->osar, 0x00000004); |
449 | 516 | ||
450 | /* Clear interrupt status */ | 517 | /* Clear interrupt status */ |
451 | out_be32((void *)&msg_regs->osr, 0x000000b3); | 518 | out_be32(&priv->msg_regs->osr, 0x000000b3); |
452 | 519 | ||
453 | /* Hook up outbound message handler */ | 520 | /* Hook up outbound message handler */ |
454 | if ((rc = | 521 | rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0, |
455 | request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, | 522 | "msg_tx", (void *)mport); |
456 | "msg_tx", (void *)mport)) < 0) | 523 | if (rc < 0) |
457 | goto out_irq; | 524 | goto out_irq; |
458 | 525 | ||
459 | /* | 526 | /* |
@@ -463,28 +530,28 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr | |||
463 | * Chaining mode | 530 | * Chaining mode |
464 | * Disable | 531 | * Disable |
465 | */ | 532 | */ |
466 | out_be32((void *)&msg_regs->omr, 0x00100220); | 533 | out_be32(&priv->msg_regs->omr, 0x00100220); |
467 | 534 | ||
468 | /* Set number of entries */ | 535 | /* Set number of entries */ |
469 | out_be32((void *)&msg_regs->omr, | 536 | out_be32(&priv->msg_regs->omr, |
470 | in_be32((void *)&msg_regs->omr) | | 537 | in_be32(&priv->msg_regs->omr) | |
471 | ((get_bitmask_order(entries) - 2) << 12)); | 538 | ((get_bitmask_order(entries) - 2) << 12)); |
472 | 539 | ||
473 | /* Now enable the unit */ | 540 | /* Now enable the unit */ |
474 | out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1); | 541 | out_be32(&priv->msg_regs->omr, in_be32(&priv->msg_regs->omr) | 0x1); |
475 | 542 | ||
476 | out: | 543 | out: |
477 | return rc; | 544 | return rc; |
478 | 545 | ||
479 | out_irq: | 546 | out_irq: |
480 | dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, | 547 | dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE, |
481 | msg_tx_ring.virt, msg_tx_ring.phys); | 548 | priv->msg_tx_ring.virt, priv->msg_tx_ring.phys); |
482 | 549 | ||
483 | out_dma: | 550 | out_dma: |
484 | for (i = 0; i < msg_tx_ring.size; i++) | 551 | for (i = 0; i < priv->msg_tx_ring.size; i++) |
485 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, | 552 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, |
486 | msg_tx_ring.virt_buffer[i], | 553 | priv->msg_tx_ring.virt_buffer[i], |
487 | msg_tx_ring.phys_buffer[i]); | 554 | priv->msg_tx_ring.phys_buffer[i]); |
488 | 555 | ||
489 | return rc; | 556 | return rc; |
490 | } | 557 | } |
@@ -499,19 +566,20 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr | |||
499 | */ | 566 | */ |
500 | void rio_close_outb_mbox(struct rio_mport *mport, int mbox) | 567 | void rio_close_outb_mbox(struct rio_mport *mport, int mbox) |
501 | { | 568 | { |
569 | struct rio_priv *priv = mport->priv; | ||
502 | /* Disable inbound message unit */ | 570 | /* Disable inbound message unit */ |
503 | out_be32((void *)&msg_regs->omr, 0); | 571 | out_be32(&priv->msg_regs->omr, 0); |
504 | 572 | ||
505 | /* Free ring */ | 573 | /* Free ring */ |
506 | dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, | 574 | dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE, |
507 | msg_tx_ring.virt, msg_tx_ring.phys); | 575 | priv->msg_tx_ring.virt, priv->msg_tx_ring.phys); |
508 | 576 | ||
509 | /* Free interrupt */ | 577 | /* Free interrupt */ |
510 | free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport); | 578 | free_irq(IRQ_RIO_TX(mport), (void *)mport); |
511 | } | 579 | } |
512 | 580 | ||
513 | /** | 581 | /** |
514 | * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler | 582 | * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler |
515 | * @irq: Linux interrupt number | 583 | * @irq: Linux interrupt number |
516 | * @dev_instance: Pointer to interrupt-specific data | 584 | * @dev_instance: Pointer to interrupt-specific data |
517 | * | 585 | * |
@@ -519,16 +587,17 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox) | |||
519 | * mailbox event handler and acks the interrupt occurrence. | 587 | * mailbox event handler and acks the interrupt occurrence. |
520 | */ | 588 | */ |
521 | static irqreturn_t | 589 | static irqreturn_t |
522 | mpc85xx_rio_rx_handler(int irq, void *dev_instance) | 590 | fsl_rio_rx_handler(int irq, void *dev_instance) |
523 | { | 591 | { |
524 | int isr; | 592 | int isr; |
525 | struct rio_mport *port = (struct rio_mport *)dev_instance; | 593 | struct rio_mport *port = (struct rio_mport *)dev_instance; |
594 | struct rio_priv *priv = port->priv; | ||
526 | 595 | ||
527 | isr = in_be32((void *)&msg_regs->isr); | 596 | isr = in_be32(&priv->msg_regs->isr); |
528 | 597 | ||
529 | if (isr & RIO_MSG_ISR_TE) { | 598 | if (isr & RIO_MSG_ISR_TE) { |
530 | pr_info("RIO: inbound message reception error\n"); | 599 | pr_info("RIO: inbound message reception error\n"); |
531 | out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE); | 600 | out_be32((void *)&priv->msg_regs->isr, RIO_MSG_ISR_TE); |
532 | goto out; | 601 | goto out; |
533 | } | 602 | } |
534 | 603 | ||
@@ -540,10 +609,10 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance) | |||
540 | * make the callback with an unknown/invalid mailbox number | 609 | * make the callback with an unknown/invalid mailbox number |
541 | * argument. | 610 | * argument. |
542 | */ | 611 | */ |
543 | port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1); | 612 | port->inb_msg[0].mcback(port, priv->msg_rx_ring.dev_id, -1, -1); |
544 | 613 | ||
545 | /* Ack the queueing interrupt */ | 614 | /* Ack the queueing interrupt */ |
546 | out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI); | 615 | out_be32(&priv->msg_regs->isr, RIO_MSG_ISR_DIQI); |
547 | } | 616 | } |
548 | 617 | ||
549 | out: | 618 | out: |
@@ -564,6 +633,7 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance) | |||
564 | int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | 633 | int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) |
565 | { | 634 | { |
566 | int i, rc = 0; | 635 | int i, rc = 0; |
636 | struct rio_priv *priv = mport->priv; | ||
567 | 637 | ||
568 | if ((entries < RIO_MIN_RX_RING_SIZE) || | 638 | if ((entries < RIO_MIN_RX_RING_SIZE) || |
569 | (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { | 639 | (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { |
@@ -572,36 +642,35 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri | |||
572 | } | 642 | } |
573 | 643 | ||
574 | /* Initialize client buffer ring */ | 644 | /* Initialize client buffer ring */ |
575 | msg_rx_ring.dev_id = dev_id; | 645 | priv->msg_rx_ring.dev_id = dev_id; |
576 | msg_rx_ring.size = entries; | 646 | priv->msg_rx_ring.size = entries; |
577 | msg_rx_ring.rx_slot = 0; | 647 | priv->msg_rx_ring.rx_slot = 0; |
578 | for (i = 0; i < msg_rx_ring.size; i++) | 648 | for (i = 0; i < priv->msg_rx_ring.size; i++) |
579 | msg_rx_ring.virt_buffer[i] = NULL; | 649 | priv->msg_rx_ring.virt_buffer[i] = NULL; |
580 | 650 | ||
581 | /* Initialize inbound message ring */ | 651 | /* Initialize inbound message ring */ |
582 | if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL, | 652 | priv->msg_rx_ring.virt = dma_alloc_coherent(NULL, |
583 | msg_rx_ring.size * | 653 | priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE, |
584 | RIO_MAX_MSG_SIZE, | 654 | &priv->msg_rx_ring.phys, GFP_KERNEL); |
585 | &msg_rx_ring.phys, | 655 | if (!priv->msg_rx_ring.virt) { |
586 | GFP_KERNEL))) { | ||
587 | rc = -ENOMEM; | 656 | rc = -ENOMEM; |
588 | goto out; | 657 | goto out; |
589 | } | 658 | } |
590 | 659 | ||
591 | /* Point dequeue/enqueue pointers at first entry in ring */ | 660 | /* Point dequeue/enqueue pointers at first entry in ring */ |
592 | out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys); | 661 | out_be32(&priv->msg_regs->ifqdpar, (u32) priv->msg_rx_ring.phys); |
593 | out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys); | 662 | out_be32(&priv->msg_regs->ifqepar, (u32) priv->msg_rx_ring.phys); |
594 | 663 | ||
595 | /* Clear interrupt status */ | 664 | /* Clear interrupt status */ |
596 | out_be32((void *)&msg_regs->isr, 0x00000091); | 665 | out_be32(&priv->msg_regs->isr, 0x00000091); |
597 | 666 | ||
598 | /* Hook up inbound message handler */ | 667 | /* Hook up inbound message handler */ |
599 | if ((rc = | 668 | rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0, |
600 | request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, | 669 | "msg_rx", (void *)mport); |
601 | "msg_rx", (void *)mport)) < 0) { | 670 | if (rc < 0) { |
602 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, | 671 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, |
603 | msg_tx_ring.virt_buffer[i], | 672 | priv->msg_tx_ring.virt_buffer[i], |
604 | msg_tx_ring.phys_buffer[i]); | 673 | priv->msg_tx_ring.phys_buffer[i]); |
605 | goto out; | 674 | goto out; |
606 | } | 675 | } |
607 | 676 | ||
@@ -612,15 +681,13 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri | |||
612 | * Unmask all interrupt sources | 681 | * Unmask all interrupt sources |
613 | * Disable | 682 | * Disable |
614 | */ | 683 | */ |
615 | out_be32((void *)&msg_regs->imr, 0x001b0060); | 684 | out_be32(&priv->msg_regs->imr, 0x001b0060); |
616 | 685 | ||
617 | /* Set number of queue entries */ | 686 | /* Set number of queue entries */ |
618 | out_be32((void *)&msg_regs->imr, | 687 | setbits32(&priv->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12); |
619 | in_be32((void *)&msg_regs->imr) | | ||
620 | ((get_bitmask_order(entries) - 2) << 12)); | ||
621 | 688 | ||
622 | /* Now enable the unit */ | 689 | /* Now enable the unit */ |
623 | out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1); | 690 | setbits32(&priv->msg_regs->imr, 0x1); |
624 | 691 | ||
625 | out: | 692 | out: |
626 | return rc; | 693 | return rc; |
@@ -636,15 +703,16 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri | |||
636 | */ | 703 | */ |
637 | void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | 704 | void rio_close_inb_mbox(struct rio_mport *mport, int mbox) |
638 | { | 705 | { |
706 | struct rio_priv *priv = mport->priv; | ||
639 | /* Disable inbound message unit */ | 707 | /* Disable inbound message unit */ |
640 | out_be32((void *)&msg_regs->imr, 0); | 708 | out_be32(&priv->msg_regs->imr, 0); |
641 | 709 | ||
642 | /* Free ring */ | 710 | /* Free ring */ |
643 | dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE, | 711 | dma_free_coherent(NULL, priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE, |
644 | msg_rx_ring.virt, msg_rx_ring.phys); | 712 | priv->msg_rx_ring.virt, priv->msg_rx_ring.phys); |
645 | 713 | ||
646 | /* Free interrupt */ | 714 | /* Free interrupt */ |
647 | free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport); | 715 | free_irq(IRQ_RIO_RX(mport), (void *)mport); |
648 | } | 716 | } |
649 | 717 | ||
650 | /** | 718 | /** |
@@ -659,21 +727,22 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | |||
659 | int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) | 727 | int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) |
660 | { | 728 | { |
661 | int rc = 0; | 729 | int rc = 0; |
730 | struct rio_priv *priv = mport->priv; | ||
662 | 731 | ||
663 | pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", | 732 | pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", |
664 | msg_rx_ring.rx_slot); | 733 | priv->msg_rx_ring.rx_slot); |
665 | 734 | ||
666 | if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) { | 735 | if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) { |
667 | printk(KERN_ERR | 736 | printk(KERN_ERR |
668 | "RIO: error adding inbound buffer %d, buffer exists\n", | 737 | "RIO: error adding inbound buffer %d, buffer exists\n", |
669 | msg_rx_ring.rx_slot); | 738 | priv->msg_rx_ring.rx_slot); |
670 | rc = -EINVAL; | 739 | rc = -EINVAL; |
671 | goto out; | 740 | goto out; |
672 | } | 741 | } |
673 | 742 | ||
674 | msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf; | 743 | priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot] = buf; |
675 | if (++msg_rx_ring.rx_slot == msg_rx_ring.size) | 744 | if (++priv->msg_rx_ring.rx_slot == priv->msg_rx_ring.size) |
676 | msg_rx_ring.rx_slot = 0; | 745 | priv->msg_rx_ring.rx_slot = 0; |
677 | 746 | ||
678 | out: | 747 | out: |
679 | return rc; | 748 | return rc; |
@@ -691,20 +760,21 @@ EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer); | |||
691 | */ | 760 | */ |
692 | void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | 761 | void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) |
693 | { | 762 | { |
694 | u32 imr; | 763 | struct rio_priv *priv = mport->priv; |
695 | u32 phys_buf, virt_buf; | 764 | u32 phys_buf, virt_buf; |
696 | void *buf = NULL; | 765 | void *buf = NULL; |
697 | int buf_idx; | 766 | int buf_idx; |
698 | 767 | ||
699 | phys_buf = in_be32((void *)&msg_regs->ifqdpar); | 768 | phys_buf = in_be32(&priv->msg_regs->ifqdpar); |
700 | 769 | ||
701 | /* If no more messages, then bail out */ | 770 | /* If no more messages, then bail out */ |
702 | if (phys_buf == in_be32((void *)&msg_regs->ifqepar)) | 771 | if (phys_buf == in_be32(&priv->msg_regs->ifqepar)) |
703 | goto out2; | 772 | goto out2; |
704 | 773 | ||
705 | virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys); | 774 | virt_buf = (u32) priv->msg_rx_ring.virt + (phys_buf |
706 | buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; | 775 | - priv->msg_rx_ring.phys); |
707 | buf = msg_rx_ring.virt_buffer[buf_idx]; | 776 | buf_idx = (phys_buf - priv->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; |
777 | buf = priv->msg_rx_ring.virt_buffer[buf_idx]; | ||
708 | 778 | ||
709 | if (!buf) { | 779 | if (!buf) { |
710 | printk(KERN_ERR | 780 | printk(KERN_ERR |
@@ -716,11 +786,10 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | |||
716 | memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); | 786 | memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); |
717 | 787 | ||
718 | /* Clear the available buffer */ | 788 | /* Clear the available buffer */ |
719 | msg_rx_ring.virt_buffer[buf_idx] = NULL; | 789 | priv->msg_rx_ring.virt_buffer[buf_idx] = NULL; |
720 | 790 | ||
721 | out1: | 791 | out1: |
722 | imr = in_be32((void *)&msg_regs->imr); | 792 | setbits32(&priv->msg_regs->imr, RIO_MSG_IMR_MI); |
723 | out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI); | ||
724 | 793 | ||
725 | out2: | 794 | out2: |
726 | return buf; | 795 | return buf; |
@@ -729,7 +798,7 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | |||
729 | EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); | 798 | EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); |
730 | 799 | ||
731 | /** | 800 | /** |
732 | * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler | 801 | * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler |
733 | * @irq: Linux interrupt number | 802 | * @irq: Linux interrupt number |
734 | * @dev_instance: Pointer to interrupt-specific data | 803 | * @dev_instance: Pointer to interrupt-specific data |
735 | * | 804 | * |
@@ -737,31 +806,31 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); | |||
737 | * doorbell event handlers and executes a matching event handler. | 806 | * doorbell event handlers and executes a matching event handler. |
738 | */ | 807 | */ |
739 | static irqreturn_t | 808 | static irqreturn_t |
740 | mpc85xx_rio_dbell_handler(int irq, void *dev_instance) | 809 | fsl_rio_dbell_handler(int irq, void *dev_instance) |
741 | { | 810 | { |
742 | int dsr; | 811 | int dsr; |
743 | struct rio_mport *port = (struct rio_mport *)dev_instance; | 812 | struct rio_mport *port = (struct rio_mport *)dev_instance; |
813 | struct rio_priv *priv = port->priv; | ||
744 | 814 | ||
745 | dsr = in_be32((void *)&msg_regs->dsr); | 815 | dsr = in_be32(&priv->msg_regs->dsr); |
746 | 816 | ||
747 | if (dsr & DOORBELL_DSR_TE) { | 817 | if (dsr & DOORBELL_DSR_TE) { |
748 | pr_info("RIO: doorbell reception error\n"); | 818 | pr_info("RIO: doorbell reception error\n"); |
749 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE); | 819 | out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_TE); |
750 | goto out; | 820 | goto out; |
751 | } | 821 | } |
752 | 822 | ||
753 | if (dsr & DOORBELL_DSR_QFI) { | 823 | if (dsr & DOORBELL_DSR_QFI) { |
754 | pr_info("RIO: doorbell queue full\n"); | 824 | pr_info("RIO: doorbell queue full\n"); |
755 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI); | 825 | out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_QFI); |
756 | goto out; | 826 | goto out; |
757 | } | 827 | } |
758 | 828 | ||
759 | /* XXX Need to check/dispatch until queue empty */ | 829 | /* XXX Need to check/dispatch until queue empty */ |
760 | if (dsr & DOORBELL_DSR_DIQI) { | 830 | if (dsr & DOORBELL_DSR_DIQI) { |
761 | u32 dmsg = | 831 | u32 dmsg = |
762 | (u32) dbell_ring.virt + | 832 | (u32) priv->dbell_ring.virt + |
763 | (in_be32((void *)&msg_regs->dqdpar) & 0xfff); | 833 | (in_be32(&priv->msg_regs->dqdpar) & 0xfff); |
764 | u32 dmr; | ||
765 | struct rio_dbell *dbell; | 834 | struct rio_dbell *dbell; |
766 | int found = 0; | 835 | int found = 0; |
767 | 836 | ||
@@ -784,9 +853,8 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance) | |||
784 | ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n", | 853 | ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n", |
785 | DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); | 854 | DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); |
786 | } | 855 | } |
787 | dmr = in_be32((void *)&msg_regs->dmr); | 856 | setbits32(&priv->msg_regs->dmr, DOORBELL_DMR_DI); |
788 | out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI); | 857 | out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_DIQI); |
789 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI); | ||
790 | } | 858 | } |
791 | 859 | ||
792 | out: | 860 | out: |
@@ -794,21 +862,22 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance) | |||
794 | } | 862 | } |
795 | 863 | ||
796 | /** | 864 | /** |
797 | * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init | 865 | * fsl_rio_doorbell_init - MPC85xx doorbell interface init |
798 | * @mport: Master port implementing the inbound doorbell unit | 866 | * @mport: Master port implementing the inbound doorbell unit |
799 | * | 867 | * |
800 | * Initializes doorbell unit hardware and inbound DMA buffer | 868 | * Initializes doorbell unit hardware and inbound DMA buffer |
801 | * ring. Called from mpc85xx_rio_setup(). Returns %0 on success | 869 | * ring. Called from fsl_rio_setup(). Returns %0 on success |
802 | * or %-ENOMEM on failure. | 870 | * or %-ENOMEM on failure. |
803 | */ | 871 | */ |
804 | static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) | 872 | static int fsl_rio_doorbell_init(struct rio_mport *mport) |
805 | { | 873 | { |
874 | struct rio_priv *priv = mport->priv; | ||
806 | int rc = 0; | 875 | int rc = 0; |
807 | 876 | ||
808 | /* Map outbound doorbell window immediately after maintenance window */ | 877 | /* Map outbound doorbell window immediately after maintenance window */ |
809 | if (!(dbell_win = | 878 | priv->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, |
810 | (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, | 879 | RIO_DBELL_WIN_SIZE); |
811 | RIO_DBELL_WIN_SIZE))) { | 880 | if (!priv->dbell_win) { |
812 | printk(KERN_ERR | 881 | printk(KERN_ERR |
813 | "RIO: unable to map outbound doorbell window\n"); | 882 | "RIO: unable to map outbound doorbell window\n"); |
814 | rc = -ENOMEM; | 883 | rc = -ENOMEM; |
@@ -816,37 +885,36 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) | |||
816 | } | 885 | } |
817 | 886 | ||
818 | /* Initialize inbound doorbells */ | 887 | /* Initialize inbound doorbells */ |
819 | if (!(dbell_ring.virt = dma_alloc_coherent(NULL, | 888 | priv->dbell_ring.virt = dma_alloc_coherent(NULL, 512 * |
820 | 512 * DOORBELL_MESSAGE_SIZE, | 889 | DOORBELL_MESSAGE_SIZE, &priv->dbell_ring.phys, GFP_KERNEL); |
821 | &dbell_ring.phys, | 890 | if (!priv->dbell_ring.virt) { |
822 | GFP_KERNEL))) { | ||
823 | printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); | 891 | printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); |
824 | rc = -ENOMEM; | 892 | rc = -ENOMEM; |
825 | iounmap((void *)dbell_win); | 893 | iounmap(priv->dbell_win); |
826 | goto out; | 894 | goto out; |
827 | } | 895 | } |
828 | 896 | ||
829 | /* Point dequeue/enqueue pointers at first entry in ring */ | 897 | /* Point dequeue/enqueue pointers at first entry in ring */ |
830 | out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys); | 898 | out_be32(&priv->msg_regs->dqdpar, (u32) priv->dbell_ring.phys); |
831 | out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys); | 899 | out_be32(&priv->msg_regs->dqepar, (u32) priv->dbell_ring.phys); |
832 | 900 | ||
833 | /* Clear interrupt status */ | 901 | /* Clear interrupt status */ |
834 | out_be32((void *)&msg_regs->dsr, 0x00000091); | 902 | out_be32(&priv->msg_regs->dsr, 0x00000091); |
835 | 903 | ||
836 | /* Hook up doorbell handler */ | 904 | /* Hook up doorbell handler */ |
837 | if ((rc = | 905 | rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0, |
838 | request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0, | 906 | "dbell_rx", (void *)mport); |
839 | "dbell_rx", (void *)mport) < 0)) { | 907 | if (rc < 0) { |
840 | iounmap((void *)dbell_win); | 908 | iounmap(priv->dbell_win); |
841 | dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE, | 909 | dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE, |
842 | dbell_ring.virt, dbell_ring.phys); | 910 | priv->dbell_ring.virt, priv->dbell_ring.phys); |
843 | printk(KERN_ERR | 911 | printk(KERN_ERR |
844 | "MPC85xx RIO: unable to request inbound doorbell irq"); | 912 | "MPC85xx RIO: unable to request inbound doorbell irq"); |
845 | goto out; | 913 | goto out; |
846 | } | 914 | } |
847 | 915 | ||
848 | /* Configure doorbells for snooping, 512 entries, and enable */ | 916 | /* Configure doorbells for snooping, 512 entries, and enable */ |
849 | out_be32((void *)&msg_regs->dmr, 0x00108161); | 917 | out_be32(&priv->msg_regs->dmr, 0x00108161); |
850 | 918 | ||
851 | out: | 919 | out: |
852 | return rc; | 920 | return rc; |
@@ -854,7 +922,7 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) | |||
854 | 922 | ||
855 | static char *cmdline = NULL; | 923 | static char *cmdline = NULL; |
856 | 924 | ||
857 | static int mpc85xx_rio_get_hdid(int index) | 925 | static int fsl_rio_get_hdid(int index) |
858 | { | 926 | { |
859 | /* XXX Need to parse multiple entries in some format */ | 927 | /* XXX Need to parse multiple entries in some format */ |
860 | if (!cmdline) | 928 | if (!cmdline) |
@@ -863,7 +931,7 @@ static int mpc85xx_rio_get_hdid(int index) | |||
863 | return simple_strtol(cmdline, NULL, 0); | 931 | return simple_strtol(cmdline, NULL, 0); |
864 | } | 932 | } |
865 | 933 | ||
866 | static int mpc85xx_rio_get_cmdline(char *s) | 934 | static int fsl_rio_get_cmdline(char *s) |
867 | { | 935 | { |
868 | if (!s) | 936 | if (!s) |
869 | return 0; | 937 | return 0; |
@@ -872,61 +940,266 @@ static int mpc85xx_rio_get_cmdline(char *s) | |||
872 | return 1; | 940 | return 1; |
873 | } | 941 | } |
874 | 942 | ||
875 | __setup("riohdid=", mpc85xx_rio_get_cmdline); | 943 | __setup("riohdid=", fsl_rio_get_cmdline); |
944 | |||
945 | static inline void fsl_rio_info(struct device *dev, u32 ccsr) | ||
946 | { | ||
947 | const char *str; | ||
948 | if (ccsr & 1) { | ||
949 | /* Serial phy */ | ||
950 | switch (ccsr >> 30) { | ||
951 | case 0: | ||
952 | str = "1"; | ||
953 | break; | ||
954 | case 1: | ||
955 | str = "4"; | ||
956 | break; | ||
957 | default: | ||
958 | str = "Unknown"; | ||
959 | break;; | ||
960 | } | ||
961 | dev_info(dev, "Hardware port width: %s\n", str); | ||
962 | |||
963 | switch ((ccsr >> 27) & 7) { | ||
964 | case 0: | ||
965 | str = "Single-lane 0"; | ||
966 | break; | ||
967 | case 1: | ||
968 | str = "Single-lane 2"; | ||
969 | break; | ||
970 | case 2: | ||
971 | str = "Four-lane"; | ||
972 | break; | ||
973 | default: | ||
974 | str = "Unknown"; | ||
975 | break; | ||
976 | } | ||
977 | dev_info(dev, "Training connection status: %s\n", str); | ||
978 | } else { | ||
979 | /* Parallel phy */ | ||
980 | if (!(ccsr & 0x80000000)) | ||
981 | dev_info(dev, "Output port operating in 8-bit mode\n"); | ||
982 | if (!(ccsr & 0x08000000)) | ||
983 | dev_info(dev, "Input port operating in 8-bit mode\n"); | ||
984 | } | ||
985 | } | ||
876 | 986 | ||
877 | /** | 987 | /** |
878 | * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface | 988 | * fsl_rio_setup - Setup MPC85xx RapidIO interface |
879 | * @law_start: Starting physical address of RapidIO LAW | 989 | * @fsl_rio_setup - Setup Freescale PowerPC RapidIO interface |
880 | * @law_size: Size of RapidIO LAW | ||
881 | * | 990 | * |
882 | * Initializes MPC85xx RapidIO hardware interface, configures | 991 | * Initializes MPC85xx RapidIO hardware interface, configures |
883 | * master port with system-specific info, and registers the | 992 | * master port with system-specific info, and registers the |
884 | * master port with the RapidIO subsystem. | 993 | * master port with the RapidIO subsystem. |
885 | */ | 994 | */ |
886 | void mpc85xx_rio_setup(int law_start, int law_size) | 995 | int fsl_rio_setup(struct of_device *dev) |
887 | { | 996 | { |
888 | struct rio_ops *ops; | 997 | struct rio_ops *ops; |
889 | struct rio_mport *port; | 998 | struct rio_mport *port; |
999 | struct rio_priv *priv; | ||
1000 | int rc = 0; | ||
1001 | const u32 *dt_range, *cell; | ||
1002 | struct resource regs; | ||
1003 | int rlen; | ||
1004 | u32 ccsr; | ||
1005 | u64 law_start, law_size; | ||
1006 | int paw, aw, sw; | ||
1007 | |||
1008 | if (!dev->node) { | ||
1009 | dev_err(&dev->dev, "Device OF-Node is NULL"); | ||
1010 | return -EFAULT; | ||
1011 | } | ||
1012 | |||
1013 | rc = of_address_to_resource(dev->node, 0, ®s); | ||
1014 | if (rc) { | ||
1015 | dev_err(&dev->dev, "Can't get %s property 'reg'\n", | ||
1016 | dev->node->full_name); | ||
1017 | return -EFAULT; | ||
1018 | } | ||
1019 | dev_info(&dev->dev, "Of-device full name %s\n", dev->node->full_name); | ||
1020 | dev_info(&dev->dev, "Regs start 0x%08x size 0x%08x\n", regs.start, | ||
1021 | regs.end - regs.start + 1); | ||
1022 | |||
1023 | dt_range = of_get_property(dev->node, "ranges", &rlen); | ||
1024 | if (!dt_range) { | ||
1025 | dev_err(&dev->dev, "Can't get %s property 'ranges'\n", | ||
1026 | dev->node->full_name); | ||
1027 | return -EFAULT; | ||
1028 | } | ||
1029 | |||
1030 | /* Get node address wide */ | ||
1031 | cell = of_get_property(dev->node, "#address-cells", NULL); | ||
1032 | if (cell) | ||
1033 | aw = *cell; | ||
1034 | else | ||
1035 | aw = of_n_addr_cells(dev->node); | ||
1036 | /* Get node size wide */ | ||
1037 | cell = of_get_property(dev->node, "#size-cells", NULL); | ||
1038 | if (cell) | ||
1039 | sw = *cell; | ||
1040 | else | ||
1041 | sw = of_n_size_cells(dev->node); | ||
1042 | /* Get parent address wide wide */ | ||
1043 | paw = of_n_addr_cells(dev->node); | ||
1044 | |||
1045 | law_start = of_read_number(dt_range + aw, paw); | ||
1046 | law_size = of_read_number(dt_range + aw + paw, sw); | ||
1047 | |||
1048 | dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n", | ||
1049 | law_start, law_size); | ||
890 | 1050 | ||
891 | ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL); | 1051 | ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL); |
892 | ops->lcread = mpc85xx_local_config_read; | 1052 | ops->lcread = fsl_local_config_read; |
893 | ops->lcwrite = mpc85xx_local_config_write; | 1053 | ops->lcwrite = fsl_local_config_write; |
894 | ops->cread = mpc85xx_rio_config_read; | 1054 | ops->cread = fsl_rio_config_read; |
895 | ops->cwrite = mpc85xx_rio_config_write; | 1055 | ops->cwrite = fsl_rio_config_write; |
896 | ops->dsend = mpc85xx_rio_doorbell_send; | 1056 | ops->dsend = fsl_rio_doorbell_send; |
897 | 1057 | ||
898 | port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL); | 1058 | port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); |
899 | port->id = 0; | 1059 | port->id = 0; |
900 | port->index = 0; | 1060 | port->index = 0; |
1061 | |||
1062 | priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); | ||
1063 | if (!priv) { | ||
1064 | printk(KERN_ERR "Can't alloc memory for 'priv'\n"); | ||
1065 | rc = -ENOMEM; | ||
1066 | goto err; | ||
1067 | } | ||
1068 | |||
901 | INIT_LIST_HEAD(&port->dbells); | 1069 | INIT_LIST_HEAD(&port->dbells); |
902 | port->iores.start = law_start; | 1070 | port->iores.start = law_start; |
903 | port->iores.end = law_start + law_size; | 1071 | port->iores.end = law_start + law_size; |
904 | port->iores.flags = IORESOURCE_MEM; | 1072 | port->iores.flags = IORESOURCE_MEM; |
905 | 1073 | ||
1074 | priv->bellirq = irq_of_parse_and_map(dev->node, 2); | ||
1075 | priv->txirq = irq_of_parse_and_map(dev->node, 3); | ||
1076 | priv->rxirq = irq_of_parse_and_map(dev->node, 4); | ||
1077 | dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq, | ||
1078 | priv->txirq, priv->rxirq); | ||
1079 | |||
906 | rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); | 1080 | rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); |
907 | rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); | 1081 | rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); |
908 | rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); | 1082 | rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); |
909 | strcpy(port->name, "RIO0 mport"); | 1083 | strcpy(port->name, "RIO0 mport"); |
910 | 1084 | ||
911 | port->ops = ops; | 1085 | port->ops = ops; |
912 | port->host_deviceid = mpc85xx_rio_get_hdid(port->id); | 1086 | port->host_deviceid = fsl_rio_get_hdid(port->id); |
913 | 1087 | ||
1088 | port->priv = priv; | ||
914 | rio_register_mport(port); | 1089 | rio_register_mport(port); |
915 | 1090 | ||
916 | regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000); | 1091 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); |
917 | atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET); | 1092 | |
918 | maint_atmu_regs = atmu_regs + 1; | 1093 | /* Probe the master port phy type */ |
919 | dbell_atmu_regs = atmu_regs + 2; | 1094 | ccsr = in_be32(priv->regs_win + RIO_CCSR); |
920 | msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET); | 1095 | port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL; |
1096 | dev_info(&dev->dev, "RapidIO PHY type: %s\n", | ||
1097 | (port->phy_type == RIO_PHY_PARALLEL) ? "parallel" : | ||
1098 | ((port->phy_type == RIO_PHY_SERIAL) ? "serial" : | ||
1099 | "unknown")); | ||
1100 | /* Checking the port training status */ | ||
1101 | if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) { | ||
1102 | dev_err(&dev->dev, "Port is not ready. " | ||
1103 | "Try to restart connection...\n"); | ||
1104 | switch (port->phy_type) { | ||
1105 | case RIO_PHY_SERIAL: | ||
1106 | /* Disable ports */ | ||
1107 | out_be32(priv->regs_win + RIO_CCSR, 0); | ||
1108 | /* Set 1x lane */ | ||
1109 | setbits32(priv->regs_win + RIO_CCSR, 0x02000000); | ||
1110 | /* Enable ports */ | ||
1111 | setbits32(priv->regs_win + RIO_CCSR, 0x00600000); | ||
1112 | break; | ||
1113 | case RIO_PHY_PARALLEL: | ||
1114 | /* Disable ports */ | ||
1115 | out_be32(priv->regs_win + RIO_CCSR, 0x22000000); | ||
1116 | /* Enable ports */ | ||
1117 | out_be32(priv->regs_win + RIO_CCSR, 0x44000000); | ||
1118 | break; | ||
1119 | } | ||
1120 | msleep(100); | ||
1121 | if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) { | ||
1122 | dev_err(&dev->dev, "Port restart failed.\n"); | ||
1123 | rc = -ENOLINK; | ||
1124 | goto err; | ||
1125 | } | ||
1126 | dev_info(&dev->dev, "Port restart success!\n"); | ||
1127 | } | ||
1128 | fsl_rio_info(&dev->dev, ccsr); | ||
1129 | |||
1130 | port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR)) | ||
1131 | & RIO_PEF_CTLS) >> 4; | ||
1132 | dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", | ||
1133 | port->sys_size ? 65536 : 256); | ||
1134 | |||
1135 | priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win | ||
1136 | + RIO_ATMU_REGS_OFFSET); | ||
1137 | priv->maint_atmu_regs = priv->atmu_regs + 1; | ||
1138 | priv->dbell_atmu_regs = priv->atmu_regs + 2; | ||
1139 | priv->msg_regs = (struct rio_msg_regs *)(priv->regs_win + | ||
1140 | ((port->phy_type == RIO_PHY_SERIAL) ? | ||
1141 | RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET)); | ||
1142 | |||
1143 | /* Set to receive any dist ID for serial RapidIO controller. */ | ||
1144 | if (port->phy_type == RIO_PHY_SERIAL) | ||
1145 | out_be32((priv->regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA); | ||
921 | 1146 | ||
922 | /* Configure maintenance transaction window */ | 1147 | /* Configure maintenance transaction window */ |
923 | out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000); | 1148 | out_be32(&priv->maint_atmu_regs->rowbar, 0x000c0000); |
924 | out_be32((void *)&maint_atmu_regs->rowar, 0x80077015); | 1149 | out_be32(&priv->maint_atmu_regs->rowar, 0x80077015); |
925 | 1150 | ||
926 | maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE); | 1151 | priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE); |
927 | 1152 | ||
928 | /* Configure outbound doorbell window */ | 1153 | /* Configure outbound doorbell window */ |
929 | out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400); | 1154 | out_be32(&priv->dbell_atmu_regs->rowbar, 0x000c0400); |
930 | out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b); | 1155 | out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); |
931 | mpc85xx_rio_doorbell_init(port); | 1156 | fsl_rio_doorbell_init(port); |
1157 | |||
1158 | return 0; | ||
1159 | err: | ||
1160 | if (priv) | ||
1161 | iounmap(priv->regs_win); | ||
1162 | kfree(ops); | ||
1163 | kfree(priv); | ||
1164 | kfree(port); | ||
1165 | return rc; | ||
1166 | } | ||
1167 | |||
1168 | /* The probe function for RapidIO peer-to-peer network. | ||
1169 | */ | ||
1170 | static int __devinit fsl_of_rio_rpn_probe(struct of_device *dev, | ||
1171 | const struct of_device_id *match) | ||
1172 | { | ||
1173 | int rc; | ||
1174 | printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n", | ||
1175 | dev->node->full_name); | ||
1176 | |||
1177 | rc = fsl_rio_setup(dev); | ||
1178 | if (rc) | ||
1179 | goto out; | ||
1180 | |||
1181 | /* Enumerate all registered ports */ | ||
1182 | rc = rio_init_mports(); | ||
1183 | out: | ||
1184 | return rc; | ||
1185 | }; | ||
1186 | |||
1187 | static const struct of_device_id fsl_of_rio_rpn_ids[] = { | ||
1188 | { | ||
1189 | .compatible = "fsl,rapidio-delta", | ||
1190 | }, | ||
1191 | {}, | ||
1192 | }; | ||
1193 | |||
1194 | static struct of_platform_driver fsl_of_rio_rpn_driver = { | ||
1195 | .name = "fsl-of-rio", | ||
1196 | .match_table = fsl_of_rio_rpn_ids, | ||
1197 | .probe = fsl_of_rio_rpn_probe, | ||
1198 | }; | ||
1199 | |||
1200 | static __init int fsl_of_rio_rpn_init(void) | ||
1201 | { | ||
1202 | return of_register_platform_driver(&fsl_of_rio_rpn_driver); | ||
932 | } | 1203 | } |
1204 | |||
1205 | subsys_initcall(fsl_of_rio_rpn_init); | ||
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h deleted file mode 100644 index 6d3ff30b1579..000000000000 --- a/arch/powerpc/sysdev/fsl_rio.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* | ||
2 | * MPC85xx RapidIO definitions | ||
3 | * | ||
4 | * Copyright 2005 MontaVista Software, Inc. | ||
5 | * Matt Porter <mporter@kernel.crashing.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef __PPC_SYSLIB_PPC85XX_RIO_H | ||
14 | #define __PPC_SYSLIB_PPC85XX_RIO_H | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | |||
18 | extern void mpc85xx_rio_setup(int law_start, int law_size); | ||
19 | |||
20 | #endif /* __PPC_SYSLIB_PPC85XX_RIO_H */ | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 5c1b246aaccc..7b45670c7af3 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -892,3 +892,44 @@ void fsl_rstcr_restart(char *cmd) | |||
892 | while (1) ; | 892 | while (1) ; |
893 | } | 893 | } |
894 | #endif | 894 | #endif |
895 | |||
896 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) | ||
897 | struct platform_diu_data_ops diu_ops = { | ||
898 | .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */ | ||
899 | }; | ||
900 | EXPORT_SYMBOL(diu_ops); | ||
901 | |||
902 | int __init preallocate_diu_videomemory(void) | ||
903 | { | ||
904 | pr_debug("diu_size=%lu\n", diu_ops.diu_size); | ||
905 | |||
906 | diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0); | ||
907 | if (!diu_ops.diu_mem) { | ||
908 | printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n", | ||
909 | diu_ops.diu_size); | ||
910 | return -ENOMEM; | ||
911 | } | ||
912 | |||
913 | pr_debug("diu_mem=%p\n", diu_ops.diu_mem); | ||
914 | |||
915 | rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block), | ||
916 | diu_ops.diu_rh_block); | ||
917 | return rh_attach_region(&diu_ops.diu_rh_info, | ||
918 | (unsigned long) diu_ops.diu_mem, | ||
919 | diu_ops.diu_size); | ||
920 | } | ||
921 | |||
922 | static int __init early_parse_diufb(char *p) | ||
923 | { | ||
924 | if (!p) | ||
925 | return 1; | ||
926 | |||
927 | diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8); | ||
928 | |||
929 | pr_debug("diu_size=%lu\n", diu_ops.diu_size); | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | early_param("diufb", early_parse_diufb); | ||
934 | |||
935 | #endif | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 74c4a9657b33..52c831fa1886 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h | |||
@@ -17,5 +17,28 @@ extern int fsl_spi_init(struct spi_board_info *board_infos, | |||
17 | void (*deactivate_cs)(u8 cs, u8 polarity)); | 17 | void (*deactivate_cs)(u8 cs, u8 polarity)); |
18 | 18 | ||
19 | extern void fsl_rstcr_restart(char *cmd); | 19 | extern void fsl_rstcr_restart(char *cmd); |
20 | |||
21 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) | ||
22 | #include <linux/bootmem.h> | ||
23 | #include <asm/rheap.h> | ||
24 | struct platform_diu_data_ops { | ||
25 | rh_block_t diu_rh_block[16]; | ||
26 | rh_info_t diu_rh_info; | ||
27 | unsigned long diu_size; | ||
28 | void *diu_mem; | ||
29 | |||
30 | unsigned int (*get_pixel_format) (unsigned int bits_per_pixel, | ||
31 | int monitor_port); | ||
32 | void (*set_gamma_table) (int monitor_port, char *gamma_table_base); | ||
33 | void (*set_monitor_port) (int monitor_port); | ||
34 | void (*set_pixel_clock) (unsigned int pixclock); | ||
35 | ssize_t (*show_monitor_port) (int monitor_port, char *buf); | ||
36 | int (*set_sysfs_monitor_port) (int val); | ||
37 | }; | ||
38 | |||
39 | extern struct platform_diu_data_ops diu_ops; | ||
40 | int __init preallocate_diu_videomemory(void); | ||
41 | #endif | ||
42 | |||
20 | #endif | 43 | #endif |
21 | #endif | 44 | #endif |
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index a51a17714231..8dcbdd6c2d2c 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/suspend.h> | 18 | #include <linux/suspend.h> |
19 | #include <linux/mman.h> | 19 | #include <linux/mman.h> |
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/kbuild.h> | ||
22 | |||
21 | #include <asm/io.h> | 23 | #include <asm/io.h> |
22 | #include <asm/page.h> | 24 | #include <asm/page.h> |
23 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
@@ -26,11 +28,6 @@ | |||
26 | #include <asm/thread_info.h> | 28 | #include <asm/thread_info.h> |
27 | #include <asm/vdso_datapage.h> | 29 | #include <asm/vdso_datapage.h> |
28 | 30 | ||
29 | #define DEFINE(sym, val) \ | ||
30 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
31 | |||
32 | #define BLANK() asm volatile("\n->" : : ) | ||
33 | |||
34 | int | 31 | int |
35 | main(void) | 32 | main(void) |
36 | { | 33 | { |
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 50ce83f20adb..df3ef6db072c 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c | |||
@@ -1121,8 +1121,8 @@ void __init pci_init_resource(struct resource *res, resource_size_t start, | |||
1121 | 1121 | ||
1122 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) | 1122 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) |
1123 | { | 1123 | { |
1124 | unsigned long start = pci_resource_start(dev, bar); | 1124 | resource_size_t start = pci_resource_start(dev, bar); |
1125 | unsigned long len = pci_resource_len(dev, bar); | 1125 | resource_size_t len = pci_resource_len(dev, bar); |
1126 | unsigned long flags = pci_resource_flags(dev, bar); | 1126 | unsigned long flags = pci_resource_flags(dev, bar); |
1127 | 1127 | ||
1128 | if (!len) | 1128 | if (!len) |
diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c index 0df6aacb8237..24f6e0694ac1 100644 --- a/arch/ppc/platforms/sbc82xx.c +++ b/arch/ppc/platforms/sbc82xx.c | |||
@@ -30,8 +30,6 @@ static void (*callback_init_IRQ)(void); | |||
30 | 30 | ||
31 | extern unsigned char __res[sizeof(bd_t)]; | 31 | extern unsigned char __res[sizeof(bd_t)]; |
32 | 32 | ||
33 | extern void (*late_time_init)(void); | ||
34 | |||
35 | #ifdef CONFIG_GEN_RTC | 33 | #ifdef CONFIG_GEN_RTC |
36 | TODC_ALLOC(); | 34 | TODC_ALLOC(); |
37 | 35 | ||
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f6a68e178fc5..8f5f02160ffc 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -62,6 +62,10 @@ config GENERIC_LOCKBREAK | |||
62 | default y | 62 | default y |
63 | depends on SMP && PREEMPT | 63 | depends on SMP && PREEMPT |
64 | 64 | ||
65 | config PGSTE | ||
66 | bool | ||
67 | default y if KVM | ||
68 | |||
65 | mainmenu "Linux Kernel Configuration" | 69 | mainmenu "Linux Kernel Configuration" |
66 | 70 | ||
67 | config S390 | 71 | config S390 |
@@ -69,6 +73,7 @@ config S390 | |||
69 | select HAVE_OPROFILE | 73 | select HAVE_OPROFILE |
70 | select HAVE_KPROBES | 74 | select HAVE_KPROBES |
71 | select HAVE_KRETPROBES | 75 | select HAVE_KRETPROBES |
76 | select HAVE_KVM if 64BIT | ||
72 | 77 | ||
73 | source "init/Kconfig" | 78 | source "init/Kconfig" |
74 | 79 | ||
@@ -515,6 +520,13 @@ config ZFCPDUMP | |||
515 | Select this option if you want to build an zfcpdump enabled kernel. | 520 | Select this option if you want to build an zfcpdump enabled kernel. |
516 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. | 521 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. |
517 | 522 | ||
523 | config S390_GUEST | ||
524 | bool "s390 guest support (EXPERIMENTAL)" | ||
525 | depends on 64BIT && EXPERIMENTAL | ||
526 | select VIRTIO | ||
527 | select VIRTIO_RING | ||
528 | help | ||
529 | Select this option if you want to run the kernel under s390 linux | ||
518 | endmenu | 530 | endmenu |
519 | 531 | ||
520 | source "net/Kconfig" | 532 | source "net/Kconfig" |
@@ -536,3 +548,5 @@ source "security/Kconfig" | |||
536 | source "crypto/Kconfig" | 548 | source "crypto/Kconfig" |
537 | 549 | ||
538 | source "lib/Kconfig" | 550 | source "lib/Kconfig" |
551 | |||
552 | source "arch/s390/kvm/Kconfig" | ||
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index f708be367b03..792a4e7743ce 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
@@ -87,7 +87,7 @@ LDFLAGS_vmlinux := -e start | |||
87 | head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o | 87 | head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o |
88 | 88 | ||
89 | core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ | 89 | core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ |
90 | arch/s390/appldata/ arch/s390/hypfs/ | 90 | arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ |
91 | libs-y += arch/s390/lib/ | 91 | libs-y += arch/s390/lib/ |
92 | drivers-y += drivers/s390/ | 92 | drivers-y += drivers/s390/ |
93 | drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ | 93 | drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 1375f8a4469e..fa28ecae636b 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -5,44 +5,38 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | 8 | #include <linux/kbuild.h> | |
9 | /* Use marker if you need to separate the values later */ | ||
10 | |||
11 | #define DEFINE(sym, val, marker) \ | ||
12 | asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val)) | ||
13 | |||
14 | #define BLANK() asm volatile("\n->" : : ) | ||
15 | 9 | ||
16 | int main(void) | 10 | int main(void) |
17 | { | 11 | { |
18 | DEFINE(__THREAD_info, offsetof(struct task_struct, stack),); | 12 | DEFINE(__THREAD_info, offsetof(struct task_struct, stack)); |
19 | DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),); | 13 | DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp)); |
20 | DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),); | 14 | DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info)); |
21 | DEFINE(__THREAD_mm_segment, | 15 | DEFINE(__THREAD_mm_segment, |
22 | offsetof(struct task_struct, thread.mm_segment),); | 16 | offsetof(struct task_struct, thread.mm_segment)); |
23 | BLANK(); | 17 | BLANK(); |
24 | DEFINE(__TASK_pid, offsetof(struct task_struct, pid),); | 18 | DEFINE(__TASK_pid, offsetof(struct task_struct, pid)); |
25 | BLANK(); | 19 | BLANK(); |
26 | DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),); | 20 | DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid)); |
27 | DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),); | 21 | DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address)); |
28 | DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),); | 22 | DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id)); |
29 | BLANK(); | 23 | BLANK(); |
30 | DEFINE(__TI_task, offsetof(struct thread_info, task),); | 24 | DEFINE(__TI_task, offsetof(struct thread_info, task)); |
31 | DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),); | 25 | DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain)); |
32 | DEFINE(__TI_flags, offsetof(struct thread_info, flags),); | 26 | DEFINE(__TI_flags, offsetof(struct thread_info, flags)); |
33 | DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),); | 27 | DEFINE(__TI_cpu, offsetof(struct thread_info, cpu)); |
34 | DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),); | 28 | DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count)); |
35 | BLANK(); | 29 | BLANK(); |
36 | DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),); | 30 | DEFINE(__PT_ARGS, offsetof(struct pt_regs, args)); |
37 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),); | 31 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); |
38 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),); | 32 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); |
39 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),); | 33 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); |
40 | DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),); | 34 | DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc)); |
41 | DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),); | 35 | DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap)); |
42 | DEFINE(__PT_SIZE, sizeof(struct pt_regs),); | 36 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); |
43 | BLANK(); | 37 | BLANK(); |
44 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),); | 38 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); |
45 | DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),); | 39 | DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs)); |
46 | DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),); | 40 | DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1)); |
47 | return 0; | 41 | return 0; |
48 | } | 42 | } |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 540a67f979b6..68ec4083bf73 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -144,6 +144,10 @@ static noinline __init void detect_machine_type(void) | |||
144 | /* Running on a P/390 ? */ | 144 | /* Running on a P/390 ? */ |
145 | if (cpuinfo->cpu_id.machine == 0x7490) | 145 | if (cpuinfo->cpu_id.machine == 0x7490) |
146 | machine_flags |= 4; | 146 | machine_flags |= 4; |
147 | |||
148 | /* Running under KVM ? */ | ||
149 | if (cpuinfo->cpu_id.version == 0xfe) | ||
150 | machine_flags |= 64; | ||
147 | } | 151 | } |
148 | 152 | ||
149 | #ifdef CONFIG_64BIT | 153 | #ifdef CONFIG_64BIT |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index c36d8123ca14..c59a86dca584 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -60,8 +60,6 @@ init_IRQ(void) | |||
60 | /* | 60 | /* |
61 | * Switch to the asynchronous interrupt stack for softirq execution. | 61 | * Switch to the asynchronous interrupt stack for softirq execution. |
62 | */ | 62 | */ |
63 | extern void __do_softirq(void); | ||
64 | |||
65 | asmlinkage void do_softirq(void) | 63 | asmlinkage void do_softirq(void) |
66 | { | 64 | { |
67 | unsigned long flags, old, new; | 65 | unsigned long flags, old, new; |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 7141147e6b63..a9d18aafa5f4 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -316,7 +316,11 @@ static int __init early_parse_ipldelay(char *p) | |||
316 | early_param("ipldelay", early_parse_ipldelay); | 316 | early_param("ipldelay", early_parse_ipldelay); |
317 | 317 | ||
318 | #ifdef CONFIG_S390_SWITCH_AMODE | 318 | #ifdef CONFIG_S390_SWITCH_AMODE |
319 | #ifdef CONFIG_PGSTE | ||
320 | unsigned int switch_amode = 1; | ||
321 | #else | ||
319 | unsigned int switch_amode = 0; | 322 | unsigned int switch_amode = 0; |
323 | #endif | ||
320 | EXPORT_SYMBOL_GPL(switch_amode); | 324 | EXPORT_SYMBOL_GPL(switch_amode); |
321 | 325 | ||
322 | static void set_amode_and_uaccess(unsigned long user_amode, | 326 | static void set_amode_and_uaccess(unsigned long user_amode, |
@@ -797,9 +801,13 @@ setup_arch(char **cmdline_p) | |||
797 | "This machine has an IEEE fpu\n" : | 801 | "This machine has an IEEE fpu\n" : |
798 | "This machine has no IEEE fpu\n"); | 802 | "This machine has no IEEE fpu\n"); |
799 | #else /* CONFIG_64BIT */ | 803 | #else /* CONFIG_64BIT */ |
800 | printk((MACHINE_IS_VM) ? | 804 | if (MACHINE_IS_VM) |
801 | "We are running under VM (64 bit mode)\n" : | 805 | printk("We are running under VM (64 bit mode)\n"); |
802 | "We are running native (64 bit mode)\n"); | 806 | else if (MACHINE_IS_KVM) { |
807 | printk("We are running under KVM (64 bit mode)\n"); | ||
808 | add_preferred_console("ttyS", 1, NULL); | ||
809 | } else | ||
810 | printk("We are running native (64 bit mode)\n"); | ||
803 | #endif /* CONFIG_64BIT */ | 811 | #endif /* CONFIG_64BIT */ |
804 | 812 | ||
805 | /* Save unparsed command line copy for /proc/cmdline */ | 813 | /* Save unparsed command line copy for /proc/cmdline */ |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index c5f05b3fb2c3..ca90ee3f930e 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -110,6 +110,7 @@ void account_system_vtime(struct task_struct *tsk) | |||
110 | S390_lowcore.steal_clock -= cputime << 12; | 110 | S390_lowcore.steal_clock -= cputime << 12; |
111 | account_system_time(tsk, 0, cputime); | 111 | account_system_time(tsk, 0, cputime); |
112 | } | 112 | } |
113 | EXPORT_SYMBOL_GPL(account_system_vtime); | ||
113 | 114 | ||
114 | static inline void set_vtimer(__u64 expires) | 115 | static inline void set_vtimer(__u64 expires) |
115 | { | 116 | { |
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig new file mode 100644 index 000000000000..1761b74d639b --- /dev/null +++ b/arch/s390/kvm/Kconfig | |||
@@ -0,0 +1,46 @@ | |||
1 | # | ||
2 | # KVM configuration | ||
3 | # | ||
4 | config HAVE_KVM | ||
5 | bool | ||
6 | |||
7 | menuconfig VIRTUALIZATION | ||
8 | bool "Virtualization" | ||
9 | default y | ||
10 | ---help--- | ||
11 | Say Y here to get to see options for using your Linux host to run other | ||
12 | operating systems inside virtual machines (guests). | ||
13 | This option alone does not add any kernel code. | ||
14 | |||
15 | If you say N, all options in this submenu will be skipped and disabled. | ||
16 | |||
17 | if VIRTUALIZATION | ||
18 | |||
19 | config KVM | ||
20 | tristate "Kernel-based Virtual Machine (KVM) support" | ||
21 | depends on HAVE_KVM && EXPERIMENTAL | ||
22 | select PREEMPT_NOTIFIERS | ||
23 | select ANON_INODES | ||
24 | select S390_SWITCH_AMODE | ||
25 | select PREEMPT | ||
26 | ---help--- | ||
27 | Support hosting paravirtualized guest machines using the SIE | ||
28 | virtualization capability on the mainframe. This should work | ||
29 | on any 64bit machine. | ||
30 | |||
31 | This module provides access to the hardware capabilities through | ||
32 | a character device node named /dev/kvm. | ||
33 | |||
34 | To compile this as a module, choose M here: the module | ||
35 | will be called kvm. | ||
36 | |||
37 | If unsure, say N. | ||
38 | |||
39 | config KVM_TRACE | ||
40 | bool | ||
41 | |||
42 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | ||
43 | # the virtualization menu. | ||
44 | source drivers/virtio/Kconfig | ||
45 | |||
46 | endif # VIRTUALIZATION | ||
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile new file mode 100644 index 000000000000..e5221ec0b8e3 --- /dev/null +++ b/arch/s390/kvm/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # Makefile for kernel virtual machines on s390 | ||
2 | # | ||
3 | # Copyright IBM Corp. 2008 | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License (version 2 only) | ||
7 | # as published by the Free Software Foundation. | ||
8 | |||
9 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) | ||
10 | |||
11 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm | ||
12 | |||
13 | kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o diag.o | ||
14 | obj-$(CONFIG_KVM) += kvm.o | ||
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c new file mode 100644 index 000000000000..f639a152869f --- /dev/null +++ b/arch/s390/kvm/diag.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * diag.c - handling diagnose instructions | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | */ | ||
13 | |||
14 | #include <linux/kvm.h> | ||
15 | #include <linux/kvm_host.h> | ||
16 | #include "kvm-s390.h" | ||
17 | |||
18 | static int __diag_time_slice_end(struct kvm_vcpu *vcpu) | ||
19 | { | ||
20 | VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); | ||
21 | vcpu->stat.diagnose_44++; | ||
22 | vcpu_put(vcpu); | ||
23 | schedule(); | ||
24 | vcpu_load(vcpu); | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | static int __diag_ipl_functions(struct kvm_vcpu *vcpu) | ||
29 | { | ||
30 | unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; | ||
31 | unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff; | ||
32 | |||
33 | VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); | ||
34 | switch (subcode) { | ||
35 | case 3: | ||
36 | vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; | ||
37 | break; | ||
38 | case 4: | ||
39 | vcpu->run->s390_reset_flags = 0; | ||
40 | break; | ||
41 | default: | ||
42 | return -ENOTSUPP; | ||
43 | } | ||
44 | |||
45 | atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | ||
46 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; | ||
47 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; | ||
48 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; | ||
49 | vcpu->run->exit_reason = KVM_EXIT_S390_RESET; | ||
50 | VCPU_EVENT(vcpu, 3, "requesting userspace resets %lx", | ||
51 | vcpu->run->s390_reset_flags); | ||
52 | return -EREMOTE; | ||
53 | } | ||
54 | |||
55 | int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) | ||
56 | { | ||
57 | int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; | ||
58 | |||
59 | switch (code) { | ||
60 | case 0x44: | ||
61 | return __diag_time_slice_end(vcpu); | ||
62 | case 0x308: | ||
63 | return __diag_ipl_functions(vcpu); | ||
64 | default: | ||
65 | return -ENOTSUPP; | ||
66 | } | ||
67 | } | ||
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h new file mode 100644 index 000000000000..4e0633c413f3 --- /dev/null +++ b/arch/s390/kvm/gaccess.h | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * gaccess.h - access guest memory | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #ifndef __KVM_S390_GACCESS_H | ||
14 | #define __KVM_S390_GACCESS_H | ||
15 | |||
16 | #include <linux/compiler.h> | ||
17 | #include <linux/kvm_host.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | |||
20 | static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu, | ||
21 | u64 guestaddr) | ||
22 | { | ||
23 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
24 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
25 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
26 | |||
27 | if (guestaddr < 2 * PAGE_SIZE) | ||
28 | guestaddr += prefix; | ||
29 | else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE)) | ||
30 | guestaddr -= prefix; | ||
31 | |||
32 | if (guestaddr > memsize) | ||
33 | return (void __user __force *) ERR_PTR(-EFAULT); | ||
34 | |||
35 | guestaddr += origin; | ||
36 | |||
37 | return (void __user *) guestaddr; | ||
38 | } | ||
39 | |||
40 | static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
41 | u64 *result) | ||
42 | { | ||
43 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
44 | |||
45 | BUG_ON(guestaddr & 7); | ||
46 | |||
47 | if (IS_ERR((void __force *) uptr)) | ||
48 | return PTR_ERR((void __force *) uptr); | ||
49 | |||
50 | return get_user(*result, (u64 __user *) uptr); | ||
51 | } | ||
52 | |||
53 | static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
54 | u32 *result) | ||
55 | { | ||
56 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
57 | |||
58 | BUG_ON(guestaddr & 3); | ||
59 | |||
60 | if (IS_ERR((void __force *) uptr)) | ||
61 | return PTR_ERR((void __force *) uptr); | ||
62 | |||
63 | return get_user(*result, (u32 __user *) uptr); | ||
64 | } | ||
65 | |||
66 | static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
67 | u16 *result) | ||
68 | { | ||
69 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
70 | |||
71 | BUG_ON(guestaddr & 1); | ||
72 | |||
73 | if (IS_ERR(uptr)) | ||
74 | return PTR_ERR(uptr); | ||
75 | |||
76 | return get_user(*result, (u16 __user *) uptr); | ||
77 | } | ||
78 | |||
79 | static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
80 | u8 *result) | ||
81 | { | ||
82 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
83 | |||
84 | if (IS_ERR((void __force *) uptr)) | ||
85 | return PTR_ERR((void __force *) uptr); | ||
86 | |||
87 | return get_user(*result, (u8 __user *) uptr); | ||
88 | } | ||
89 | |||
90 | static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
91 | u64 value) | ||
92 | { | ||
93 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
94 | |||
95 | BUG_ON(guestaddr & 7); | ||
96 | |||
97 | if (IS_ERR((void __force *) uptr)) | ||
98 | return PTR_ERR((void __force *) uptr); | ||
99 | |||
100 | return put_user(value, (u64 __user *) uptr); | ||
101 | } | ||
102 | |||
103 | static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
104 | u32 value) | ||
105 | { | ||
106 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
107 | |||
108 | BUG_ON(guestaddr & 3); | ||
109 | |||
110 | if (IS_ERR((void __force *) uptr)) | ||
111 | return PTR_ERR((void __force *) uptr); | ||
112 | |||
113 | return put_user(value, (u32 __user *) uptr); | ||
114 | } | ||
115 | |||
116 | static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
117 | u16 value) | ||
118 | { | ||
119 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
120 | |||
121 | BUG_ON(guestaddr & 1); | ||
122 | |||
123 | if (IS_ERR((void __force *) uptr)) | ||
124 | return PTR_ERR((void __force *) uptr); | ||
125 | |||
126 | return put_user(value, (u16 __user *) uptr); | ||
127 | } | ||
128 | |||
129 | static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
130 | u8 value) | ||
131 | { | ||
132 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
133 | |||
134 | if (IS_ERR((void __force *) uptr)) | ||
135 | return PTR_ERR((void __force *) uptr); | ||
136 | |||
137 | return put_user(value, (u8 __user *) uptr); | ||
138 | } | ||
139 | |||
140 | |||
141 | static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest, | ||
142 | const void *from, unsigned long n) | ||
143 | { | ||
144 | int rc; | ||
145 | unsigned long i; | ||
146 | const u8 *data = from; | ||
147 | |||
148 | for (i = 0; i < n; i++) { | ||
149 | rc = put_guest_u8(vcpu, guestdest++, *(data++)); | ||
150 | if (rc < 0) | ||
151 | return rc; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static inline int copy_to_guest(struct kvm_vcpu *vcpu, u64 guestdest, | ||
157 | const void *from, unsigned long n) | ||
158 | { | ||
159 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
160 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
161 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
162 | |||
163 | if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE)) | ||
164 | goto slowpath; | ||
165 | |||
166 | if ((guestdest < prefix) && (guestdest + n > prefix)) | ||
167 | goto slowpath; | ||
168 | |||
169 | if ((guestdest < prefix + 2 * PAGE_SIZE) | ||
170 | && (guestdest + n > prefix + 2 * PAGE_SIZE)) | ||
171 | goto slowpath; | ||
172 | |||
173 | if (guestdest < 2 * PAGE_SIZE) | ||
174 | guestdest += prefix; | ||
175 | else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE)) | ||
176 | guestdest -= prefix; | ||
177 | |||
178 | if (guestdest + n > memsize) | ||
179 | return -EFAULT; | ||
180 | |||
181 | if (guestdest + n < guestdest) | ||
182 | return -EFAULT; | ||
183 | |||
184 | guestdest += origin; | ||
185 | |||
186 | return copy_to_user((void __user *) guestdest, from, n); | ||
187 | slowpath: | ||
188 | return __copy_to_guest_slow(vcpu, guestdest, from, n); | ||
189 | } | ||
190 | |||
191 | static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to, | ||
192 | u64 guestsrc, unsigned long n) | ||
193 | { | ||
194 | int rc; | ||
195 | unsigned long i; | ||
196 | u8 *data = to; | ||
197 | |||
198 | for (i = 0; i < n; i++) { | ||
199 | rc = get_guest_u8(vcpu, guestsrc++, data++); | ||
200 | if (rc < 0) | ||
201 | return rc; | ||
202 | } | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, | ||
207 | u64 guestsrc, unsigned long n) | ||
208 | { | ||
209 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
210 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
211 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
212 | |||
213 | if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) | ||
214 | goto slowpath; | ||
215 | |||
216 | if ((guestsrc < prefix) && (guestsrc + n > prefix)) | ||
217 | goto slowpath; | ||
218 | |||
219 | if ((guestsrc < prefix + 2 * PAGE_SIZE) | ||
220 | && (guestsrc + n > prefix + 2 * PAGE_SIZE)) | ||
221 | goto slowpath; | ||
222 | |||
223 | if (guestsrc < 2 * PAGE_SIZE) | ||
224 | guestsrc += prefix; | ||
225 | else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) | ||
226 | guestsrc -= prefix; | ||
227 | |||
228 | if (guestsrc + n > memsize) | ||
229 | return -EFAULT; | ||
230 | |||
231 | if (guestsrc + n < guestsrc) | ||
232 | return -EFAULT; | ||
233 | |||
234 | guestsrc += origin; | ||
235 | |||
236 | return copy_from_user(to, (void __user *) guestsrc, n); | ||
237 | slowpath: | ||
238 | return __copy_from_guest_slow(vcpu, to, guestsrc, n); | ||
239 | } | ||
240 | |||
241 | static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest, | ||
242 | const void *from, unsigned long n) | ||
243 | { | ||
244 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
245 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
246 | |||
247 | if (guestdest + n > memsize) | ||
248 | return -EFAULT; | ||
249 | |||
250 | if (guestdest + n < guestdest) | ||
251 | return -EFAULT; | ||
252 | |||
253 | guestdest += origin; | ||
254 | |||
255 | return copy_to_user((void __user *) guestdest, from, n); | ||
256 | } | ||
257 | |||
258 | static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to, | ||
259 | u64 guestsrc, unsigned long n) | ||
260 | { | ||
261 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
262 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
263 | |||
264 | if (guestsrc + n > memsize) | ||
265 | return -EFAULT; | ||
266 | |||
267 | if (guestsrc + n < guestsrc) | ||
268 | return -EFAULT; | ||
269 | |||
270 | guestsrc += origin; | ||
271 | |||
272 | return copy_from_user(to, (void __user *) guestsrc, n); | ||
273 | } | ||
274 | #endif | ||
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c new file mode 100644 index 000000000000..349581a26103 --- /dev/null +++ b/arch/s390/kvm/intercept.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * intercept.c - in-kernel handling for sie intercepts | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | */ | ||
13 | |||
14 | #include <linux/kvm_host.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/pagemap.h> | ||
17 | |||
18 | #include <asm/kvm_host.h> | ||
19 | |||
20 | #include "kvm-s390.h" | ||
21 | #include "gaccess.h" | ||
22 | |||
23 | static int handle_lctg(struct kvm_vcpu *vcpu) | ||
24 | { | ||
25 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
26 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
27 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
28 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + | ||
29 | ((vcpu->arch.sie_block->ipb & 0xff00) << 4); | ||
30 | u64 useraddr; | ||
31 | int reg, rc; | ||
32 | |||
33 | vcpu->stat.instruction_lctg++; | ||
34 | if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) | ||
35 | return -ENOTSUPP; | ||
36 | |||
37 | useraddr = disp2; | ||
38 | if (base2) | ||
39 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
40 | |||
41 | reg = reg1; | ||
42 | |||
43 | VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
44 | disp2); | ||
45 | |||
46 | do { | ||
47 | rc = get_guest_u64(vcpu, useraddr, | ||
48 | &vcpu->arch.sie_block->gcr[reg]); | ||
49 | if (rc == -EFAULT) { | ||
50 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
51 | break; | ||
52 | } | ||
53 | useraddr += 8; | ||
54 | if (reg == reg3) | ||
55 | break; | ||
56 | reg = (reg + 1) % 16; | ||
57 | } while (1); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int handle_lctl(struct kvm_vcpu *vcpu) | ||
62 | { | ||
63 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
64 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
65 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
66 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
67 | u64 useraddr; | ||
68 | u32 val = 0; | ||
69 | int reg, rc; | ||
70 | |||
71 | vcpu->stat.instruction_lctl++; | ||
72 | |||
73 | useraddr = disp2; | ||
74 | if (base2) | ||
75 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
76 | |||
77 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
78 | disp2); | ||
79 | |||
80 | reg = reg1; | ||
81 | do { | ||
82 | rc = get_guest_u32(vcpu, useraddr, &val); | ||
83 | if (rc == -EFAULT) { | ||
84 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
85 | break; | ||
86 | } | ||
87 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
88 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
89 | useraddr += 4; | ||
90 | if (reg == reg3) | ||
91 | break; | ||
92 | reg = (reg + 1) % 16; | ||
93 | } while (1); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static intercept_handler_t instruction_handlers[256] = { | ||
98 | [0x83] = kvm_s390_handle_diag, | ||
99 | [0xae] = kvm_s390_handle_sigp, | ||
100 | [0xb2] = kvm_s390_handle_priv, | ||
101 | [0xb7] = handle_lctl, | ||
102 | [0xeb] = handle_lctg, | ||
103 | }; | ||
104 | |||
105 | static int handle_noop(struct kvm_vcpu *vcpu) | ||
106 | { | ||
107 | switch (vcpu->arch.sie_block->icptcode) { | ||
108 | case 0x10: | ||
109 | vcpu->stat.exit_external_request++; | ||
110 | break; | ||
111 | case 0x14: | ||
112 | vcpu->stat.exit_external_interrupt++; | ||
113 | break; | ||
114 | default: | ||
115 | break; /* nothing */ | ||
116 | } | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int handle_stop(struct kvm_vcpu *vcpu) | ||
121 | { | ||
122 | int rc; | ||
123 | |||
124 | vcpu->stat.exit_stop_request++; | ||
125 | atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | ||
126 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
127 | if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { | ||
128 | vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; | ||
129 | rc = __kvm_s390_vcpu_store_status(vcpu, | ||
130 | KVM_S390_STORE_STATUS_NOADDR); | ||
131 | if (rc >= 0) | ||
132 | rc = -ENOTSUPP; | ||
133 | } | ||
134 | |||
135 | if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { | ||
136 | vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; | ||
137 | VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); | ||
138 | rc = -ENOTSUPP; | ||
139 | } else | ||
140 | rc = 0; | ||
141 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
142 | return rc; | ||
143 | } | ||
144 | |||
145 | static int handle_validity(struct kvm_vcpu *vcpu) | ||
146 | { | ||
147 | int viwhy = vcpu->arch.sie_block->ipb >> 16; | ||
148 | vcpu->stat.exit_validity++; | ||
149 | if (viwhy == 0x37) { | ||
150 | fault_in_pages_writeable((char __user *) | ||
151 | vcpu->kvm->arch.guest_origin + | ||
152 | vcpu->arch.sie_block->prefix, | ||
153 | PAGE_SIZE); | ||
154 | return 0; | ||
155 | } | ||
156 | VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", | ||
157 | viwhy); | ||
158 | return -ENOTSUPP; | ||
159 | } | ||
160 | |||
161 | static int handle_instruction(struct kvm_vcpu *vcpu) | ||
162 | { | ||
163 | intercept_handler_t handler; | ||
164 | |||
165 | vcpu->stat.exit_instruction++; | ||
166 | handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; | ||
167 | if (handler) | ||
168 | return handler(vcpu); | ||
169 | return -ENOTSUPP; | ||
170 | } | ||
171 | |||
172 | static int handle_prog(struct kvm_vcpu *vcpu) | ||
173 | { | ||
174 | vcpu->stat.exit_program_interruption++; | ||
175 | return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); | ||
176 | } | ||
177 | |||
178 | static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) | ||
179 | { | ||
180 | int rc, rc2; | ||
181 | |||
182 | vcpu->stat.exit_instr_and_program++; | ||
183 | rc = handle_instruction(vcpu); | ||
184 | rc2 = handle_prog(vcpu); | ||
185 | |||
186 | if (rc == -ENOTSUPP) | ||
187 | vcpu->arch.sie_block->icptcode = 0x04; | ||
188 | if (rc) | ||
189 | return rc; | ||
190 | return rc2; | ||
191 | } | ||
192 | |||
193 | static const intercept_handler_t intercept_funcs[0x48 >> 2] = { | ||
194 | [0x00 >> 2] = handle_noop, | ||
195 | [0x04 >> 2] = handle_instruction, | ||
196 | [0x08 >> 2] = handle_prog, | ||
197 | [0x0C >> 2] = handle_instruction_and_prog, | ||
198 | [0x10 >> 2] = handle_noop, | ||
199 | [0x14 >> 2] = handle_noop, | ||
200 | [0x1C >> 2] = kvm_s390_handle_wait, | ||
201 | [0x20 >> 2] = handle_validity, | ||
202 | [0x28 >> 2] = handle_stop, | ||
203 | }; | ||
204 | |||
205 | int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) | ||
206 | { | ||
207 | intercept_handler_t func; | ||
208 | u8 code = vcpu->arch.sie_block->icptcode; | ||
209 | |||
210 | if (code & 3 || code > 0x48) | ||
211 | return -ENOTSUPP; | ||
212 | func = intercept_funcs[code >> 2]; | ||
213 | if (func) | ||
214 | return func(vcpu); | ||
215 | return -ENOTSUPP; | ||
216 | } | ||
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c new file mode 100644 index 000000000000..fcd1ed8015c1 --- /dev/null +++ b/arch/s390/kvm/interrupt.c | |||
@@ -0,0 +1,592 @@ | |||
1 | /* | ||
2 | * interrupt.c - handling kvm guest interrupts | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #include <asm/lowcore.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <linux/kvm_host.h> | ||
16 | #include "kvm-s390.h" | ||
17 | #include "gaccess.h" | ||
18 | |||
19 | static int psw_extint_disabled(struct kvm_vcpu *vcpu) | ||
20 | { | ||
21 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); | ||
22 | } | ||
23 | |||
24 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) | ||
25 | { | ||
26 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || | ||
27 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) || | ||
28 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT)) | ||
29 | return 0; | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, | ||
34 | struct interrupt_info *inti) | ||
35 | { | ||
36 | switch (inti->type) { | ||
37 | case KVM_S390_INT_EMERGENCY: | ||
38 | if (psw_extint_disabled(vcpu)) | ||
39 | return 0; | ||
40 | if (vcpu->arch.sie_block->gcr[0] & 0x4000ul) | ||
41 | return 1; | ||
42 | return 0; | ||
43 | case KVM_S390_INT_SERVICE: | ||
44 | if (psw_extint_disabled(vcpu)) | ||
45 | return 0; | ||
46 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | ||
47 | return 1; | ||
48 | return 0; | ||
49 | case KVM_S390_INT_VIRTIO: | ||
50 | if (psw_extint_disabled(vcpu)) | ||
51 | return 0; | ||
52 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | ||
53 | return 1; | ||
54 | return 0; | ||
55 | case KVM_S390_PROGRAM_INT: | ||
56 | case KVM_S390_SIGP_STOP: | ||
57 | case KVM_S390_SIGP_SET_PREFIX: | ||
58 | case KVM_S390_RESTART: | ||
59 | return 1; | ||
60 | default: | ||
61 | BUG(); | ||
62 | } | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static void __set_cpu_idle(struct kvm_vcpu *vcpu) | ||
67 | { | ||
68 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | ||
69 | atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | ||
70 | set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | ||
71 | } | ||
72 | |||
73 | static void __unset_cpu_idle(struct kvm_vcpu *vcpu) | ||
74 | { | ||
75 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | ||
76 | atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | ||
77 | clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | ||
78 | } | ||
79 | |||
80 | static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) | ||
81 | { | ||
82 | atomic_clear_mask(CPUSTAT_ECALL_PEND | | ||
83 | CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, | ||
84 | &vcpu->arch.sie_block->cpuflags); | ||
85 | vcpu->arch.sie_block->lctl = 0x0000; | ||
86 | } | ||
87 | |||
88 | static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) | ||
89 | { | ||
90 | atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); | ||
91 | } | ||
92 | |||
93 | static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | ||
94 | struct interrupt_info *inti) | ||
95 | { | ||
96 | switch (inti->type) { | ||
97 | case KVM_S390_INT_EMERGENCY: | ||
98 | case KVM_S390_INT_SERVICE: | ||
99 | case KVM_S390_INT_VIRTIO: | ||
100 | if (psw_extint_disabled(vcpu)) | ||
101 | __set_cpuflag(vcpu, CPUSTAT_EXT_INT); | ||
102 | else | ||
103 | vcpu->arch.sie_block->lctl |= LCTL_CR0; | ||
104 | break; | ||
105 | case KVM_S390_SIGP_STOP: | ||
106 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); | ||
107 | break; | ||
108 | default: | ||
109 | BUG(); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | ||
114 | struct interrupt_info *inti) | ||
115 | { | ||
116 | const unsigned short table[] = { 2, 4, 4, 6 }; | ||
117 | int rc, exception = 0; | ||
118 | |||
119 | switch (inti->type) { | ||
120 | case KVM_S390_INT_EMERGENCY: | ||
121 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); | ||
122 | vcpu->stat.deliver_emergency_signal++; | ||
123 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); | ||
124 | if (rc == -EFAULT) | ||
125 | exception = 1; | ||
126 | |||
127 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
128 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
129 | if (rc == -EFAULT) | ||
130 | exception = 1; | ||
131 | |||
132 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
133 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
134 | if (rc == -EFAULT) | ||
135 | exception = 1; | ||
136 | break; | ||
137 | |||
138 | case KVM_S390_INT_SERVICE: | ||
139 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", | ||
140 | inti->ext.ext_params); | ||
141 | vcpu->stat.deliver_service_signal++; | ||
142 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); | ||
143 | if (rc == -EFAULT) | ||
144 | exception = 1; | ||
145 | |||
146 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
147 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
148 | if (rc == -EFAULT) | ||
149 | exception = 1; | ||
150 | |||
151 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
152 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
153 | if (rc == -EFAULT) | ||
154 | exception = 1; | ||
155 | |||
156 | rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); | ||
157 | if (rc == -EFAULT) | ||
158 | exception = 1; | ||
159 | break; | ||
160 | |||
161 | case KVM_S390_INT_VIRTIO: | ||
162 | VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%lx", | ||
163 | inti->ext.ext_params, inti->ext.ext_params2); | ||
164 | vcpu->stat.deliver_virtio_interrupt++; | ||
165 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); | ||
166 | if (rc == -EFAULT) | ||
167 | exception = 1; | ||
168 | |||
169 | rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00); | ||
170 | if (rc == -EFAULT) | ||
171 | exception = 1; | ||
172 | |||
173 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
174 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
175 | if (rc == -EFAULT) | ||
176 | exception = 1; | ||
177 | |||
178 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
179 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
180 | if (rc == -EFAULT) | ||
181 | exception = 1; | ||
182 | |||
183 | rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); | ||
184 | if (rc == -EFAULT) | ||
185 | exception = 1; | ||
186 | |||
187 | rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM, | ||
188 | inti->ext.ext_params2); | ||
189 | if (rc == -EFAULT) | ||
190 | exception = 1; | ||
191 | break; | ||
192 | |||
193 | case KVM_S390_SIGP_STOP: | ||
194 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); | ||
195 | vcpu->stat.deliver_stop_signal++; | ||
196 | __set_intercept_indicator(vcpu, inti); | ||
197 | break; | ||
198 | |||
199 | case KVM_S390_SIGP_SET_PREFIX: | ||
200 | VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", | ||
201 | inti->prefix.address); | ||
202 | vcpu->stat.deliver_prefix_signal++; | ||
203 | vcpu->arch.sie_block->prefix = inti->prefix.address; | ||
204 | vcpu->arch.sie_block->ihcpu = 0xffff; | ||
205 | break; | ||
206 | |||
207 | case KVM_S390_RESTART: | ||
208 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); | ||
209 | vcpu->stat.deliver_restart_signal++; | ||
210 | rc = copy_to_guest(vcpu, offsetof(struct _lowcore, | ||
211 | restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
212 | if (rc == -EFAULT) | ||
213 | exception = 1; | ||
214 | |||
215 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
216 | offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); | ||
217 | if (rc == -EFAULT) | ||
218 | exception = 1; | ||
219 | break; | ||
220 | |||
221 | case KVM_S390_PROGRAM_INT: | ||
222 | VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", | ||
223 | inti->pgm.code, | ||
224 | table[vcpu->arch.sie_block->ipa >> 14]); | ||
225 | vcpu->stat.deliver_program_int++; | ||
226 | rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); | ||
227 | if (rc == -EFAULT) | ||
228 | exception = 1; | ||
229 | |||
230 | rc = put_guest_u16(vcpu, __LC_PGM_ILC, | ||
231 | table[vcpu->arch.sie_block->ipa >> 14]); | ||
232 | if (rc == -EFAULT) | ||
233 | exception = 1; | ||
234 | |||
235 | rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, | ||
236 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
237 | if (rc == -EFAULT) | ||
238 | exception = 1; | ||
239 | |||
240 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
241 | __LC_PGM_NEW_PSW, sizeof(psw_t)); | ||
242 | if (rc == -EFAULT) | ||
243 | exception = 1; | ||
244 | break; | ||
245 | |||
246 | default: | ||
247 | BUG(); | ||
248 | } | ||
249 | |||
250 | if (exception) { | ||
251 | VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" | ||
252 | " interrupt"); | ||
253 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
254 | if (inti->type == KVM_S390_PROGRAM_INT) { | ||
255 | printk(KERN_WARNING "kvm: recursive program check\n"); | ||
256 | BUG(); | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) | ||
262 | { | ||
263 | int rc, exception = 0; | ||
264 | |||
265 | if (psw_extint_disabled(vcpu)) | ||
266 | return 0; | ||
267 | if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) | ||
268 | return 0; | ||
269 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004); | ||
270 | if (rc == -EFAULT) | ||
271 | exception = 1; | ||
272 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
273 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
274 | if (rc == -EFAULT) | ||
275 | exception = 1; | ||
276 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
277 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
278 | if (rc == -EFAULT) | ||
279 | exception = 1; | ||
280 | |||
281 | if (exception) { | ||
282 | VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \ | ||
283 | " ckc interrupt"); | ||
284 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | return 1; | ||
289 | } | ||
290 | |||
291 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) | ||
292 | { | ||
293 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
294 | struct float_interrupt *fi = vcpu->arch.local_int.float_int; | ||
295 | struct interrupt_info *inti; | ||
296 | int rc = 0; | ||
297 | |||
298 | if (atomic_read(&li->active)) { | ||
299 | spin_lock_bh(&li->lock); | ||
300 | list_for_each_entry(inti, &li->list, list) | ||
301 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
302 | rc = 1; | ||
303 | break; | ||
304 | } | ||
305 | spin_unlock_bh(&li->lock); | ||
306 | } | ||
307 | |||
308 | if ((!rc) && atomic_read(&fi->active)) { | ||
309 | spin_lock_bh(&fi->lock); | ||
310 | list_for_each_entry(inti, &fi->list, list) | ||
311 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
312 | rc = 1; | ||
313 | break; | ||
314 | } | ||
315 | spin_unlock_bh(&fi->lock); | ||
316 | } | ||
317 | |||
318 | if ((!rc) && (vcpu->arch.sie_block->ckc < | ||
319 | get_clock() + vcpu->arch.sie_block->epoch)) { | ||
320 | if ((!psw_extint_disabled(vcpu)) && | ||
321 | (vcpu->arch.sie_block->gcr[0] & 0x800ul)) | ||
322 | rc = 1; | ||
323 | } | ||
324 | |||
325 | return rc; | ||
326 | } | ||
327 | |||
328 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | ||
329 | { | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) | ||
334 | { | ||
335 | u64 now, sltime; | ||
336 | DECLARE_WAITQUEUE(wait, current); | ||
337 | |||
338 | vcpu->stat.exit_wait_state++; | ||
339 | if (kvm_cpu_has_interrupt(vcpu)) | ||
340 | return 0; | ||
341 | |||
342 | if (psw_interrupts_disabled(vcpu)) { | ||
343 | VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); | ||
344 | __unset_cpu_idle(vcpu); | ||
345 | return -ENOTSUPP; /* disabled wait */ | ||
346 | } | ||
347 | |||
348 | if (psw_extint_disabled(vcpu) || | ||
349 | (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) { | ||
350 | VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); | ||
351 | goto no_timer; | ||
352 | } | ||
353 | |||
354 | now = get_clock() + vcpu->arch.sie_block->epoch; | ||
355 | if (vcpu->arch.sie_block->ckc < now) { | ||
356 | __unset_cpu_idle(vcpu); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1; | ||
361 | |||
362 | vcpu->arch.ckc_timer.expires = jiffies + sltime; | ||
363 | |||
364 | add_timer(&vcpu->arch.ckc_timer); | ||
365 | VCPU_EVENT(vcpu, 5, "enabled wait timer:%lx jiffies", sltime); | ||
366 | no_timer: | ||
367 | spin_lock_bh(&vcpu->arch.local_int.float_int->lock); | ||
368 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
369 | __set_cpu_idle(vcpu); | ||
370 | vcpu->arch.local_int.timer_due = 0; | ||
371 | add_wait_queue(&vcpu->arch.local_int.wq, &wait); | ||
372 | while (list_empty(&vcpu->arch.local_int.list) && | ||
373 | list_empty(&vcpu->arch.local_int.float_int->list) && | ||
374 | (!vcpu->arch.local_int.timer_due) && | ||
375 | !signal_pending(current)) { | ||
376 | set_current_state(TASK_INTERRUPTIBLE); | ||
377 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
378 | spin_unlock_bh(&vcpu->arch.local_int.float_int->lock); | ||
379 | vcpu_put(vcpu); | ||
380 | schedule(); | ||
381 | vcpu_load(vcpu); | ||
382 | spin_lock_bh(&vcpu->arch.local_int.float_int->lock); | ||
383 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
384 | } | ||
385 | __unset_cpu_idle(vcpu); | ||
386 | __set_current_state(TASK_RUNNING); | ||
387 | remove_wait_queue(&vcpu->wq, &wait); | ||
388 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
389 | spin_unlock_bh(&vcpu->arch.local_int.float_int->lock); | ||
390 | del_timer(&vcpu->arch.ckc_timer); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | void kvm_s390_idle_wakeup(unsigned long data) | ||
395 | { | ||
396 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; | ||
397 | |||
398 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
399 | vcpu->arch.local_int.timer_due = 1; | ||
400 | if (waitqueue_active(&vcpu->arch.local_int.wq)) | ||
401 | wake_up_interruptible(&vcpu->arch.local_int.wq); | ||
402 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
403 | } | ||
404 | |||
405 | |||
406 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | ||
407 | { | ||
408 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
409 | struct float_interrupt *fi = vcpu->arch.local_int.float_int; | ||
410 | struct interrupt_info *n, *inti = NULL; | ||
411 | int deliver; | ||
412 | |||
413 | __reset_intercept_indicators(vcpu); | ||
414 | if (atomic_read(&li->active)) { | ||
415 | do { | ||
416 | deliver = 0; | ||
417 | spin_lock_bh(&li->lock); | ||
418 | list_for_each_entry_safe(inti, n, &li->list, list) { | ||
419 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
420 | list_del(&inti->list); | ||
421 | deliver = 1; | ||
422 | break; | ||
423 | } | ||
424 | __set_intercept_indicator(vcpu, inti); | ||
425 | } | ||
426 | if (list_empty(&li->list)) | ||
427 | atomic_set(&li->active, 0); | ||
428 | spin_unlock_bh(&li->lock); | ||
429 | if (deliver) { | ||
430 | __do_deliver_interrupt(vcpu, inti); | ||
431 | kfree(inti); | ||
432 | } | ||
433 | } while (deliver); | ||
434 | } | ||
435 | |||
436 | if ((vcpu->arch.sie_block->ckc < | ||
437 | get_clock() + vcpu->arch.sie_block->epoch)) | ||
438 | __try_deliver_ckc_interrupt(vcpu); | ||
439 | |||
440 | if (atomic_read(&fi->active)) { | ||
441 | do { | ||
442 | deliver = 0; | ||
443 | spin_lock_bh(&fi->lock); | ||
444 | list_for_each_entry_safe(inti, n, &fi->list, list) { | ||
445 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
446 | list_del(&inti->list); | ||
447 | deliver = 1; | ||
448 | break; | ||
449 | } | ||
450 | __set_intercept_indicator(vcpu, inti); | ||
451 | } | ||
452 | if (list_empty(&fi->list)) | ||
453 | atomic_set(&fi->active, 0); | ||
454 | spin_unlock_bh(&fi->lock); | ||
455 | if (deliver) { | ||
456 | __do_deliver_interrupt(vcpu, inti); | ||
457 | kfree(inti); | ||
458 | } | ||
459 | } while (deliver); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) | ||
464 | { | ||
465 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
466 | struct interrupt_info *inti; | ||
467 | |||
468 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
469 | if (!inti) | ||
470 | return -ENOMEM; | ||
471 | |||
472 | inti->type = KVM_S390_PROGRAM_INT;; | ||
473 | inti->pgm.code = code; | ||
474 | |||
475 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); | ||
476 | spin_lock_bh(&li->lock); | ||
477 | list_add(&inti->list, &li->list); | ||
478 | atomic_set(&li->active, 1); | ||
479 | BUG_ON(waitqueue_active(&li->wq)); | ||
480 | spin_unlock_bh(&li->lock); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | int kvm_s390_inject_vm(struct kvm *kvm, | ||
485 | struct kvm_s390_interrupt *s390int) | ||
486 | { | ||
487 | struct local_interrupt *li; | ||
488 | struct float_interrupt *fi; | ||
489 | struct interrupt_info *inti; | ||
490 | int sigcpu; | ||
491 | |||
492 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
493 | if (!inti) | ||
494 | return -ENOMEM; | ||
495 | |||
496 | switch (s390int->type) { | ||
497 | case KVM_S390_INT_VIRTIO: | ||
498 | VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%lx", | ||
499 | s390int->parm, s390int->parm64); | ||
500 | inti->type = s390int->type; | ||
501 | inti->ext.ext_params = s390int->parm; | ||
502 | inti->ext.ext_params2 = s390int->parm64; | ||
503 | break; | ||
504 | case KVM_S390_INT_SERVICE: | ||
505 | VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm); | ||
506 | inti->type = s390int->type; | ||
507 | inti->ext.ext_params = s390int->parm; | ||
508 | break; | ||
509 | case KVM_S390_PROGRAM_INT: | ||
510 | case KVM_S390_SIGP_STOP: | ||
511 | case KVM_S390_INT_EMERGENCY: | ||
512 | default: | ||
513 | kfree(inti); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | mutex_lock(&kvm->lock); | ||
518 | fi = &kvm->arch.float_int; | ||
519 | spin_lock_bh(&fi->lock); | ||
520 | list_add_tail(&inti->list, &fi->list); | ||
521 | atomic_set(&fi->active, 1); | ||
522 | sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); | ||
523 | if (sigcpu == KVM_MAX_VCPUS) { | ||
524 | do { | ||
525 | sigcpu = fi->next_rr_cpu++; | ||
526 | if (sigcpu == KVM_MAX_VCPUS) | ||
527 | sigcpu = fi->next_rr_cpu = 0; | ||
528 | } while (fi->local_int[sigcpu] == NULL); | ||
529 | } | ||
530 | li = fi->local_int[sigcpu]; | ||
531 | spin_lock_bh(&li->lock); | ||
532 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
533 | if (waitqueue_active(&li->wq)) | ||
534 | wake_up_interruptible(&li->wq); | ||
535 | spin_unlock_bh(&li->lock); | ||
536 | spin_unlock_bh(&fi->lock); | ||
537 | mutex_unlock(&kvm->lock); | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | ||
542 | struct kvm_s390_interrupt *s390int) | ||
543 | { | ||
544 | struct local_interrupt *li; | ||
545 | struct interrupt_info *inti; | ||
546 | |||
547 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
548 | if (!inti) | ||
549 | return -ENOMEM; | ||
550 | |||
551 | switch (s390int->type) { | ||
552 | case KVM_S390_PROGRAM_INT: | ||
553 | if (s390int->parm & 0xffff0000) { | ||
554 | kfree(inti); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | inti->type = s390int->type; | ||
558 | inti->pgm.code = s390int->parm; | ||
559 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", | ||
560 | s390int->parm); | ||
561 | break; | ||
562 | case KVM_S390_SIGP_STOP: | ||
563 | case KVM_S390_RESTART: | ||
564 | case KVM_S390_SIGP_SET_PREFIX: | ||
565 | case KVM_S390_INT_EMERGENCY: | ||
566 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | ||
567 | inti->type = s390int->type; | ||
568 | break; | ||
569 | case KVM_S390_INT_VIRTIO: | ||
570 | case KVM_S390_INT_SERVICE: | ||
571 | default: | ||
572 | kfree(inti); | ||
573 | return -EINVAL; | ||
574 | } | ||
575 | |||
576 | mutex_lock(&vcpu->kvm->lock); | ||
577 | li = &vcpu->arch.local_int; | ||
578 | spin_lock_bh(&li->lock); | ||
579 | if (inti->type == KVM_S390_PROGRAM_INT) | ||
580 | list_add(&inti->list, &li->list); | ||
581 | else | ||
582 | list_add_tail(&inti->list, &li->list); | ||
583 | atomic_set(&li->active, 1); | ||
584 | if (inti->type == KVM_S390_SIGP_STOP) | ||
585 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
586 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
587 | if (waitqueue_active(&li->wq)) | ||
588 | wake_up_interruptible(&vcpu->arch.local_int.wq); | ||
589 | spin_unlock_bh(&li->lock); | ||
590 | mutex_unlock(&vcpu->kvm->lock); | ||
591 | return 0; | ||
592 | } | ||
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c new file mode 100644 index 000000000000..98d1e73e01f1 --- /dev/null +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -0,0 +1,685 @@ | |||
1 | /* | ||
2 | * s390host.c -- hosting zSeries kernel virtual machines | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | * Heiko Carstens <heiko.carstens@de.ibm.com> | ||
13 | */ | ||
14 | |||
15 | #include <linux/compiler.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/kvm.h> | ||
20 | #include <linux/kvm_host.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <asm/lowcore.h> | ||
25 | #include <asm/pgtable.h> | ||
26 | |||
27 | #include "kvm-s390.h" | ||
28 | #include "gaccess.h" | ||
29 | |||
30 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | ||
31 | |||
32 | struct kvm_stats_debugfs_item debugfs_entries[] = { | ||
33 | { "userspace_handled", VCPU_STAT(exit_userspace) }, | ||
34 | { "exit_validity", VCPU_STAT(exit_validity) }, | ||
35 | { "exit_stop_request", VCPU_STAT(exit_stop_request) }, | ||
36 | { "exit_external_request", VCPU_STAT(exit_external_request) }, | ||
37 | { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, | ||
38 | { "exit_instruction", VCPU_STAT(exit_instruction) }, | ||
39 | { "exit_program_interruption", VCPU_STAT(exit_program_interruption) }, | ||
40 | { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, | ||
41 | { "instruction_lctg", VCPU_STAT(instruction_lctg) }, | ||
42 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | ||
43 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | ||
44 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | ||
45 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, | ||
46 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, | ||
47 | { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, | ||
48 | { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, | ||
49 | { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, | ||
50 | { "exit_wait_state", VCPU_STAT(exit_wait_state) }, | ||
51 | { "instruction_stidp", VCPU_STAT(instruction_stidp) }, | ||
52 | { "instruction_spx", VCPU_STAT(instruction_spx) }, | ||
53 | { "instruction_stpx", VCPU_STAT(instruction_stpx) }, | ||
54 | { "instruction_stap", VCPU_STAT(instruction_stap) }, | ||
55 | { "instruction_storage_key", VCPU_STAT(instruction_storage_key) }, | ||
56 | { "instruction_stsch", VCPU_STAT(instruction_stsch) }, | ||
57 | { "instruction_chsc", VCPU_STAT(instruction_chsc) }, | ||
58 | { "instruction_stsi", VCPU_STAT(instruction_stsi) }, | ||
59 | { "instruction_stfl", VCPU_STAT(instruction_stfl) }, | ||
60 | { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, | ||
61 | { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, | ||
62 | { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, | ||
63 | { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, | ||
64 | { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, | ||
65 | { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, | ||
66 | { "diagnose_44", VCPU_STAT(diagnose_44) }, | ||
67 | { NULL } | ||
68 | }; | ||
69 | |||
70 | |||
71 | /* Section: not file related */ | ||
72 | void kvm_arch_hardware_enable(void *garbage) | ||
73 | { | ||
74 | /* every s390 is virtualization enabled ;-) */ | ||
75 | } | ||
76 | |||
77 | void kvm_arch_hardware_disable(void *garbage) | ||
78 | { | ||
79 | } | ||
80 | |||
81 | void decache_vcpus_on_cpu(int cpu) | ||
82 | { | ||
83 | } | ||
84 | |||
85 | int kvm_arch_hardware_setup(void) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | void kvm_arch_hardware_unsetup(void) | ||
91 | { | ||
92 | } | ||
93 | |||
94 | void kvm_arch_check_processor_compat(void *rtn) | ||
95 | { | ||
96 | } | ||
97 | |||
98 | int kvm_arch_init(void *opaque) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | void kvm_arch_exit(void) | ||
104 | { | ||
105 | } | ||
106 | |||
107 | /* Section: device related */ | ||
108 | long kvm_arch_dev_ioctl(struct file *filp, | ||
109 | unsigned int ioctl, unsigned long arg) | ||
110 | { | ||
111 | if (ioctl == KVM_S390_ENABLE_SIE) | ||
112 | return s390_enable_sie(); | ||
113 | return -EINVAL; | ||
114 | } | ||
115 | |||
116 | int kvm_dev_ioctl_check_extension(long ext) | ||
117 | { | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* Section: vm related */ | ||
122 | /* | ||
123 | * Get (and clear) the dirty memory log for a memory slot. | ||
124 | */ | ||
125 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | ||
126 | struct kvm_dirty_log *log) | ||
127 | { | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | long kvm_arch_vm_ioctl(struct file *filp, | ||
132 | unsigned int ioctl, unsigned long arg) | ||
133 | { | ||
134 | struct kvm *kvm = filp->private_data; | ||
135 | void __user *argp = (void __user *)arg; | ||
136 | int r; | ||
137 | |||
138 | switch (ioctl) { | ||
139 | case KVM_S390_INTERRUPT: { | ||
140 | struct kvm_s390_interrupt s390int; | ||
141 | |||
142 | r = -EFAULT; | ||
143 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
144 | break; | ||
145 | r = kvm_s390_inject_vm(kvm, &s390int); | ||
146 | break; | ||
147 | } | ||
148 | default: | ||
149 | r = -EINVAL; | ||
150 | } | ||
151 | |||
152 | return r; | ||
153 | } | ||
154 | |||
155 | struct kvm *kvm_arch_create_vm(void) | ||
156 | { | ||
157 | struct kvm *kvm; | ||
158 | int rc; | ||
159 | char debug_name[16]; | ||
160 | |||
161 | rc = s390_enable_sie(); | ||
162 | if (rc) | ||
163 | goto out_nokvm; | ||
164 | |||
165 | rc = -ENOMEM; | ||
166 | kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); | ||
167 | if (!kvm) | ||
168 | goto out_nokvm; | ||
169 | |||
170 | kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL); | ||
171 | if (!kvm->arch.sca) | ||
172 | goto out_nosca; | ||
173 | |||
174 | sprintf(debug_name, "kvm-%u", current->pid); | ||
175 | |||
176 | kvm->arch.dbf = debug_register(debug_name, 8, 2, 8 * sizeof(long)); | ||
177 | if (!kvm->arch.dbf) | ||
178 | goto out_nodbf; | ||
179 | |||
180 | spin_lock_init(&kvm->arch.float_int.lock); | ||
181 | INIT_LIST_HEAD(&kvm->arch.float_int.list); | ||
182 | |||
183 | debug_register_view(kvm->arch.dbf, &debug_sprintf_view); | ||
184 | VM_EVENT(kvm, 3, "%s", "vm created"); | ||
185 | |||
186 | try_module_get(THIS_MODULE); | ||
187 | |||
188 | return kvm; | ||
189 | out_nodbf: | ||
190 | free_page((unsigned long)(kvm->arch.sca)); | ||
191 | out_nosca: | ||
192 | kfree(kvm); | ||
193 | out_nokvm: | ||
194 | return ERR_PTR(rc); | ||
195 | } | ||
196 | |||
197 | void kvm_arch_destroy_vm(struct kvm *kvm) | ||
198 | { | ||
199 | debug_unregister(kvm->arch.dbf); | ||
200 | free_page((unsigned long)(kvm->arch.sca)); | ||
201 | kfree(kvm); | ||
202 | module_put(THIS_MODULE); | ||
203 | } | ||
204 | |||
205 | /* Section: vcpu related */ | ||
206 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | ||
207 | { | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | ||
212 | { | ||
213 | /* kvm common code refers to this, but does'nt call it */ | ||
214 | BUG(); | ||
215 | } | ||
216 | |||
217 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
218 | { | ||
219 | save_fp_regs(&vcpu->arch.host_fpregs); | ||
220 | save_access_regs(vcpu->arch.host_acrs); | ||
221 | vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK; | ||
222 | restore_fp_regs(&vcpu->arch.guest_fpregs); | ||
223 | restore_access_regs(vcpu->arch.guest_acrs); | ||
224 | |||
225 | if (signal_pending(current)) | ||
226 | atomic_set_mask(CPUSTAT_STOP_INT, | ||
227 | &vcpu->arch.sie_block->cpuflags); | ||
228 | } | ||
229 | |||
230 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | ||
231 | { | ||
232 | save_fp_regs(&vcpu->arch.guest_fpregs); | ||
233 | save_access_regs(vcpu->arch.guest_acrs); | ||
234 | restore_fp_regs(&vcpu->arch.host_fpregs); | ||
235 | restore_access_regs(vcpu->arch.host_acrs); | ||
236 | } | ||
237 | |||
238 | static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | ||
239 | { | ||
240 | /* this equals initial cpu reset in pop, but we don't switch to ESA */ | ||
241 | vcpu->arch.sie_block->gpsw.mask = 0UL; | ||
242 | vcpu->arch.sie_block->gpsw.addr = 0UL; | ||
243 | vcpu->arch.sie_block->prefix = 0UL; | ||
244 | vcpu->arch.sie_block->ihcpu = 0xffff; | ||
245 | vcpu->arch.sie_block->cputm = 0UL; | ||
246 | vcpu->arch.sie_block->ckc = 0UL; | ||
247 | vcpu->arch.sie_block->todpr = 0; | ||
248 | memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); | ||
249 | vcpu->arch.sie_block->gcr[0] = 0xE0UL; | ||
250 | vcpu->arch.sie_block->gcr[14] = 0xC2000000UL; | ||
251 | vcpu->arch.guest_fpregs.fpc = 0; | ||
252 | asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc)); | ||
253 | vcpu->arch.sie_block->gbea = 1; | ||
254 | } | ||
255 | |||
256 | int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||
257 | { | ||
258 | atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH); | ||
259 | vcpu->arch.sie_block->gmslm = 0xffffffffffUL; | ||
260 | vcpu->arch.sie_block->gmsor = 0x000000000000; | ||
261 | vcpu->arch.sie_block->ecb = 2; | ||
262 | vcpu->arch.sie_block->eca = 0xC1002001U; | ||
263 | setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, | ||
264 | (unsigned long) vcpu); | ||
265 | get_cpu_id(&vcpu->arch.cpu_id); | ||
266 | vcpu->arch.cpu_id.version = 0xfe; | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | ||
271 | unsigned int id) | ||
272 | { | ||
273 | struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); | ||
274 | int rc = -ENOMEM; | ||
275 | |||
276 | if (!vcpu) | ||
277 | goto out_nomem; | ||
278 | |||
279 | vcpu->arch.sie_block = (struct sie_block *) get_zeroed_page(GFP_KERNEL); | ||
280 | |||
281 | if (!vcpu->arch.sie_block) | ||
282 | goto out_free_cpu; | ||
283 | |||
284 | vcpu->arch.sie_block->icpua = id; | ||
285 | BUG_ON(!kvm->arch.sca); | ||
286 | BUG_ON(kvm->arch.sca->cpu[id].sda); | ||
287 | kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block; | ||
288 | vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); | ||
289 | vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; | ||
290 | |||
291 | spin_lock_init(&vcpu->arch.local_int.lock); | ||
292 | INIT_LIST_HEAD(&vcpu->arch.local_int.list); | ||
293 | vcpu->arch.local_int.float_int = &kvm->arch.float_int; | ||
294 | spin_lock_bh(&kvm->arch.float_int.lock); | ||
295 | kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int; | ||
296 | init_waitqueue_head(&vcpu->arch.local_int.wq); | ||
297 | vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags; | ||
298 | spin_unlock_bh(&kvm->arch.float_int.lock); | ||
299 | |||
300 | rc = kvm_vcpu_init(vcpu, kvm, id); | ||
301 | if (rc) | ||
302 | goto out_free_cpu; | ||
303 | VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu, | ||
304 | vcpu->arch.sie_block); | ||
305 | |||
306 | try_module_get(THIS_MODULE); | ||
307 | |||
308 | return vcpu; | ||
309 | out_free_cpu: | ||
310 | kfree(vcpu); | ||
311 | out_nomem: | ||
312 | return ERR_PTR(rc); | ||
313 | } | ||
314 | |||
315 | void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) | ||
316 | { | ||
317 | VCPU_EVENT(vcpu, 3, "%s", "destroy cpu"); | ||
318 | free_page((unsigned long)(vcpu->arch.sie_block)); | ||
319 | kfree(vcpu); | ||
320 | module_put(THIS_MODULE); | ||
321 | } | ||
322 | |||
323 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) | ||
324 | { | ||
325 | /* kvm common code refers to this, but never calls it */ | ||
326 | BUG(); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | ||
331 | { | ||
332 | vcpu_load(vcpu); | ||
333 | kvm_s390_vcpu_initial_reset(vcpu); | ||
334 | vcpu_put(vcpu); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
339 | { | ||
340 | vcpu_load(vcpu); | ||
341 | memcpy(&vcpu->arch.guest_gprs, ®s->gprs, sizeof(regs->gprs)); | ||
342 | vcpu_put(vcpu); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
347 | { | ||
348 | vcpu_load(vcpu); | ||
349 | memcpy(®s->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs)); | ||
350 | vcpu_put(vcpu); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||
355 | struct kvm_sregs *sregs) | ||
356 | { | ||
357 | vcpu_load(vcpu); | ||
358 | memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs)); | ||
359 | memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs)); | ||
360 | vcpu_put(vcpu); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||
365 | struct kvm_sregs *sregs) | ||
366 | { | ||
367 | vcpu_load(vcpu); | ||
368 | memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs)); | ||
369 | memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs)); | ||
370 | vcpu_put(vcpu); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
375 | { | ||
376 | vcpu_load(vcpu); | ||
377 | memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); | ||
378 | vcpu->arch.guest_fpregs.fpc = fpu->fpc; | ||
379 | vcpu_put(vcpu); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
384 | { | ||
385 | vcpu_load(vcpu); | ||
386 | memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs)); | ||
387 | fpu->fpc = vcpu->arch.guest_fpregs.fpc; | ||
388 | vcpu_put(vcpu); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw) | ||
393 | { | ||
394 | int rc = 0; | ||
395 | |||
396 | vcpu_load(vcpu); | ||
397 | if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING) | ||
398 | rc = -EBUSY; | ||
399 | else | ||
400 | vcpu->arch.sie_block->gpsw = psw; | ||
401 | vcpu_put(vcpu); | ||
402 | return rc; | ||
403 | } | ||
404 | |||
405 | int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||
406 | struct kvm_translation *tr) | ||
407 | { | ||
408 | return -EINVAL; /* not implemented yet */ | ||
409 | } | ||
410 | |||
411 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | ||
412 | struct kvm_debug_guest *dbg) | ||
413 | { | ||
414 | return -EINVAL; /* not implemented yet */ | ||
415 | } | ||
416 | |||
417 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | ||
418 | struct kvm_mp_state *mp_state) | ||
419 | { | ||
420 | return -EINVAL; /* not implemented yet */ | ||
421 | } | ||
422 | |||
423 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | ||
424 | struct kvm_mp_state *mp_state) | ||
425 | { | ||
426 | return -EINVAL; /* not implemented yet */ | ||
427 | } | ||
428 | |||
429 | static void __vcpu_run(struct kvm_vcpu *vcpu) | ||
430 | { | ||
431 | memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); | ||
432 | |||
433 | if (need_resched()) | ||
434 | schedule(); | ||
435 | |||
436 | vcpu->arch.sie_block->icptcode = 0; | ||
437 | local_irq_disable(); | ||
438 | kvm_guest_enter(); | ||
439 | local_irq_enable(); | ||
440 | VCPU_EVENT(vcpu, 6, "entering sie flags %x", | ||
441 | atomic_read(&vcpu->arch.sie_block->cpuflags)); | ||
442 | sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs); | ||
443 | VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", | ||
444 | vcpu->arch.sie_block->icptcode); | ||
445 | local_irq_disable(); | ||
446 | kvm_guest_exit(); | ||
447 | local_irq_enable(); | ||
448 | |||
449 | memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16); | ||
450 | } | ||
451 | |||
452 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
453 | { | ||
454 | int rc; | ||
455 | sigset_t sigsaved; | ||
456 | |||
457 | vcpu_load(vcpu); | ||
458 | |||
459 | if (vcpu->sigset_active) | ||
460 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); | ||
461 | |||
462 | atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | ||
463 | |||
464 | BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL); | ||
465 | |||
466 | switch (kvm_run->exit_reason) { | ||
467 | case KVM_EXIT_S390_SIEIC: | ||
468 | vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; | ||
469 | vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr; | ||
470 | break; | ||
471 | case KVM_EXIT_UNKNOWN: | ||
472 | case KVM_EXIT_S390_RESET: | ||
473 | break; | ||
474 | default: | ||
475 | BUG(); | ||
476 | } | ||
477 | |||
478 | might_sleep(); | ||
479 | |||
480 | do { | ||
481 | kvm_s390_deliver_pending_interrupts(vcpu); | ||
482 | __vcpu_run(vcpu); | ||
483 | rc = kvm_handle_sie_intercept(vcpu); | ||
484 | } while (!signal_pending(current) && !rc); | ||
485 | |||
486 | if (signal_pending(current) && !rc) | ||
487 | rc = -EINTR; | ||
488 | |||
489 | if (rc == -ENOTSUPP) { | ||
490 | /* intercept cannot be handled in-kernel, prepare kvm-run */ | ||
491 | kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; | ||
492 | kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode; | ||
493 | kvm_run->s390_sieic.mask = vcpu->arch.sie_block->gpsw.mask; | ||
494 | kvm_run->s390_sieic.addr = vcpu->arch.sie_block->gpsw.addr; | ||
495 | kvm_run->s390_sieic.ipa = vcpu->arch.sie_block->ipa; | ||
496 | kvm_run->s390_sieic.ipb = vcpu->arch.sie_block->ipb; | ||
497 | rc = 0; | ||
498 | } | ||
499 | |||
500 | if (rc == -EREMOTE) { | ||
501 | /* intercept was handled, but userspace support is needed | ||
502 | * kvm_run has been prepared by the handler */ | ||
503 | rc = 0; | ||
504 | } | ||
505 | |||
506 | if (vcpu->sigset_active) | ||
507 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
508 | |||
509 | vcpu_put(vcpu); | ||
510 | |||
511 | vcpu->stat.exit_userspace++; | ||
512 | return rc; | ||
513 | } | ||
514 | |||
515 | static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from, | ||
516 | unsigned long n, int prefix) | ||
517 | { | ||
518 | if (prefix) | ||
519 | return copy_to_guest(vcpu, guestdest, from, n); | ||
520 | else | ||
521 | return copy_to_guest_absolute(vcpu, guestdest, from, n); | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * store status at address | ||
526 | * we use have two special cases: | ||
527 | * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit | ||
528 | * KVM_S390_STORE_STATUS_PREFIXED: -> prefix | ||
529 | */ | ||
530 | int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) | ||
531 | { | ||
532 | const unsigned char archmode = 1; | ||
533 | int prefix; | ||
534 | |||
535 | if (addr == KVM_S390_STORE_STATUS_NOADDR) { | ||
536 | if (copy_to_guest_absolute(vcpu, 163ul, &archmode, 1)) | ||
537 | return -EFAULT; | ||
538 | addr = SAVE_AREA_BASE; | ||
539 | prefix = 0; | ||
540 | } else if (addr == KVM_S390_STORE_STATUS_PREFIXED) { | ||
541 | if (copy_to_guest(vcpu, 163ul, &archmode, 1)) | ||
542 | return -EFAULT; | ||
543 | addr = SAVE_AREA_BASE; | ||
544 | prefix = 1; | ||
545 | } else | ||
546 | prefix = 0; | ||
547 | |||
548 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, fp_regs), | ||
549 | vcpu->arch.guest_fpregs.fprs, 128, prefix)) | ||
550 | return -EFAULT; | ||
551 | |||
552 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, gp_regs), | ||
553 | vcpu->arch.guest_gprs, 128, prefix)) | ||
554 | return -EFAULT; | ||
555 | |||
556 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, psw), | ||
557 | &vcpu->arch.sie_block->gpsw, 16, prefix)) | ||
558 | return -EFAULT; | ||
559 | |||
560 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, pref_reg), | ||
561 | &vcpu->arch.sie_block->prefix, 4, prefix)) | ||
562 | return -EFAULT; | ||
563 | |||
564 | if (__guestcopy(vcpu, | ||
565 | addr + offsetof(struct save_area_s390x, fp_ctrl_reg), | ||
566 | &vcpu->arch.guest_fpregs.fpc, 4, prefix)) | ||
567 | return -EFAULT; | ||
568 | |||
569 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, tod_reg), | ||
570 | &vcpu->arch.sie_block->todpr, 4, prefix)) | ||
571 | return -EFAULT; | ||
572 | |||
573 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, timer), | ||
574 | &vcpu->arch.sie_block->cputm, 8, prefix)) | ||
575 | return -EFAULT; | ||
576 | |||
577 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, clk_cmp), | ||
578 | &vcpu->arch.sie_block->ckc, 8, prefix)) | ||
579 | return -EFAULT; | ||
580 | |||
581 | if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, acc_regs), | ||
582 | &vcpu->arch.guest_acrs, 64, prefix)) | ||
583 | return -EFAULT; | ||
584 | |||
585 | if (__guestcopy(vcpu, | ||
586 | addr + offsetof(struct save_area_s390x, ctrl_regs), | ||
587 | &vcpu->arch.sie_block->gcr, 128, prefix)) | ||
588 | return -EFAULT; | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) | ||
593 | { | ||
594 | int rc; | ||
595 | |||
596 | vcpu_load(vcpu); | ||
597 | rc = __kvm_s390_vcpu_store_status(vcpu, addr); | ||
598 | vcpu_put(vcpu); | ||
599 | return rc; | ||
600 | } | ||
601 | |||
602 | long kvm_arch_vcpu_ioctl(struct file *filp, | ||
603 | unsigned int ioctl, unsigned long arg) | ||
604 | { | ||
605 | struct kvm_vcpu *vcpu = filp->private_data; | ||
606 | void __user *argp = (void __user *)arg; | ||
607 | |||
608 | switch (ioctl) { | ||
609 | case KVM_S390_INTERRUPT: { | ||
610 | struct kvm_s390_interrupt s390int; | ||
611 | |||
612 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
613 | return -EFAULT; | ||
614 | return kvm_s390_inject_vcpu(vcpu, &s390int); | ||
615 | } | ||
616 | case KVM_S390_STORE_STATUS: | ||
617 | return kvm_s390_vcpu_store_status(vcpu, arg); | ||
618 | case KVM_S390_SET_INITIAL_PSW: { | ||
619 | psw_t psw; | ||
620 | |||
621 | if (copy_from_user(&psw, argp, sizeof(psw))) | ||
622 | return -EFAULT; | ||
623 | return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); | ||
624 | } | ||
625 | case KVM_S390_INITIAL_RESET: | ||
626 | return kvm_arch_vcpu_ioctl_initial_reset(vcpu); | ||
627 | default: | ||
628 | ; | ||
629 | } | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | |||
633 | /* Section: memory related */ | ||
634 | int kvm_arch_set_memory_region(struct kvm *kvm, | ||
635 | struct kvm_userspace_memory_region *mem, | ||
636 | struct kvm_memory_slot old, | ||
637 | int user_alloc) | ||
638 | { | ||
639 | /* A few sanity checks. We can have exactly one memory slot which has | ||
640 | to start at guest virtual zero and which has to be located at a | ||
641 | page boundary in userland and which has to end at a page boundary. | ||
642 | The memory in userland is ok to be fragmented into various different | ||
643 | vmas. It is okay to mmap() and munmap() stuff in this slot after | ||
644 | doing this call at any time */ | ||
645 | |||
646 | if (mem->slot) | ||
647 | return -EINVAL; | ||
648 | |||
649 | if (mem->guest_phys_addr) | ||
650 | return -EINVAL; | ||
651 | |||
652 | if (mem->userspace_addr & (PAGE_SIZE - 1)) | ||
653 | return -EINVAL; | ||
654 | |||
655 | if (mem->memory_size & (PAGE_SIZE - 1)) | ||
656 | return -EINVAL; | ||
657 | |||
658 | kvm->arch.guest_origin = mem->userspace_addr; | ||
659 | kvm->arch.guest_memsize = mem->memory_size; | ||
660 | |||
661 | /* FIXME: we do want to interrupt running CPUs and update their memory | ||
662 | configuration now to avoid race conditions. But hey, changing the | ||
663 | memory layout while virtual CPUs are running is usually bad | ||
664 | programming practice. */ | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | ||
670 | { | ||
671 | return gfn; | ||
672 | } | ||
673 | |||
674 | static int __init kvm_s390_init(void) | ||
675 | { | ||
676 | return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE); | ||
677 | } | ||
678 | |||
679 | static void __exit kvm_s390_exit(void) | ||
680 | { | ||
681 | kvm_exit(); | ||
682 | } | ||
683 | |||
684 | module_init(kvm_s390_init); | ||
685 | module_exit(kvm_s390_exit); | ||
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h new file mode 100644 index 000000000000..3893cf12eacf --- /dev/null +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * kvm_s390.h - definition for kvm on s390 | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | */ | ||
13 | |||
14 | #ifndef ARCH_S390_KVM_S390_H | ||
15 | #define ARCH_S390_KVM_S390_H | ||
16 | |||
17 | #include <linux/kvm.h> | ||
18 | #include <linux/kvm_host.h> | ||
19 | |||
20 | typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); | ||
21 | |||
22 | int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); | ||
23 | |||
24 | #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ | ||
25 | do { \ | ||
26 | debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \ | ||
27 | d_args); \ | ||
28 | } while (0) | ||
29 | |||
30 | #define VCPU_EVENT(d_vcpu, d_loglevel, d_string, d_args...)\ | ||
31 | do { \ | ||
32 | debug_sprintf_event(d_vcpu->kvm->arch.dbf, d_loglevel, \ | ||
33 | "%02d[%016lx-%016lx]: " d_string "\n", d_vcpu->vcpu_id, \ | ||
34 | d_vcpu->arch.sie_block->gpsw.mask, d_vcpu->arch.sie_block->gpsw.addr,\ | ||
35 | d_args); \ | ||
36 | } while (0) | ||
37 | |||
38 | static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu) | ||
39 | { | ||
40 | return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT; | ||
41 | } | ||
42 | |||
43 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); | ||
44 | void kvm_s390_idle_wakeup(unsigned long data); | ||
45 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); | ||
46 | int kvm_s390_inject_vm(struct kvm *kvm, | ||
47 | struct kvm_s390_interrupt *s390int); | ||
48 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | ||
49 | struct kvm_s390_interrupt *s390int); | ||
50 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); | ||
51 | |||
52 | /* implemented in priv.c */ | ||
53 | int kvm_s390_handle_priv(struct kvm_vcpu *vcpu); | ||
54 | |||
55 | /* implemented in sigp.c */ | ||
56 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | ||
57 | |||
58 | /* implemented in kvm-s390.c */ | ||
59 | int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, | ||
60 | unsigned long addr); | ||
61 | /* implemented in diag.c */ | ||
62 | int kvm_s390_handle_diag(struct kvm_vcpu *vcpu); | ||
63 | |||
64 | #endif | ||
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c new file mode 100644 index 000000000000..1465946325c5 --- /dev/null +++ b/arch/s390/kvm/priv.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /* | ||
2 | * priv.c - handling privileged instructions | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | */ | ||
13 | |||
14 | #include <linux/kvm.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <asm/current.h> | ||
17 | #include <asm/debug.h> | ||
18 | #include <asm/ebcdic.h> | ||
19 | #include <asm/sysinfo.h> | ||
20 | #include "gaccess.h" | ||
21 | #include "kvm-s390.h" | ||
22 | |||
23 | static int handle_set_prefix(struct kvm_vcpu *vcpu) | ||
24 | { | ||
25 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
26 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
27 | u64 operand2; | ||
28 | u32 address = 0; | ||
29 | u8 tmp; | ||
30 | |||
31 | vcpu->stat.instruction_spx++; | ||
32 | |||
33 | operand2 = disp2; | ||
34 | if (base2) | ||
35 | operand2 += vcpu->arch.guest_gprs[base2]; | ||
36 | |||
37 | /* must be word boundary */ | ||
38 | if (operand2 & 3) { | ||
39 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
40 | goto out; | ||
41 | } | ||
42 | |||
43 | /* get the value */ | ||
44 | if (get_guest_u32(vcpu, operand2, &address)) { | ||
45 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
46 | goto out; | ||
47 | } | ||
48 | |||
49 | address = address & 0x7fffe000u; | ||
50 | |||
51 | /* make sure that the new value is valid memory */ | ||
52 | if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || | ||
53 | (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { | ||
54 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
55 | goto out; | ||
56 | } | ||
57 | |||
58 | vcpu->arch.sie_block->prefix = address; | ||
59 | vcpu->arch.sie_block->ihcpu = 0xffff; | ||
60 | |||
61 | VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); | ||
62 | out: | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int handle_store_prefix(struct kvm_vcpu *vcpu) | ||
67 | { | ||
68 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
69 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
70 | u64 operand2; | ||
71 | u32 address; | ||
72 | |||
73 | vcpu->stat.instruction_stpx++; | ||
74 | operand2 = disp2; | ||
75 | if (base2) | ||
76 | operand2 += vcpu->arch.guest_gprs[base2]; | ||
77 | |||
78 | /* must be word boundary */ | ||
79 | if (operand2 & 3) { | ||
80 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
81 | goto out; | ||
82 | } | ||
83 | |||
84 | address = vcpu->arch.sie_block->prefix; | ||
85 | address = address & 0x7fffe000u; | ||
86 | |||
87 | /* get the value */ | ||
88 | if (put_guest_u32(vcpu, operand2, address)) { | ||
89 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); | ||
94 | out: | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int handle_store_cpu_address(struct kvm_vcpu *vcpu) | ||
99 | { | ||
100 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
101 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
102 | u64 useraddr; | ||
103 | int rc; | ||
104 | |||
105 | vcpu->stat.instruction_stap++; | ||
106 | useraddr = disp2; | ||
107 | if (base2) | ||
108 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
109 | |||
110 | if (useraddr & 1) { | ||
111 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); | ||
116 | if (rc == -EFAULT) { | ||
117 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | VCPU_EVENT(vcpu, 5, "storing cpu address to %lx", useraddr); | ||
122 | out: | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int handle_skey(struct kvm_vcpu *vcpu) | ||
127 | { | ||
128 | vcpu->stat.instruction_storage_key++; | ||
129 | vcpu->arch.sie_block->gpsw.addr -= 4; | ||
130 | VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int handle_stsch(struct kvm_vcpu *vcpu) | ||
135 | { | ||
136 | vcpu->stat.instruction_stsch++; | ||
137 | VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3"); | ||
138 | /* condition code 3 */ | ||
139 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
140 | vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int handle_chsc(struct kvm_vcpu *vcpu) | ||
145 | { | ||
146 | vcpu->stat.instruction_chsc++; | ||
147 | VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3"); | ||
148 | /* condition code 3 */ | ||
149 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
150 | vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static unsigned int kvm_stfl(void) | ||
155 | { | ||
156 | asm volatile( | ||
157 | " .insn s,0xb2b10000,0(0)\n" /* stfl */ | ||
158 | "0:\n" | ||
159 | EX_TABLE(0b, 0b)); | ||
160 | return S390_lowcore.stfl_fac_list; | ||
161 | } | ||
162 | |||
163 | static int handle_stfl(struct kvm_vcpu *vcpu) | ||
164 | { | ||
165 | unsigned int facility_list = kvm_stfl(); | ||
166 | int rc; | ||
167 | |||
168 | vcpu->stat.instruction_stfl++; | ||
169 | facility_list &= ~(1UL<<24); /* no stfle */ | ||
170 | |||
171 | rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), | ||
172 | &facility_list, sizeof(facility_list)); | ||
173 | if (rc == -EFAULT) | ||
174 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
175 | else | ||
176 | VCPU_EVENT(vcpu, 5, "store facility list value %x", | ||
177 | facility_list); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int handle_stidp(struct kvm_vcpu *vcpu) | ||
182 | { | ||
183 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
184 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
185 | u64 operand2; | ||
186 | int rc; | ||
187 | |||
188 | vcpu->stat.instruction_stidp++; | ||
189 | operand2 = disp2; | ||
190 | if (base2) | ||
191 | operand2 += vcpu->arch.guest_gprs[base2]; | ||
192 | |||
193 | if (operand2 & 7) { | ||
194 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data); | ||
199 | if (rc == -EFAULT) { | ||
200 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); | ||
205 | out: | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) | ||
210 | { | ||
211 | struct float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
212 | int cpus = 0; | ||
213 | int n; | ||
214 | |||
215 | spin_lock_bh(&fi->lock); | ||
216 | for (n = 0; n < KVM_MAX_VCPUS; n++) | ||
217 | if (fi->local_int[n]) | ||
218 | cpus++; | ||
219 | spin_unlock_bh(&fi->lock); | ||
220 | |||
221 | /* deal with other level 3 hypervisors */ | ||
222 | if (stsi(mem, 3, 2, 2) == -ENOSYS) | ||
223 | mem->count = 0; | ||
224 | if (mem->count < 8) | ||
225 | mem->count++; | ||
226 | for (n = mem->count - 1; n > 0 ; n--) | ||
227 | memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0])); | ||
228 | |||
229 | mem->vm[0].cpus_total = cpus; | ||
230 | mem->vm[0].cpus_configured = cpus; | ||
231 | mem->vm[0].cpus_standby = 0; | ||
232 | mem->vm[0].cpus_reserved = 0; | ||
233 | mem->vm[0].caf = 1000; | ||
234 | memcpy(mem->vm[0].name, "KVMguest", 8); | ||
235 | ASCEBC(mem->vm[0].name, 8); | ||
236 | memcpy(mem->vm[0].cpi, "KVM/Linux ", 16); | ||
237 | ASCEBC(mem->vm[0].cpi, 16); | ||
238 | } | ||
239 | |||
240 | static int handle_stsi(struct kvm_vcpu *vcpu) | ||
241 | { | ||
242 | int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28; | ||
243 | int sel1 = vcpu->arch.guest_gprs[0] & 0xff; | ||
244 | int sel2 = vcpu->arch.guest_gprs[1] & 0xffff; | ||
245 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
246 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
247 | u64 operand2; | ||
248 | unsigned long mem; | ||
249 | |||
250 | vcpu->stat.instruction_stsi++; | ||
251 | VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2); | ||
252 | |||
253 | operand2 = disp2; | ||
254 | if (base2) | ||
255 | operand2 += vcpu->arch.guest_gprs[base2]; | ||
256 | |||
257 | if (operand2 & 0xfff && fc > 0) | ||
258 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
259 | |||
260 | switch (fc) { | ||
261 | case 0: | ||
262 | vcpu->arch.guest_gprs[0] = 3 << 28; | ||
263 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
264 | return 0; | ||
265 | case 1: /* same handling for 1 and 2 */ | ||
266 | case 2: | ||
267 | mem = get_zeroed_page(GFP_KERNEL); | ||
268 | if (!mem) | ||
269 | goto out_fail; | ||
270 | if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS) | ||
271 | goto out_mem; | ||
272 | break; | ||
273 | case 3: | ||
274 | if (sel1 != 2 || sel2 != 2) | ||
275 | goto out_fail; | ||
276 | mem = get_zeroed_page(GFP_KERNEL); | ||
277 | if (!mem) | ||
278 | goto out_fail; | ||
279 | handle_stsi_3_2_2(vcpu, (void *) mem); | ||
280 | break; | ||
281 | default: | ||
282 | goto out_fail; | ||
283 | } | ||
284 | |||
285 | if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { | ||
286 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
287 | goto out_mem; | ||
288 | } | ||
289 | free_page(mem); | ||
290 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
291 | vcpu->arch.guest_gprs[0] = 0; | ||
292 | return 0; | ||
293 | out_mem: | ||
294 | free_page(mem); | ||
295 | out_fail: | ||
296 | /* condition code 3 */ | ||
297 | vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static intercept_handler_t priv_handlers[256] = { | ||
302 | [0x02] = handle_stidp, | ||
303 | [0x10] = handle_set_prefix, | ||
304 | [0x11] = handle_store_prefix, | ||
305 | [0x12] = handle_store_cpu_address, | ||
306 | [0x29] = handle_skey, | ||
307 | [0x2a] = handle_skey, | ||
308 | [0x2b] = handle_skey, | ||
309 | [0x34] = handle_stsch, | ||
310 | [0x5f] = handle_chsc, | ||
311 | [0x7d] = handle_stsi, | ||
312 | [0xb1] = handle_stfl, | ||
313 | }; | ||
314 | |||
315 | int kvm_s390_handle_priv(struct kvm_vcpu *vcpu) | ||
316 | { | ||
317 | intercept_handler_t handler; | ||
318 | |||
319 | handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; | ||
320 | if (handler) | ||
321 | return handler(vcpu); | ||
322 | return -ENOTSUPP; | ||
323 | } | ||
diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S new file mode 100644 index 000000000000..934fd6a885f6 --- /dev/null +++ b/arch/s390/kvm/sie64a.S | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * sie64a.S - low level sie call | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | |||
16 | SP_R5 = 5 * 8 # offset into stackframe | ||
17 | SP_R6 = 6 * 8 | ||
18 | |||
19 | /* | ||
20 | * sie64a calling convention: | ||
21 | * %r2 pointer to sie control block | ||
22 | * %r3 guest register save area | ||
23 | */ | ||
24 | .globl sie64a | ||
25 | sie64a: | ||
26 | lgr %r5,%r3 | ||
27 | stmg %r5,%r14,SP_R5(%r15) # save register on entry | ||
28 | lgr %r14,%r2 # pointer to sie control block | ||
29 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | ||
30 | sie_inst: | ||
31 | sie 0(%r14) | ||
32 | lg %r14,SP_R5(%r15) | ||
33 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
34 | lghi %r2,0 | ||
35 | lmg %r6,%r14,SP_R6(%r15) | ||
36 | br %r14 | ||
37 | |||
38 | sie_err: | ||
39 | lg %r14,SP_R5(%r15) | ||
40 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
41 | lghi %r2,-EFAULT | ||
42 | lmg %r6,%r14,SP_R6(%r15) | ||
43 | br %r14 | ||
44 | |||
45 | .section __ex_table,"a" | ||
46 | .quad sie_inst,sie_err | ||
47 | .previous | ||
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c new file mode 100644 index 000000000000..0a236acfb5f6 --- /dev/null +++ b/arch/s390/kvm/sigp.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * sigp.c - handlinge interprocessor communication | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
11 | * Christian Borntraeger <borntraeger@de.ibm.com> | ||
12 | */ | ||
13 | |||
14 | #include <linux/kvm.h> | ||
15 | #include <linux/kvm_host.h> | ||
16 | #include "gaccess.h" | ||
17 | #include "kvm-s390.h" | ||
18 | |||
19 | /* sigp order codes */ | ||
20 | #define SIGP_SENSE 0x01 | ||
21 | #define SIGP_EXTERNAL_CALL 0x02 | ||
22 | #define SIGP_EMERGENCY 0x03 | ||
23 | #define SIGP_START 0x04 | ||
24 | #define SIGP_STOP 0x05 | ||
25 | #define SIGP_RESTART 0x06 | ||
26 | #define SIGP_STOP_STORE_STATUS 0x09 | ||
27 | #define SIGP_INITIAL_CPU_RESET 0x0b | ||
28 | #define SIGP_CPU_RESET 0x0c | ||
29 | #define SIGP_SET_PREFIX 0x0d | ||
30 | #define SIGP_STORE_STATUS_ADDR 0x0e | ||
31 | #define SIGP_SET_ARCH 0x12 | ||
32 | |||
33 | /* cpu status bits */ | ||
34 | #define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL | ||
35 | #define SIGP_STAT_INCORRECT_STATE 0x00000200UL | ||
36 | #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL | ||
37 | #define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL | ||
38 | #define SIGP_STAT_STOPPED 0x00000040UL | ||
39 | #define SIGP_STAT_OPERATOR_INTERV 0x00000020UL | ||
40 | #define SIGP_STAT_CHECK_STOP 0x00000010UL | ||
41 | #define SIGP_STAT_INOPERATIVE 0x00000004UL | ||
42 | #define SIGP_STAT_INVALID_ORDER 0x00000002UL | ||
43 | #define SIGP_STAT_RECEIVER_CHECK 0x00000001UL | ||
44 | |||
45 | |||
46 | static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) | ||
47 | { | ||
48 | struct float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
49 | int rc; | ||
50 | |||
51 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
52 | return 3; /* not operational */ | ||
53 | |||
54 | spin_lock_bh(&fi->lock); | ||
55 | if (fi->local_int[cpu_addr] == NULL) | ||
56 | rc = 3; /* not operational */ | ||
57 | else if (atomic_read(fi->local_int[cpu_addr]->cpuflags) | ||
58 | & CPUSTAT_RUNNING) { | ||
59 | *reg &= 0xffffffff00000000UL; | ||
60 | rc = 1; /* status stored */ | ||
61 | } else { | ||
62 | *reg &= 0xffffffff00000000UL; | ||
63 | *reg |= SIGP_STAT_STOPPED; | ||
64 | rc = 1; /* status stored */ | ||
65 | } | ||
66 | spin_unlock_bh(&fi->lock); | ||
67 | |||
68 | VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc); | ||
69 | return rc; | ||
70 | } | ||
71 | |||
72 | static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | ||
73 | { | ||
74 | struct float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
75 | struct local_interrupt *li; | ||
76 | struct interrupt_info *inti; | ||
77 | int rc; | ||
78 | |||
79 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
80 | return 3; /* not operational */ | ||
81 | |||
82 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
83 | if (!inti) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | inti->type = KVM_S390_INT_EMERGENCY; | ||
87 | |||
88 | spin_lock_bh(&fi->lock); | ||
89 | li = fi->local_int[cpu_addr]; | ||
90 | if (li == NULL) { | ||
91 | rc = 3; /* not operational */ | ||
92 | kfree(inti); | ||
93 | goto unlock; | ||
94 | } | ||
95 | spin_lock_bh(&li->lock); | ||
96 | list_add_tail(&inti->list, &li->list); | ||
97 | atomic_set(&li->active, 1); | ||
98 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
99 | if (waitqueue_active(&li->wq)) | ||
100 | wake_up_interruptible(&li->wq); | ||
101 | spin_unlock_bh(&li->lock); | ||
102 | rc = 0; /* order accepted */ | ||
103 | unlock: | ||
104 | spin_unlock_bh(&fi->lock); | ||
105 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
106 | return rc; | ||
107 | } | ||
108 | |||
109 | static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) | ||
110 | { | ||
111 | struct float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
112 | struct local_interrupt *li; | ||
113 | struct interrupt_info *inti; | ||
114 | int rc; | ||
115 | |||
116 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
117 | return 3; /* not operational */ | ||
118 | |||
119 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
120 | if (!inti) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | inti->type = KVM_S390_SIGP_STOP; | ||
124 | |||
125 | spin_lock_bh(&fi->lock); | ||
126 | li = fi->local_int[cpu_addr]; | ||
127 | if (li == NULL) { | ||
128 | rc = 3; /* not operational */ | ||
129 | kfree(inti); | ||
130 | goto unlock; | ||
131 | } | ||
132 | spin_lock_bh(&li->lock); | ||
133 | list_add_tail(&inti->list, &li->list); | ||
134 | atomic_set(&li->active, 1); | ||
135 | atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); | ||
136 | if (store) | ||
137 | li->action_bits |= ACTION_STORE_ON_STOP; | ||
138 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
139 | if (waitqueue_active(&li->wq)) | ||
140 | wake_up_interruptible(&li->wq); | ||
141 | spin_unlock_bh(&li->lock); | ||
142 | rc = 0; /* order accepted */ | ||
143 | unlock: | ||
144 | spin_unlock_bh(&fi->lock); | ||
145 | VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); | ||
146 | return rc; | ||
147 | } | ||
148 | |||
149 | static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) | ||
150 | { | ||
151 | int rc; | ||
152 | |||
153 | switch (parameter & 0xff) { | ||
154 | case 0: | ||
155 | printk(KERN_WARNING "kvm: request to switch to ESA/390 mode" | ||
156 | " not supported"); | ||
157 | rc = 3; /* not operational */ | ||
158 | break; | ||
159 | case 1: | ||
160 | case 2: | ||
161 | rc = 0; /* order accepted */ | ||
162 | break; | ||
163 | default: | ||
164 | rc = -ENOTSUPP; | ||
165 | } | ||
166 | return rc; | ||
167 | } | ||
168 | |||
169 | static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, | ||
170 | u64 *reg) | ||
171 | { | ||
172 | struct float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
173 | struct local_interrupt *li; | ||
174 | struct interrupt_info *inti; | ||
175 | int rc; | ||
176 | u8 tmp; | ||
177 | |||
178 | /* make sure that the new value is valid memory */ | ||
179 | address = address & 0x7fffe000u; | ||
180 | if ((copy_from_guest(vcpu, &tmp, | ||
181 | (u64) (address + vcpu->kvm->arch.guest_origin) , 1)) || | ||
182 | (copy_from_guest(vcpu, &tmp, (u64) (address + | ||
183 | vcpu->kvm->arch.guest_origin + PAGE_SIZE), 1))) { | ||
184 | *reg |= SIGP_STAT_INVALID_PARAMETER; | ||
185 | return 1; /* invalid parameter */ | ||
186 | } | ||
187 | |||
188 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
189 | if (!inti) | ||
190 | return 2; /* busy */ | ||
191 | |||
192 | spin_lock_bh(&fi->lock); | ||
193 | li = fi->local_int[cpu_addr]; | ||
194 | |||
195 | if ((cpu_addr >= KVM_MAX_VCPUS) || (li == NULL)) { | ||
196 | rc = 1; /* incorrect state */ | ||
197 | *reg &= SIGP_STAT_INCORRECT_STATE; | ||
198 | kfree(inti); | ||
199 | goto out_fi; | ||
200 | } | ||
201 | |||
202 | spin_lock_bh(&li->lock); | ||
203 | /* cpu must be in stopped state */ | ||
204 | if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { | ||
205 | rc = 1; /* incorrect state */ | ||
206 | *reg &= SIGP_STAT_INCORRECT_STATE; | ||
207 | kfree(inti); | ||
208 | goto out_li; | ||
209 | } | ||
210 | |||
211 | inti->type = KVM_S390_SIGP_SET_PREFIX; | ||
212 | inti->prefix.address = address; | ||
213 | |||
214 | list_add_tail(&inti->list, &li->list); | ||
215 | atomic_set(&li->active, 1); | ||
216 | if (waitqueue_active(&li->wq)) | ||
217 | wake_up_interruptible(&li->wq); | ||
218 | rc = 0; /* order accepted */ | ||
219 | |||
220 | VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); | ||
221 | out_li: | ||
222 | spin_unlock_bh(&li->lock); | ||
223 | out_fi: | ||
224 | spin_unlock_bh(&fi->lock); | ||
225 | return rc; | ||
226 | } | ||
227 | |||
228 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) | ||
229 | { | ||
230 | int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
231 | int r3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
232 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
233 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
234 | u32 parameter; | ||
235 | u16 cpu_addr = vcpu->arch.guest_gprs[r3]; | ||
236 | u8 order_code; | ||
237 | int rc; | ||
238 | |||
239 | order_code = disp2; | ||
240 | if (base2) | ||
241 | order_code += vcpu->arch.guest_gprs[base2]; | ||
242 | |||
243 | if (r1 % 2) | ||
244 | parameter = vcpu->arch.guest_gprs[r1]; | ||
245 | else | ||
246 | parameter = vcpu->arch.guest_gprs[r1 + 1]; | ||
247 | |||
248 | switch (order_code) { | ||
249 | case SIGP_SENSE: | ||
250 | vcpu->stat.instruction_sigp_sense++; | ||
251 | rc = __sigp_sense(vcpu, cpu_addr, | ||
252 | &vcpu->arch.guest_gprs[r1]); | ||
253 | break; | ||
254 | case SIGP_EMERGENCY: | ||
255 | vcpu->stat.instruction_sigp_emergency++; | ||
256 | rc = __sigp_emergency(vcpu, cpu_addr); | ||
257 | break; | ||
258 | case SIGP_STOP: | ||
259 | vcpu->stat.instruction_sigp_stop++; | ||
260 | rc = __sigp_stop(vcpu, cpu_addr, 0); | ||
261 | break; | ||
262 | case SIGP_STOP_STORE_STATUS: | ||
263 | vcpu->stat.instruction_sigp_stop++; | ||
264 | rc = __sigp_stop(vcpu, cpu_addr, 1); | ||
265 | break; | ||
266 | case SIGP_SET_ARCH: | ||
267 | vcpu->stat.instruction_sigp_arch++; | ||
268 | rc = __sigp_set_arch(vcpu, parameter); | ||
269 | break; | ||
270 | case SIGP_SET_PREFIX: | ||
271 | vcpu->stat.instruction_sigp_prefix++; | ||
272 | rc = __sigp_set_prefix(vcpu, cpu_addr, parameter, | ||
273 | &vcpu->arch.guest_gprs[r1]); | ||
274 | break; | ||
275 | case SIGP_RESTART: | ||
276 | vcpu->stat.instruction_sigp_restart++; | ||
277 | /* user space must know about restart */ | ||
278 | default: | ||
279 | return -ENOTSUPP; | ||
280 | } | ||
281 | |||
282 | if (rc < 0) | ||
283 | return rc; | ||
284 | |||
285 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
286 | vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44; | ||
287 | return 0; | ||
288 | } | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index fd072013f88c..5c1aea97cd12 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -30,11 +30,27 @@ | |||
30 | #define TABLES_PER_PAGE 4 | 30 | #define TABLES_PER_PAGE 4 |
31 | #define FRAG_MASK 15UL | 31 | #define FRAG_MASK 15UL |
32 | #define SECOND_HALVES 10UL | 32 | #define SECOND_HALVES 10UL |
33 | |||
34 | void clear_table_pgstes(unsigned long *table) | ||
35 | { | ||
36 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/4); | ||
37 | memset(table + 256, 0, PAGE_SIZE/4); | ||
38 | clear_table(table + 512, _PAGE_TYPE_EMPTY, PAGE_SIZE/4); | ||
39 | memset(table + 768, 0, PAGE_SIZE/4); | ||
40 | } | ||
41 | |||
33 | #else | 42 | #else |
34 | #define ALLOC_ORDER 2 | 43 | #define ALLOC_ORDER 2 |
35 | #define TABLES_PER_PAGE 2 | 44 | #define TABLES_PER_PAGE 2 |
36 | #define FRAG_MASK 3UL | 45 | #define FRAG_MASK 3UL |
37 | #define SECOND_HALVES 2UL | 46 | #define SECOND_HALVES 2UL |
47 | |||
48 | void clear_table_pgstes(unsigned long *table) | ||
49 | { | ||
50 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2); | ||
51 | memset(table + 256, 0, PAGE_SIZE/2); | ||
52 | } | ||
53 | |||
38 | #endif | 54 | #endif |
39 | 55 | ||
40 | unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) | 56 | unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) |
@@ -153,7 +169,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
153 | unsigned long *table; | 169 | unsigned long *table; |
154 | unsigned long bits; | 170 | unsigned long bits; |
155 | 171 | ||
156 | bits = mm->context.noexec ? 3UL : 1UL; | 172 | bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL; |
157 | spin_lock(&mm->page_table_lock); | 173 | spin_lock(&mm->page_table_lock); |
158 | page = NULL; | 174 | page = NULL; |
159 | if (!list_empty(&mm->context.pgtable_list)) { | 175 | if (!list_empty(&mm->context.pgtable_list)) { |
@@ -170,7 +186,10 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
170 | pgtable_page_ctor(page); | 186 | pgtable_page_ctor(page); |
171 | page->flags &= ~FRAG_MASK; | 187 | page->flags &= ~FRAG_MASK; |
172 | table = (unsigned long *) page_to_phys(page); | 188 | table = (unsigned long *) page_to_phys(page); |
173 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); | 189 | if (mm->context.pgstes) |
190 | clear_table_pgstes(table); | ||
191 | else | ||
192 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); | ||
174 | spin_lock(&mm->page_table_lock); | 193 | spin_lock(&mm->page_table_lock); |
175 | list_add(&page->lru, &mm->context.pgtable_list); | 194 | list_add(&page->lru, &mm->context.pgtable_list); |
176 | } | 195 | } |
@@ -191,7 +210,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) | |||
191 | struct page *page; | 210 | struct page *page; |
192 | unsigned long bits; | 211 | unsigned long bits; |
193 | 212 | ||
194 | bits = mm->context.noexec ? 3UL : 1UL; | 213 | bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL; |
195 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 214 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
196 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 215 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
197 | spin_lock(&mm->page_table_lock); | 216 | spin_lock(&mm->page_table_lock); |
@@ -228,3 +247,43 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) | |||
228 | mm->context.noexec = 0; | 247 | mm->context.noexec = 0; |
229 | update_mm(mm, tsk); | 248 | update_mm(mm, tsk); |
230 | } | 249 | } |
250 | |||
251 | /* | ||
252 | * switch on pgstes for its userspace process (for kvm) | ||
253 | */ | ||
254 | int s390_enable_sie(void) | ||
255 | { | ||
256 | struct task_struct *tsk = current; | ||
257 | struct mm_struct *mm; | ||
258 | int rc; | ||
259 | |||
260 | task_lock(tsk); | ||
261 | |||
262 | rc = 0; | ||
263 | if (tsk->mm->context.pgstes) | ||
264 | goto unlock; | ||
265 | |||
266 | rc = -EINVAL; | ||
267 | if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 || | ||
268 | tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) | ||
269 | goto unlock; | ||
270 | |||
271 | tsk->mm->context.pgstes = 1; /* dirty little tricks .. */ | ||
272 | mm = dup_mm(tsk); | ||
273 | tsk->mm->context.pgstes = 0; | ||
274 | |||
275 | rc = -ENOMEM; | ||
276 | if (!mm) | ||
277 | goto unlock; | ||
278 | mmput(tsk->mm); | ||
279 | tsk->mm = tsk->active_mm = mm; | ||
280 | preempt_disable(); | ||
281 | update_mm(mm, tsk); | ||
282 | cpu_set(smp_processor_id(), mm->cpu_vm_mask); | ||
283 | preempt_enable(); | ||
284 | rc = 0; | ||
285 | unlock: | ||
286 | task_unlock(tsk); | ||
287 | return rc; | ||
288 | } | ||
289 | EXPORT_SYMBOL_GPL(s390_enable_sie); | ||
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 49b435c3a57a..08d2e7325252 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c | |||
@@ -191,8 +191,8 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) | |||
191 | 191 | ||
192 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 192 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
193 | { | 193 | { |
194 | unsigned long start = pci_resource_start(dev, bar); | 194 | resource_size_t start = pci_resource_start(dev, bar); |
195 | unsigned long len = pci_resource_len(dev, bar); | 195 | resource_size_t len = pci_resource_len(dev, bar); |
196 | unsigned long flags = pci_resource_flags(dev, bar); | 196 | unsigned long flags = pci_resource_flags(dev, bar); |
197 | 197 | ||
198 | if (unlikely(!len || !start)) | 198 | if (unlikely(!len || !start)) |
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c index dc6725c51a89..57cf0e0680f3 100644 --- a/arch/sh/kernel/asm-offsets.c +++ b/arch/sh/kernel/asm-offsets.c | |||
@@ -11,12 +11,9 @@ | |||
11 | #include <linux/stddef.h> | 11 | #include <linux/stddef.h> |
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
14 | #include <asm/thread_info.h> | 14 | #include <linux/kbuild.h> |
15 | |||
16 | #define DEFINE(sym, val) \ | ||
17 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
18 | 15 | ||
19 | #define BLANK() asm volatile("\n->" : : ) | 16 | #include <asm/thread_info.h> |
20 | 17 | ||
21 | int main(void) | 18 | int main(void) |
22 | { | 19 | { |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 9bf19b00696a..a2a99e487e33 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -200,8 +200,6 @@ void irq_ctx_exit(int cpu) | |||
200 | hardirq_ctx[cpu] = NULL; | 200 | hardirq_ctx[cpu] = NULL; |
201 | } | 201 | } |
202 | 202 | ||
203 | extern asmlinkage void __do_softirq(void); | ||
204 | |||
205 | asmlinkage void do_softirq(void) | 203 | asmlinkage void do_softirq(void) |
206 | { | 204 | { |
207 | unsigned long flags; | 205 | unsigned long flags; |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 53dde0607362..d7df26bd1e54 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -307,15 +307,6 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
307 | #endif | 307 | #endif |
308 | 308 | ||
309 | #ifdef CONFIG_MEMORY_HOTPLUG | 309 | #ifdef CONFIG_MEMORY_HOTPLUG |
310 | void online_page(struct page *page) | ||
311 | { | ||
312 | ClearPageReserved(page); | ||
313 | init_page_count(page); | ||
314 | __free_page(page); | ||
315 | totalram_pages++; | ||
316 | num_physpages++; | ||
317 | } | ||
318 | |||
319 | int arch_add_memory(int nid, u64 start, u64 size) | 310 | int arch_add_memory(int nid, u64 start, u64 size) |
320 | { | 311 | { |
321 | pg_data_t *pgdat; | 312 | pg_data_t *pgdat; |
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c index 6773ed76e414..cd3f7694e9b9 100644 --- a/arch/sparc/kernel/asm-offsets.c +++ b/arch/sparc/kernel/asm-offsets.c | |||
@@ -12,11 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | // #include <linux/mm.h> | 14 | // #include <linux/mm.h> |
15 | 15 | #include <linux/kbuild.h> | |
16 | #define DEFINE(sym, val) \ | ||
17 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
18 | |||
19 | #define BLANK() asm volatile("\n->" : : ) | ||
20 | 16 | ||
21 | int foo(void) | 17 | int foo(void) |
22 | { | 18 | { |
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 70c0dd22491d..e7f35198ae34 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c | |||
@@ -357,8 +357,6 @@ void flush_thread(void) | |||
357 | { | 357 | { |
358 | current_thread_info()->w_saved = 0; | 358 | current_thread_info()->w_saved = 0; |
359 | 359 | ||
360 | /* No new signal delivery by default */ | ||
361 | current->thread.new_signal = 0; | ||
362 | #ifndef CONFIG_SMP | 360 | #ifndef CONFIG_SMP |
363 | if(last_task_used_math == current) { | 361 | if(last_task_used_math == current) { |
364 | #else | 362 | #else |
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 3e849e8e3480..3c312290c3c2 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* $Id: signal.c,v 1.110 2002/02/08 03:57:14 davem Exp $ | 1 | /* linux/arch/sparc/kernel/signal.c |
2 | * linux/arch/sparc/kernel/signal.c | ||
3 | * | 2 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) |
@@ -32,37 +31,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, | |||
32 | void *fpqueue, unsigned long *fpqdepth); | 31 | void *fpqueue, unsigned long *fpqdepth); |
33 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); | 32 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); |
34 | 33 | ||
35 | /* Signal frames: the original one (compatible with SunOS): | 34 | struct signal_frame { |
36 | * | ||
37 | * Set up a signal frame... Make the stack look the way SunOS | ||
38 | * expects it to look which is basically: | ||
39 | * | ||
40 | * ---------------------------------- <-- %sp at signal time | ||
41 | * Struct sigcontext | ||
42 | * Signal address | ||
43 | * Ptr to sigcontext area above | ||
44 | * Signal code | ||
45 | * The signal number itself | ||
46 | * One register window | ||
47 | * ---------------------------------- <-- New %sp | ||
48 | */ | ||
49 | struct signal_sframe { | ||
50 | struct reg_window sig_window; | ||
51 | int sig_num; | ||
52 | int sig_code; | ||
53 | struct sigcontext __user *sig_scptr; | ||
54 | int sig_address; | ||
55 | struct sigcontext sig_context; | ||
56 | unsigned int extramask[_NSIG_WORDS - 1]; | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * And the new one, intended to be used for Linux applications only | ||
61 | * (we have enough in there to work with clone). | ||
62 | * All the interesting bits are in the info field. | ||
63 | */ | ||
64 | |||
65 | struct new_signal_frame { | ||
66 | struct sparc_stackf ss; | 35 | struct sparc_stackf ss; |
67 | __siginfo_t info; | 36 | __siginfo_t info; |
68 | __siginfo_fpu_t __user *fpu_save; | 37 | __siginfo_fpu_t __user *fpu_save; |
@@ -85,8 +54,7 @@ struct rt_signal_frame { | |||
85 | }; | 54 | }; |
86 | 55 | ||
87 | /* Align macros */ | 56 | /* Align macros */ |
88 | #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7))) | 57 | #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) |
89 | #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) | ||
90 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) | 58 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) |
91 | 59 | ||
92 | static int _sigpause_common(old_sigset_t set) | 60 | static int _sigpause_common(old_sigset_t set) |
@@ -141,15 +109,20 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | |||
141 | return err; | 109 | return err; |
142 | } | 110 | } |
143 | 111 | ||
144 | static inline void do_new_sigreturn (struct pt_regs *regs) | 112 | asmlinkage void do_sigreturn(struct pt_regs *regs) |
145 | { | 113 | { |
146 | struct new_signal_frame __user *sf; | 114 | struct signal_frame __user *sf; |
147 | unsigned long up_psr, pc, npc; | 115 | unsigned long up_psr, pc, npc; |
148 | sigset_t set; | 116 | sigset_t set; |
149 | __siginfo_fpu_t __user *fpu_save; | 117 | __siginfo_fpu_t __user *fpu_save; |
150 | int err; | 118 | int err; |
151 | 119 | ||
152 | sf = (struct new_signal_frame __user *) regs->u_regs[UREG_FP]; | 120 | /* Always make any pending restarted system calls return -EINTR */ |
121 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
122 | |||
123 | synchronize_user_stack(); | ||
124 | |||
125 | sf = (struct signal_frame __user *) regs->u_regs[UREG_FP]; | ||
153 | 126 | ||
154 | /* 1. Make sure we are not getting garbage from the user */ | 127 | /* 1. Make sure we are not getting garbage from the user */ |
155 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) | 128 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) |
@@ -198,73 +171,6 @@ segv_and_exit: | |||
198 | force_sig(SIGSEGV, current); | 171 | force_sig(SIGSEGV, current); |
199 | } | 172 | } |
200 | 173 | ||
201 | asmlinkage void do_sigreturn(struct pt_regs *regs) | ||
202 | { | ||
203 | struct sigcontext __user *scptr; | ||
204 | unsigned long pc, npc, psr; | ||
205 | sigset_t set; | ||
206 | int err; | ||
207 | |||
208 | /* Always make any pending restarted system calls return -EINTR */ | ||
209 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
210 | |||
211 | synchronize_user_stack(); | ||
212 | |||
213 | if (current->thread.new_signal) { | ||
214 | do_new_sigreturn(regs); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | scptr = (struct sigcontext __user *) regs->u_regs[UREG_I0]; | ||
219 | |||
220 | /* Check sanity of the user arg. */ | ||
221 | if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext)) || | ||
222 | (((unsigned long) scptr) & 3)) | ||
223 | goto segv_and_exit; | ||
224 | |||
225 | err = __get_user(pc, &scptr->sigc_pc); | ||
226 | err |= __get_user(npc, &scptr->sigc_npc); | ||
227 | |||
228 | if ((pc | npc) & 3) | ||
229 | goto segv_and_exit; | ||
230 | |||
231 | /* This is pretty much atomic, no amount locking would prevent | ||
232 | * the races which exist anyways. | ||
233 | */ | ||
234 | err |= __get_user(set.sig[0], &scptr->sigc_mask); | ||
235 | /* Note that scptr + 1 points to extramask */ | ||
236 | err |= __copy_from_user(&set.sig[1], scptr + 1, | ||
237 | (_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
238 | |||
239 | if (err) | ||
240 | goto segv_and_exit; | ||
241 | |||
242 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
243 | spin_lock_irq(¤t->sighand->siglock); | ||
244 | current->blocked = set; | ||
245 | recalc_sigpending(); | ||
246 | spin_unlock_irq(¤t->sighand->siglock); | ||
247 | |||
248 | regs->pc = pc; | ||
249 | regs->npc = npc; | ||
250 | |||
251 | err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); | ||
252 | err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); | ||
253 | err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); | ||
254 | |||
255 | /* User can only change condition codes in %psr. */ | ||
256 | err |= __get_user(psr, &scptr->sigc_psr); | ||
257 | if (err) | ||
258 | goto segv_and_exit; | ||
259 | |||
260 | regs->psr &= ~(PSR_ICC); | ||
261 | regs->psr |= (psr & PSR_ICC); | ||
262 | return; | ||
263 | |||
264 | segv_and_exit: | ||
265 | force_sig(SIGSEGV, current); | ||
266 | } | ||
267 | |||
268 | asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | 174 | asmlinkage void do_rt_sigreturn(struct pt_regs *regs) |
269 | { | 175 | { |
270 | struct rt_signal_frame __user *sf; | 176 | struct rt_signal_frame __user *sf; |
@@ -351,128 +257,6 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re | |||
351 | return (void __user *)(sp - framesize); | 257 | return (void __user *)(sp - framesize); |
352 | } | 258 | } |
353 | 259 | ||
354 | static inline void | ||
355 | setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *oldset, siginfo_t *info) | ||
356 | { | ||
357 | struct signal_sframe __user *sframep; | ||
358 | struct sigcontext __user *sc; | ||
359 | int window = 0, err; | ||
360 | unsigned long pc = regs->pc; | ||
361 | unsigned long npc = regs->npc; | ||
362 | struct thread_info *tp = current_thread_info(); | ||
363 | void __user *sig_address; | ||
364 | int sig_code; | ||
365 | |||
366 | synchronize_user_stack(); | ||
367 | sframep = (struct signal_sframe __user *) | ||
368 | get_sigframe(sa, regs, SF_ALIGNEDSZ); | ||
369 | if (invalid_frame_pointer(sframep, sizeof(*sframep))){ | ||
370 | /* Don't change signal code and address, so that | ||
371 | * post mortem debuggers can have a look. | ||
372 | */ | ||
373 | goto sigill_and_return; | ||
374 | } | ||
375 | |||
376 | sc = &sframep->sig_context; | ||
377 | |||
378 | /* We've already made sure frame pointer isn't in kernel space... */ | ||
379 | err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), | ||
380 | &sc->sigc_onstack); | ||
381 | err |= __put_user(oldset->sig[0], &sc->sigc_mask); | ||
382 | err |= __copy_to_user(sframep->extramask, &oldset->sig[1], | ||
383 | (_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
384 | err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); | ||
385 | err |= __put_user(pc, &sc->sigc_pc); | ||
386 | err |= __put_user(npc, &sc->sigc_npc); | ||
387 | err |= __put_user(regs->psr, &sc->sigc_psr); | ||
388 | err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); | ||
389 | err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); | ||
390 | err |= __put_user(tp->w_saved, &sc->sigc_oswins); | ||
391 | if (tp->w_saved) | ||
392 | for (window = 0; window < tp->w_saved; window++) { | ||
393 | put_user((char *)tp->rwbuf_stkptrs[window], | ||
394 | &sc->sigc_spbuf[window]); | ||
395 | err |= __copy_to_user(&sc->sigc_wbuf[window], | ||
396 | &tp->reg_window[window], | ||
397 | sizeof(struct reg_window)); | ||
398 | } | ||
399 | else | ||
400 | err |= __copy_to_user(sframep, (char *) regs->u_regs[UREG_FP], | ||
401 | sizeof(struct reg_window)); | ||
402 | |||
403 | tp->w_saved = 0; /* So process is allowed to execute. */ | ||
404 | |||
405 | err |= __put_user(signr, &sframep->sig_num); | ||
406 | sig_address = NULL; | ||
407 | sig_code = 0; | ||
408 | if (SI_FROMKERNEL (info) && (info->si_code & __SI_MASK) == __SI_FAULT) { | ||
409 | sig_address = info->si_addr; | ||
410 | switch (signr) { | ||
411 | case SIGSEGV: | ||
412 | switch (info->si_code) { | ||
413 | case SEGV_MAPERR: sig_code = SUBSIG_NOMAPPING; break; | ||
414 | default: sig_code = SUBSIG_PROTECTION; break; | ||
415 | } | ||
416 | break; | ||
417 | case SIGILL: | ||
418 | switch (info->si_code) { | ||
419 | case ILL_ILLOPC: sig_code = SUBSIG_ILLINST; break; | ||
420 | case ILL_PRVOPC: sig_code = SUBSIG_PRIVINST; break; | ||
421 | case ILL_ILLTRP: sig_code = SUBSIG_BADTRAP(info->si_trapno); break; | ||
422 | default: sig_code = SUBSIG_STACK; break; | ||
423 | } | ||
424 | break; | ||
425 | case SIGFPE: | ||
426 | switch (info->si_code) { | ||
427 | case FPE_INTDIV: sig_code = SUBSIG_IDIVZERO; break; | ||
428 | case FPE_INTOVF: sig_code = SUBSIG_FPINTOVFL; break; | ||
429 | case FPE_FLTDIV: sig_code = SUBSIG_FPDIVZERO; break; | ||
430 | case FPE_FLTOVF: sig_code = SUBSIG_FPOVFLOW; break; | ||
431 | case FPE_FLTUND: sig_code = SUBSIG_FPUNFLOW; break; | ||
432 | case FPE_FLTRES: sig_code = SUBSIG_FPINEXACT; break; | ||
433 | case FPE_FLTINV: sig_code = SUBSIG_FPOPERROR; break; | ||
434 | default: sig_code = SUBSIG_FPERROR; break; | ||
435 | } | ||
436 | break; | ||
437 | case SIGBUS: | ||
438 | switch (info->si_code) { | ||
439 | case BUS_ADRALN: sig_code = SUBSIG_ALIGNMENT; break; | ||
440 | case BUS_ADRERR: sig_code = SUBSIG_MISCERROR; break; | ||
441 | default: sig_code = SUBSIG_BUSTIMEOUT; break; | ||
442 | } | ||
443 | break; | ||
444 | case SIGEMT: | ||
445 | switch (info->si_code) { | ||
446 | case EMT_TAGOVF: sig_code = SUBSIG_TAG; break; | ||
447 | } | ||
448 | break; | ||
449 | case SIGSYS: | ||
450 | if (info->si_code == (__SI_FAULT|0x100)) { | ||
451 | sig_code = info->si_trapno; | ||
452 | break; | ||
453 | } | ||
454 | default: | ||
455 | sig_address = NULL; | ||
456 | } | ||
457 | } | ||
458 | err |= __put_user((unsigned long)sig_address, &sframep->sig_address); | ||
459 | err |= __put_user(sig_code, &sframep->sig_code); | ||
460 | err |= __put_user(sc, &sframep->sig_scptr); | ||
461 | if (err) | ||
462 | goto sigsegv; | ||
463 | |||
464 | regs->u_regs[UREG_FP] = (unsigned long) sframep; | ||
465 | regs->pc = (unsigned long) sa->sa_handler; | ||
466 | regs->npc = (regs->pc + 4); | ||
467 | return; | ||
468 | |||
469 | sigill_and_return: | ||
470 | do_exit(SIGILL); | ||
471 | sigsegv: | ||
472 | force_sigsegv(signr, current); | ||
473 | } | ||
474 | |||
475 | |||
476 | static inline int | 260 | static inline int |
477 | save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | 261 | save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) |
478 | { | 262 | { |
@@ -508,21 +292,20 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | |||
508 | return err; | 292 | return err; |
509 | } | 293 | } |
510 | 294 | ||
511 | static inline void | 295 | static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, |
512 | new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | 296 | int signo, sigset_t *oldset) |
513 | int signo, sigset_t *oldset) | ||
514 | { | 297 | { |
515 | struct new_signal_frame __user *sf; | 298 | struct signal_frame __user *sf; |
516 | int sigframe_size, err; | 299 | int sigframe_size, err; |
517 | 300 | ||
518 | /* 1. Make sure everything is clean */ | 301 | /* 1. Make sure everything is clean */ |
519 | synchronize_user_stack(); | 302 | synchronize_user_stack(); |
520 | 303 | ||
521 | sigframe_size = NF_ALIGNEDSZ; | 304 | sigframe_size = SF_ALIGNEDSZ; |
522 | if (!used_math()) | 305 | if (!used_math()) |
523 | sigframe_size -= sizeof(__siginfo_fpu_t); | 306 | sigframe_size -= sizeof(__siginfo_fpu_t); |
524 | 307 | ||
525 | sf = (struct new_signal_frame __user *) | 308 | sf = (struct signal_frame __user *) |
526 | get_sigframe(&ka->sa, regs, sigframe_size); | 309 | get_sigframe(&ka->sa, regs, sigframe_size); |
527 | 310 | ||
528 | if (invalid_frame_pointer(sf, sigframe_size)) | 311 | if (invalid_frame_pointer(sf, sigframe_size)) |
@@ -586,9 +369,8 @@ sigsegv: | |||
586 | force_sigsegv(signo, current); | 369 | force_sigsegv(signo, current); |
587 | } | 370 | } |
588 | 371 | ||
589 | static inline void | 372 | static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, |
590 | new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | 373 | int signo, sigset_t *oldset, siginfo_t *info) |
591 | int signo, sigset_t *oldset, siginfo_t *info) | ||
592 | { | 374 | { |
593 | struct rt_signal_frame __user *sf; | 375 | struct rt_signal_frame __user *sf; |
594 | int sigframe_size; | 376 | int sigframe_size; |
@@ -674,11 +456,9 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, | |||
674 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) | 456 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) |
675 | { | 457 | { |
676 | if (ka->sa.sa_flags & SA_SIGINFO) | 458 | if (ka->sa.sa_flags & SA_SIGINFO) |
677 | new_setup_rt_frame(ka, regs, signr, oldset, info); | 459 | setup_rt_frame(ka, regs, signr, oldset, info); |
678 | else if (current->thread.new_signal) | ||
679 | new_setup_frame(ka, regs, signr, oldset); | ||
680 | else | 460 | else |
681 | setup_frame(&ka->sa, regs, signr, oldset, info); | 461 | setup_frame(ka, regs, signr, oldset); |
682 | 462 | ||
683 | spin_lock_irq(¤t->sighand->siglock); | 463 | spin_lock_irq(¤t->sighand->siglock); |
684 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 464 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 42bf09db9a81..f188b5dc9fd0 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* $Id: sys_sparc.c,v 1.70 2001/04/14 01:12:02 davem Exp $ | 1 | /* linux/arch/sparc/kernel/sys_sparc.c |
2 | * linux/arch/sparc/kernel/sys_sparc.c | ||
3 | * | 2 | * |
4 | * This file contains various random system calls that | 3 | * This file contains various random system calls that |
5 | * have a non-standard calling sequence on the Linux/sparc | 4 | * have a non-standard calling sequence on the Linux/sparc |
@@ -395,10 +394,8 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act, | |||
395 | struct k_sigaction new_ka, old_ka; | 394 | struct k_sigaction new_ka, old_ka; |
396 | int ret; | 395 | int ret; |
397 | 396 | ||
398 | if (sig < 0) { | 397 | WARN_ON_ONCE(sig >= 0); |
399 | current->thread.new_signal = 1; | 398 | sig = -sig; |
400 | sig = -sig; | ||
401 | } | ||
402 | 399 | ||
403 | if (act) { | 400 | if (act) { |
404 | unsigned long mask; | 401 | unsigned long mask; |
@@ -446,11 +443,6 @@ sys_rt_sigaction(int sig, | |||
446 | if (sigsetsize != sizeof(sigset_t)) | 443 | if (sigsetsize != sizeof(sigset_t)) |
447 | return -EINVAL; | 444 | return -EINVAL; |
448 | 445 | ||
449 | /* All tasks which use RT signals (effectively) use | ||
450 | * new style signals. | ||
451 | */ | ||
452 | current->thread.new_signal = 1; | ||
453 | |||
454 | if (act) { | 446 | if (act) { |
455 | new_ka.ka_restorer = restorer; | 447 | new_ka.ka_restorer = restorer; |
456 | if (copy_from_user(&new_ka.sa, act, sizeof(*act))) | 448 | if (copy_from_user(&new_ka.sa, act, sizeof(*act))) |
diff --git a/arch/sparc/lib/iomap.c b/arch/sparc/lib/iomap.c index 54501c1ca785..9ef37e13a920 100644 --- a/arch/sparc/lib/iomap.c +++ b/arch/sparc/lib/iomap.c | |||
@@ -21,8 +21,8 @@ EXPORT_SYMBOL(ioport_unmap); | |||
21 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ | 21 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ |
22 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 22 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
23 | { | 23 | { |
24 | unsigned long start = pci_resource_start(dev, bar); | 24 | resource_size_t start = pci_resource_start(dev, bar); |
25 | unsigned long len = pci_resource_len(dev, bar); | 25 | resource_size_t len = pci_resource_len(dev, bar); |
26 | unsigned long flags = pci_resource_flags(dev, bar); | 26 | unsigned long flags = pci_resource_flags(dev, bar); |
27 | 27 | ||
28 | if (!len || !start) | 28 | if (!len || !start) |
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 8acc5cc38621..edbe71e3fab9 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig | |||
@@ -1,9 +1,5 @@ | |||
1 | # $Id: config.in,v 1.158 2002/01/24 22:14:44 davem Exp $ | 1 | # sparc64 configuration |
2 | # For a description of the syntax of this configuration file, | 2 | mainmenu "Linux Kernel Configuration for 64-bit SPARC" |
3 | # see the Configure script. | ||
4 | # | ||
5 | |||
6 | mainmenu "Linux/UltraSPARC Kernel Configuration" | ||
7 | 3 | ||
8 | config SPARC | 4 | config SPARC |
9 | bool | 5 | bool |
@@ -17,12 +13,6 @@ config SPARC64 | |||
17 | default y | 13 | default y |
18 | select HAVE_IDE | 14 | select HAVE_IDE |
19 | select HAVE_LMB | 15 | select HAVE_LMB |
20 | help | ||
21 | SPARC is a family of RISC microprocessors designed and marketed by | ||
22 | Sun Microsystems, incorporated. This port covers the newer 64-bit | ||
23 | UltraSPARC. The UltraLinux project maintains both the SPARC32 and | ||
24 | SPARC64 ports; its web page is available at | ||
25 | <http://www.ultralinux.org/>. | ||
26 | 16 | ||
27 | config GENERIC_TIME | 17 | config GENERIC_TIME |
28 | bool | 18 | bool |
@@ -97,7 +87,7 @@ config SPARC64_PAGE_SIZE_8KB | |||
97 | help | 87 | help |
98 | This lets you select the page size of the kernel. | 88 | This lets you select the page size of the kernel. |
99 | 89 | ||
100 | 8KB and 64KB work quite well, since Sparc ELF sections | 90 | 8KB and 64KB work quite well, since SPARC ELF sections |
101 | provide for up to 64KB alignment. | 91 | provide for up to 64KB alignment. |
102 | 92 | ||
103 | Therefore, 512KB and 4MB are for expert hackers only. | 93 | Therefore, 512KB and 4MB are for expert hackers only. |
@@ -138,7 +128,7 @@ config HOTPLUG_CPU | |||
138 | bool "Support for hot-pluggable CPUs" | 128 | bool "Support for hot-pluggable CPUs" |
139 | depends on SMP | 129 | depends on SMP |
140 | select HOTPLUG | 130 | select HOTPLUG |
141 | ---help--- | 131 | help |
142 | Say Y here to experiment with turning CPUs off and on. CPUs | 132 | Say Y here to experiment with turning CPUs off and on. CPUs |
143 | can be controlled through /sys/devices/system/cpu/cpu#. | 133 | can be controlled through /sys/devices/system/cpu/cpu#. |
144 | Say N if you want to disable CPU hotplug. | 134 | Say N if you want to disable CPU hotplug. |
@@ -155,23 +145,16 @@ source "kernel/time/Kconfig" | |||
155 | 145 | ||
156 | config SMP | 146 | config SMP |
157 | bool "Symmetric multi-processing support" | 147 | bool "Symmetric multi-processing support" |
158 | ---help--- | 148 | help |
159 | This enables support for systems with more than one CPU. If you have | 149 | This enables support for systems with more than one CPU. If you have |
160 | a system with only one CPU, say N. If you have a system with more than | 150 | a system with only one CPU, say N. If you have a system with more than |
161 | one CPU, say Y. | 151 | one CPU, say Y. |
162 | 152 | ||
163 | If you say N here, the kernel will run on single and multiprocessor | 153 | If you say N here, the kernel will run on single and multiprocessor |
164 | machines, but will use only one CPU of a multiprocessor machine. If | 154 | machines, but will use only one CPU of a multiprocessor machine. If |
165 | you say Y here, the kernel will run on many, but not all, | 155 | you say Y here, the kernel will run on single-processor machines. |
166 | singleprocessor machines. On a singleprocessor machine, the kernel | 156 | On a single-processor machine, the kernel will run faster if you say |
167 | will run faster if you say N here. | 157 | N here. |
168 | |||
169 | People using multiprocessor machines who say Y here should also say | ||
170 | Y to "Enhanced Real Time Clock Support", below. The "Advanced Power | ||
171 | Management" code will be disabled if you say Y here. | ||
172 | |||
173 | See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO | ||
174 | available at <http://www.tldp.org/docs.html#howto>. | ||
175 | 158 | ||
176 | If you don't know what to do here, say N. | 159 | If you don't know what to do here, say N. |
177 | 160 | ||
@@ -284,50 +267,19 @@ source "mm/Kconfig" | |||
284 | 267 | ||
285 | config ISA | 268 | config ISA |
286 | bool | 269 | bool |
287 | help | ||
288 | Find out whether you have ISA slots on your motherboard. ISA is the | ||
289 | name of a bus system, i.e. the way the CPU talks to the other stuff | ||
290 | inside your box. Other bus systems are PCI, EISA, MicroChannel | ||
291 | (MCA) or VESA. ISA is an older system, now being displaced by PCI; | ||
292 | newer boards don't support it. If you have ISA, say Y, otherwise N. | ||
293 | 270 | ||
294 | config ISAPNP | 271 | config ISAPNP |
295 | bool | 272 | bool |
296 | help | ||
297 | Say Y here if you would like support for ISA Plug and Play devices. | ||
298 | Some information is in <file:Documentation/isapnp.txt>. | ||
299 | |||
300 | To compile this driver as a module, choose M here: the | ||
301 | module will be called isapnp. | ||
302 | |||
303 | If unsure, say Y. | ||
304 | 273 | ||
305 | config EISA | 274 | config EISA |
306 | bool | 275 | bool |
307 | ---help--- | ||
308 | The Extended Industry Standard Architecture (EISA) bus was | ||
309 | developed as an open alternative to the IBM MicroChannel bus. | ||
310 | |||
311 | The EISA bus provided some of the features of the IBM MicroChannel | ||
312 | bus while maintaining backward compatibility with cards made for | ||
313 | the older ISA bus. The EISA bus saw limited use between 1988 and | ||
314 | 1995 when it was made obsolete by the PCI bus. | ||
315 | |||
316 | Say Y here if you are building a kernel for an EISA-based machine. | ||
317 | |||
318 | Otherwise, say N. | ||
319 | 276 | ||
320 | config MCA | 277 | config MCA |
321 | bool | 278 | bool |
322 | help | ||
323 | MicroChannel Architecture is found in some IBM PS/2 machines and | ||
324 | laptops. It is a bus system similar to PCI or ISA. See | ||
325 | <file:Documentation/mca.txt> (and especially the web page given | ||
326 | there) before attempting to build an MCA bus kernel. | ||
327 | 279 | ||
328 | config PCMCIA | 280 | config PCMCIA |
329 | tristate | 281 | tristate |
330 | ---help--- | 282 | help |
331 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux | 283 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux |
332 | computer. These are credit-card size devices such as network cards, | 284 | computer. These are credit-card size devices such as network cards, |
333 | modems or hard drives often used with laptops computers. There are | 285 | modems or hard drives often used with laptops computers. There are |
@@ -369,10 +321,10 @@ config PCI | |||
369 | bool "PCI support" | 321 | bool "PCI support" |
370 | select ARCH_SUPPORTS_MSI | 322 | select ARCH_SUPPORTS_MSI |
371 | help | 323 | help |
372 | Find out whether you have a PCI motherboard. PCI is the name of a | 324 | Find out whether your system includes a PCI bus. PCI is the name of |
373 | bus system, i.e. the way the CPU talks to the other stuff inside | 325 | a bus system, i.e. the way the CPU talks to the other stuff inside |
374 | your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or | 326 | your box. If you say Y here, the kernel will include drivers and |
375 | VESA. If you have PCI, say Y, otherwise N. | 327 | infrastructure code to support PCI bus devices. |
376 | 328 | ||
377 | config PCI_DOMAINS | 329 | config PCI_DOMAINS |
378 | def_bool PCI | 330 | def_bool PCI |
@@ -396,15 +348,8 @@ menu "Executable file formats" | |||
396 | 348 | ||
397 | source "fs/Kconfig.binfmt" | 349 | source "fs/Kconfig.binfmt" |
398 | 350 | ||
399 | config SPARC32_COMPAT | ||
400 | bool "Kernel support for Linux/Sparc 32bit binary compatibility" | ||
401 | help | ||
402 | This allows you to run 32-bit binaries on your Ultra. | ||
403 | Everybody wants this; say Y. | ||
404 | |||
405 | config COMPAT | 351 | config COMPAT |
406 | bool | 352 | bool |
407 | depends on SPARC32_COMPAT | ||
408 | default y | 353 | default y |
409 | select COMPAT_BINFMT_ELF | 354 | select COMPAT_BINFMT_ELF |
410 | 355 | ||
@@ -421,8 +366,8 @@ config SCHED_SMT | |||
421 | default y | 366 | default y |
422 | help | 367 | help |
423 | SMT scheduler support improves the CPU scheduler's decision making | 368 | SMT scheduler support improves the CPU scheduler's decision making |
424 | when dealing with UltraSPARC cpus at a cost of slightly increased | 369 | when dealing with SPARC cpus at a cost of slightly increased overhead |
425 | overhead in some places. If unsure say N here. | 370 | in some places. If unsure say N here. |
426 | 371 | ||
427 | config SCHED_MC | 372 | config SCHED_MC |
428 | bool "Multi-core scheduler support" | 373 | bool "Multi-core scheduler support" |
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 92f79680f70d..aff93c9d13f4 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.25-numa | 3 | # Linux kernel version: 2.6.25 |
4 | # Wed Apr 23 04:49:08 2008 | 4 | # Sat Apr 26 03:11:06 2008 |
5 | # | 5 | # |
6 | CONFIG_SPARC=y | 6 | CONFIG_SPARC=y |
7 | CONFIG_SPARC64=y | 7 | CONFIG_SPARC64=y |
@@ -152,7 +152,9 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y | |||
152 | CONFIG_HUGETLB_PAGE_SIZE_4MB=y | 152 | CONFIG_HUGETLB_PAGE_SIZE_4MB=y |
153 | # CONFIG_HUGETLB_PAGE_SIZE_512K is not set | 153 | # CONFIG_HUGETLB_PAGE_SIZE_512K is not set |
154 | # CONFIG_HUGETLB_PAGE_SIZE_64K is not set | 154 | # CONFIG_HUGETLB_PAGE_SIZE_64K is not set |
155 | # CONFIG_NUMA is not set | 155 | CONFIG_NUMA=y |
156 | CONFIG_NODES_SHIFT=4 | ||
157 | CONFIG_NODES_SPAN_OTHER_NODES=y | ||
156 | CONFIG_ARCH_POPULATES_NODE_MAP=y | 158 | CONFIG_ARCH_POPULATES_NODE_MAP=y |
157 | CONFIG_ARCH_SELECT_MEMORY_MODEL=y | 159 | CONFIG_ARCH_SELECT_MEMORY_MODEL=y |
158 | CONFIG_ARCH_SPARSEMEM_ENABLE=y | 160 | CONFIG_ARCH_SPARSEMEM_ENABLE=y |
@@ -162,12 +164,14 @@ CONFIG_SELECT_MEMORY_MODEL=y | |||
162 | # CONFIG_DISCONTIGMEM_MANUAL is not set | 164 | # CONFIG_DISCONTIGMEM_MANUAL is not set |
163 | CONFIG_SPARSEMEM_MANUAL=y | 165 | CONFIG_SPARSEMEM_MANUAL=y |
164 | CONFIG_SPARSEMEM=y | 166 | CONFIG_SPARSEMEM=y |
167 | CONFIG_NEED_MULTIPLE_NODES=y | ||
165 | CONFIG_HAVE_MEMORY_PRESENT=y | 168 | CONFIG_HAVE_MEMORY_PRESENT=y |
166 | # CONFIG_SPARSEMEM_STATIC is not set | 169 | # CONFIG_SPARSEMEM_STATIC is not set |
167 | CONFIG_SPARSEMEM_EXTREME=y | 170 | CONFIG_SPARSEMEM_EXTREME=y |
168 | CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y | 171 | CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y |
169 | CONFIG_SPARSEMEM_VMEMMAP=y | 172 | CONFIG_SPARSEMEM_VMEMMAP=y |
170 | CONFIG_SPLIT_PTLOCK_CPUS=4 | 173 | CONFIG_SPLIT_PTLOCK_CPUS=4 |
174 | CONFIG_MIGRATION=y | ||
171 | CONFIG_RESOURCES_64BIT=y | 175 | CONFIG_RESOURCES_64BIT=y |
172 | CONFIG_ZONE_DMA_FLAG=0 | 176 | CONFIG_ZONE_DMA_FLAG=0 |
173 | CONFIG_NR_QUICK=1 | 177 | CONFIG_NR_QUICK=1 |
@@ -191,7 +195,6 @@ CONFIG_SUN_OPENPROMFS=m | |||
191 | CONFIG_BINFMT_ELF=y | 195 | CONFIG_BINFMT_ELF=y |
192 | CONFIG_COMPAT_BINFMT_ELF=y | 196 | CONFIG_COMPAT_BINFMT_ELF=y |
193 | CONFIG_BINFMT_MISC=m | 197 | CONFIG_BINFMT_MISC=m |
194 | CONFIG_SPARC32_COMPAT=y | ||
195 | CONFIG_COMPAT=y | 198 | CONFIG_COMPAT=y |
196 | CONFIG_SYSVIPC_COMPAT=y | 199 | CONFIG_SYSVIPC_COMPAT=y |
197 | CONFIG_SCHED_SMT=y | 200 | CONFIG_SCHED_SMT=y |
@@ -746,13 +749,7 @@ CONFIG_DEVPORT=y | |||
746 | CONFIG_I2C=y | 749 | CONFIG_I2C=y |
747 | CONFIG_I2C_BOARDINFO=y | 750 | CONFIG_I2C_BOARDINFO=y |
748 | # CONFIG_I2C_CHARDEV is not set | 751 | # CONFIG_I2C_CHARDEV is not set |
749 | |||
750 | # | ||
751 | # I2C Algorithms | ||
752 | # | ||
753 | CONFIG_I2C_ALGOBIT=y | 752 | CONFIG_I2C_ALGOBIT=y |
754 | # CONFIG_I2C_ALGOPCF is not set | ||
755 | # CONFIG_I2C_ALGOPCA is not set | ||
756 | 753 | ||
757 | # | 754 | # |
758 | # I2C Hardware Bus support | 755 | # I2C Hardware Bus support |
@@ -780,6 +777,7 @@ CONFIG_I2C_ALGOBIT=y | |||
780 | # CONFIG_I2C_VIA is not set | 777 | # CONFIG_I2C_VIA is not set |
781 | # CONFIG_I2C_VIAPRO is not set | 778 | # CONFIG_I2C_VIAPRO is not set |
782 | # CONFIG_I2C_VOODOO3 is not set | 779 | # CONFIG_I2C_VOODOO3 is not set |
780 | # CONFIG_I2C_PCA_PLATFORM is not set | ||
783 | 781 | ||
784 | # | 782 | # |
785 | # Miscellaneous I2C Chip support | 783 | # Miscellaneous I2C Chip support |
@@ -1026,6 +1024,7 @@ CONFIG_SND_ALI5451=m | |||
1026 | # CONFIG_SND_AU8810 is not set | 1024 | # CONFIG_SND_AU8810 is not set |
1027 | # CONFIG_SND_AU8820 is not set | 1025 | # CONFIG_SND_AU8820 is not set |
1028 | # CONFIG_SND_AU8830 is not set | 1026 | # CONFIG_SND_AU8830 is not set |
1027 | # CONFIG_SND_AW2 is not set | ||
1029 | # CONFIG_SND_AZT3328 is not set | 1028 | # CONFIG_SND_AZT3328 is not set |
1030 | # CONFIG_SND_BT87X is not set | 1029 | # CONFIG_SND_BT87X is not set |
1031 | # CONFIG_SND_CA0106 is not set | 1030 | # CONFIG_SND_CA0106 is not set |
@@ -1097,10 +1096,6 @@ CONFIG_SND_SUN_CS4231=m | |||
1097 | # CONFIG_SND_SOC is not set | 1096 | # CONFIG_SND_SOC is not set |
1098 | 1097 | ||
1099 | # | 1098 | # |
1100 | # SoC Audio support for SuperH | ||
1101 | # | ||
1102 | |||
1103 | # | ||
1104 | # ALSA SoC audio for Freescale SOCs | 1099 | # ALSA SoC audio for Freescale SOCs |
1105 | # | 1100 | # |
1106 | 1101 | ||
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 63c6ae0dd273..2bd0340b743d 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile | |||
@@ -15,17 +15,17 @@ obj-y := process.o setup.o cpu.o idprom.o \ | |||
15 | visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o | 15 | visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o |
16 | 16 | ||
17 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 17 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
18 | obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \ | 18 | obj-$(CONFIG_PCI) += ebus.o pci_common.o \ |
19 | pci_psycho.o pci_sabre.o pci_schizo.o \ | 19 | pci_psycho.o pci_sabre.o pci_schizo.o \ |
20 | pci_sun4v.o pci_sun4v_asm.o pci_fire.o | 20 | pci_sun4v.o pci_sun4v_asm.o pci_fire.o |
21 | obj-$(CONFIG_PCI_MSI) += pci_msi.o | 21 | obj-$(CONFIG_PCI_MSI) += pci_msi.o |
22 | obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o | 22 | obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o |
23 | obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o | 23 | obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o |
24 | obj-$(CONFIG_MODULES) += module.o | 24 | obj-$(CONFIG_MODULES) += module.o |
25 | obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o | 25 | obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o |
26 | obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o | 26 | obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o |
27 | obj-$(CONFIG_KPROBES) += kprobes.o | 27 | obj-$(CONFIG_KPROBES) += kprobes.o |
28 | obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o | 28 | obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o |
29 | obj-$(CONFIG_AUDIT) += audit.o | 29 | obj-$(CONFIG_AUDIT) += audit.o |
30 | obj-$(CONFIG_AUDIT)$(CONFIG_SPARC32_COMPAT) += compat_audit.o | 30 | obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o |
31 | obj-y += $(obj-yy) | 31 | obj-y += $(obj-yy) |
diff --git a/arch/sparc64/kernel/audit.c b/arch/sparc64/kernel/audit.c index 24d7f4b4178a..8fff0ac63d56 100644 --- a/arch/sparc64/kernel/audit.c +++ b/arch/sparc64/kernel/audit.c | |||
@@ -30,7 +30,7 @@ static unsigned signal_class[] = { | |||
30 | 30 | ||
31 | int audit_classify_arch(int arch) | 31 | int audit_classify_arch(int arch) |
32 | { | 32 | { |
33 | #ifdef CONFIG_SPARC32_COMPAT | 33 | #ifdef CONFIG_COMPAT |
34 | if (arch == AUDIT_ARCH_SPARC) | 34 | if (arch == AUDIT_ARCH_SPARC) |
35 | return 1; | 35 | return 1; |
36 | #endif | 36 | #endif |
@@ -39,7 +39,7 @@ int audit_classify_arch(int arch) | |||
39 | 39 | ||
40 | int audit_classify_syscall(int abi, unsigned syscall) | 40 | int audit_classify_syscall(int abi, unsigned syscall) |
41 | { | 41 | { |
42 | #ifdef CONFIG_SPARC32_COMPAT | 42 | #ifdef CONFIG_COMPAT |
43 | extern int sparc32_classify_syscall(unsigned); | 43 | extern int sparc32_classify_syscall(unsigned); |
44 | if (abi == AUDIT_ARCH_SPARC) | 44 | if (abi == AUDIT_ARCH_SPARC) |
45 | return sparc32_classify_syscall(syscall); | 45 | return sparc32_classify_syscall(syscall); |
@@ -60,7 +60,7 @@ int audit_classify_syscall(int abi, unsigned syscall) | |||
60 | 60 | ||
61 | static int __init audit_classes_init(void) | 61 | static int __init audit_classes_init(void) |
62 | { | 62 | { |
63 | #ifdef CONFIG_SPARC32_COMPAT | 63 | #ifdef CONFIG_COMPAT |
64 | extern __u32 sparc32_dir_class[]; | 64 | extern __u32 sparc32_dir_class[]; |
65 | extern __u32 sparc32_write_class[]; | 65 | extern __u32 sparc32_write_class[]; |
66 | extern __u32 sparc32_read_class[]; | 66 | extern __u32 sparc32_read_class[]; |
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index eb88bd6e674e..b441a26b73b0 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* irq.c: UltraSparc IRQ handling/init/registry. | 1 | /* irq.c: UltraSparc IRQ handling/init/registry. |
2 | * | 2 | * |
3 | * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 1997, 2007, 2008 David S. Miller (davem@davemloft.net) |
4 | * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) | 4 | * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) |
5 | * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) | 5 | * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) |
6 | */ | 6 | */ |
@@ -308,6 +308,7 @@ static void sun4u_irq_enable(unsigned int virt_irq) | |||
308 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); | 308 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); |
309 | val |= tid | IMAP_VALID; | 309 | val |= tid | IMAP_VALID; |
310 | upa_writeq(val, imap); | 310 | upa_writeq(val, imap); |
311 | upa_writeq(ICLR_IDLE, data->iclr); | ||
311 | } | 312 | } |
312 | } | 313 | } |
313 | 314 | ||
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c deleted file mode 100644 index a2af5ed784c9..000000000000 --- a/arch/sparc64/kernel/isa.c +++ /dev/null | |||
@@ -1,191 +0,0 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/pci.h> | ||
4 | #include <linux/slab.h> | ||
5 | #include <asm/oplib.h> | ||
6 | #include <asm/prom.h> | ||
7 | #include <asm/of_device.h> | ||
8 | #include <asm/isa.h> | ||
9 | |||
10 | struct sparc_isa_bridge *isa_chain; | ||
11 | |||
12 | static void __init fatal_err(const char *reason) | ||
13 | { | ||
14 | prom_printf("ISA: fatal error, %s.\n", reason); | ||
15 | } | ||
16 | |||
17 | static void __init report_dev(struct sparc_isa_device *isa_dev, int child) | ||
18 | { | ||
19 | if (child) | ||
20 | printk(" (%s)", isa_dev->prom_node->name); | ||
21 | else | ||
22 | printk(" [%s", isa_dev->prom_node->name); | ||
23 | } | ||
24 | |||
25 | static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) | ||
26 | { | ||
27 | struct of_device *op = of_find_device_by_node(isa_dev->prom_node); | ||
28 | |||
29 | memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource)); | ||
30 | } | ||
31 | |||
32 | static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev) | ||
33 | { | ||
34 | struct of_device *op = of_find_device_by_node(isa_dev->prom_node); | ||
35 | |||
36 | if (!op || !op->num_irqs) { | ||
37 | isa_dev->irq = PCI_IRQ_NONE; | ||
38 | } else { | ||
39 | isa_dev->irq = op->irqs[0]; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) | ||
44 | { | ||
45 | struct device_node *dp = parent_isa_dev->prom_node->child; | ||
46 | |||
47 | if (!dp) | ||
48 | return; | ||
49 | |||
50 | printk(" ->"); | ||
51 | while (dp) { | ||
52 | struct sparc_isa_device *isa_dev; | ||
53 | |||
54 | isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL); | ||
55 | if (!isa_dev) { | ||
56 | fatal_err("cannot allocate child isa_dev"); | ||
57 | prom_halt(); | ||
58 | } | ||
59 | |||
60 | /* Link it in to parent. */ | ||
61 | isa_dev->next = parent_isa_dev->child; | ||
62 | parent_isa_dev->child = isa_dev; | ||
63 | |||
64 | isa_dev->bus = parent_isa_dev->bus; | ||
65 | isa_dev->prom_node = dp; | ||
66 | |||
67 | isa_dev_get_resource(isa_dev); | ||
68 | isa_dev_get_irq(isa_dev); | ||
69 | |||
70 | report_dev(isa_dev, 1); | ||
71 | |||
72 | dp = dp->sibling; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) | ||
77 | { | ||
78 | struct device_node *dp = isa_br->prom_node->child; | ||
79 | |||
80 | while (dp) { | ||
81 | struct sparc_isa_device *isa_dev; | ||
82 | struct dev_archdata *sd; | ||
83 | |||
84 | isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL); | ||
85 | if (!isa_dev) { | ||
86 | printk(KERN_DEBUG "ISA: cannot allocate isa_dev"); | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | sd = &isa_dev->ofdev.dev.archdata; | ||
91 | sd->prom_node = dp; | ||
92 | sd->op = &isa_dev->ofdev; | ||
93 | sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu; | ||
94 | sd->stc = isa_br->ofdev.dev.parent->archdata.stc; | ||
95 | sd->numa_node = isa_br->ofdev.dev.parent->archdata.numa_node; | ||
96 | |||
97 | isa_dev->ofdev.node = dp; | ||
98 | isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; | ||
99 | isa_dev->ofdev.dev.bus = &isa_bus_type; | ||
100 | sprintf(isa_dev->ofdev.dev.bus_id, "isa[%08x]", dp->node); | ||
101 | |||
102 | /* Register with core */ | ||
103 | if (of_device_register(&isa_dev->ofdev) != 0) { | ||
104 | printk(KERN_DEBUG "isa: device registration error for %s!\n", | ||
105 | dp->path_component_name); | ||
106 | kfree(isa_dev); | ||
107 | goto next_sibling; | ||
108 | } | ||
109 | |||
110 | /* Link it in. */ | ||
111 | isa_dev->next = NULL; | ||
112 | if (isa_br->devices == NULL) { | ||
113 | isa_br->devices = isa_dev; | ||
114 | } else { | ||
115 | struct sparc_isa_device *tmp = isa_br->devices; | ||
116 | |||
117 | while (tmp->next) | ||
118 | tmp = tmp->next; | ||
119 | |||
120 | tmp->next = isa_dev; | ||
121 | } | ||
122 | |||
123 | isa_dev->bus = isa_br; | ||
124 | isa_dev->prom_node = dp; | ||
125 | |||
126 | isa_dev_get_resource(isa_dev); | ||
127 | isa_dev_get_irq(isa_dev); | ||
128 | |||
129 | report_dev(isa_dev, 0); | ||
130 | |||
131 | isa_fill_children(isa_dev); | ||
132 | |||
133 | printk("]"); | ||
134 | |||
135 | next_sibling: | ||
136 | dp = dp->sibling; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | void __init isa_init(void) | ||
141 | { | ||
142 | struct pci_dev *pdev; | ||
143 | unsigned short vendor, device; | ||
144 | int index = 0; | ||
145 | |||
146 | vendor = PCI_VENDOR_ID_AL; | ||
147 | device = PCI_DEVICE_ID_AL_M1533; | ||
148 | |||
149 | pdev = NULL; | ||
150 | while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) { | ||
151 | struct sparc_isa_bridge *isa_br; | ||
152 | struct device_node *dp; | ||
153 | |||
154 | dp = pci_device_to_OF_node(pdev); | ||
155 | |||
156 | isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL); | ||
157 | if (!isa_br) { | ||
158 | printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge"); | ||
159 | pci_dev_put(pdev); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | isa_br->ofdev.node = dp; | ||
164 | isa_br->ofdev.dev.parent = &pdev->dev; | ||
165 | isa_br->ofdev.dev.bus = &isa_bus_type; | ||
166 | sprintf(isa_br->ofdev.dev.bus_id, "isa%d", index); | ||
167 | |||
168 | /* Register with core */ | ||
169 | if (of_device_register(&isa_br->ofdev) != 0) { | ||
170 | printk(KERN_DEBUG "isa: device registration error for %s!\n", | ||
171 | dp->path_component_name); | ||
172 | kfree(isa_br); | ||
173 | pci_dev_put(pdev); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | /* Link it in. */ | ||
178 | isa_br->next = isa_chain; | ||
179 | isa_chain = isa_br; | ||
180 | |||
181 | isa_br->self = pdev; | ||
182 | isa_br->index = index++; | ||
183 | isa_br->prom_node = dp; | ||
184 | |||
185 | printk("isa%d:", isa_br->index); | ||
186 | |||
187 | isa_fill_devices(isa_br); | ||
188 | |||
189 | printk("\n"); | ||
190 | } | ||
191 | } | ||
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 9e58e8cba1c3..d569f60c24b8 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c | |||
@@ -412,12 +412,6 @@ static int __init build_one_resource(struct device_node *parent, | |||
412 | 412 | ||
413 | static int __init use_1to1_mapping(struct device_node *pp) | 413 | static int __init use_1to1_mapping(struct device_node *pp) |
414 | { | 414 | { |
415 | /* If this is on the PMU bus, don't try to translate it even | ||
416 | * if a ranges property exists. | ||
417 | */ | ||
418 | if (!strcmp(pp->name, "pmu")) | ||
419 | return 1; | ||
420 | |||
421 | /* If we have a ranges property in the parent, use it. */ | 415 | /* If we have a ranges property in the parent, use it. */ |
422 | if (of_find_property(pp, "ranges", NULL) != NULL) | 416 | if (of_find_property(pp, "ranges", NULL) != NULL) |
423 | return 0; | 417 | return 0; |
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 49f912766519..dbf2fc2f4d87 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
25 | #include <asm/ebus.h> | 25 | #include <asm/ebus.h> |
26 | #include <asm/isa.h> | ||
27 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
28 | #include <asm/apb.h> | 27 | #include <asm/apb.h> |
29 | 28 | ||
@@ -885,7 +884,6 @@ static int __init pcibios_init(void) | |||
885 | 884 | ||
886 | pci_scan_each_controller_bus(); | 885 | pci_scan_each_controller_bus(); |
887 | 886 | ||
888 | isa_init(); | ||
889 | ebus_init(); | 887 | ebus_init(); |
890 | power_init(); | 888 | power_init(); |
891 | 889 | ||
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index acf8c5250aa9..056013749157 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* $Id: process.c,v 1.131 2002/02/09 19:49:30 davem Exp $ | 1 | /* arch/sparc64/kernel/process.c |
2 | * arch/sparc64/kernel/process.c | ||
3 | * | 2 | * |
4 | * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) | 3 | * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) |
5 | * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) | 4 | * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) |
@@ -368,9 +367,6 @@ void flush_thread(void) | |||
368 | 367 | ||
369 | if (get_thread_current_ds() != ASI_AIUS) | 368 | if (get_thread_current_ds() != ASI_AIUS) |
370 | set_fs(USER_DS); | 369 | set_fs(USER_DS); |
371 | |||
372 | /* Init new signal delivery disposition. */ | ||
373 | clear_thread_flag(TIF_NEWSIGNALS); | ||
374 | } | 370 | } |
375 | 371 | ||
376 | /* It's a bit more tricky when 64-bit tasks are involved... */ | 372 | /* It's a bit more tricky when 64-bit tasks are involved... */ |
@@ -595,6 +591,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
595 | if (clone_flags & CLONE_SETTLS) | 591 | if (clone_flags & CLONE_SETTLS) |
596 | t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; | 592 | t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; |
597 | 593 | ||
594 | /* We do not want to accidently trigger system call restart | ||
595 | * handling in the new thread. Therefore, clear out the trap | ||
596 | * type, which will make pt_regs_regs_is_syscall() return false. | ||
597 | */ | ||
598 | pt_regs_clear_trap_type(t->kregs); | ||
599 | |||
598 | return 0; | 600 | return 0; |
599 | } | 601 | } |
600 | 602 | ||
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 77a3e8592cbc..f2d88d8f7a42 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 8 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifdef CONFIG_SPARC32_COMPAT | 11 | #ifdef CONFIG_COMPAT |
12 | #include <linux/compat.h> /* for compat_old_sigset_t */ | 12 | #include <linux/compat.h> /* for compat_old_sigset_t */ |
13 | #endif | 13 | #endif |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
@@ -236,9 +236,6 @@ struct rt_signal_frame { | |||
236 | __siginfo_fpu_t fpu_state; | 236 | __siginfo_fpu_t fpu_state; |
237 | }; | 237 | }; |
238 | 238 | ||
239 | /* Align macros */ | ||
240 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) | ||
241 | |||
242 | static long _sigpause_common(old_sigset_t set) | 239 | static long _sigpause_common(old_sigset_t set) |
243 | { | 240 | { |
244 | set &= _BLOCKABLE; | 241 | set &= _BLOCKABLE; |
@@ -400,7 +397,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
400 | synchronize_user_stack(); | 397 | synchronize_user_stack(); |
401 | save_and_clear_fpu(); | 398 | save_and_clear_fpu(); |
402 | 399 | ||
403 | sigframe_size = RT_ALIGNEDSZ; | 400 | sigframe_size = sizeof(struct rt_signal_frame); |
404 | if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) | 401 | if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) |
405 | sigframe_size -= sizeof(__siginfo_fpu_t); | 402 | sigframe_size -= sizeof(__siginfo_fpu_t); |
406 | 403 | ||
@@ -516,11 +513,10 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
516 | struct k_sigaction ka; | 513 | struct k_sigaction ka; |
517 | sigset_t *oldset; | 514 | sigset_t *oldset; |
518 | siginfo_t info; | 515 | siginfo_t info; |
519 | int signr, tt; | 516 | int signr; |
520 | 517 | ||
521 | tt = regs->magic & 0x1ff; | 518 | if (pt_regs_is_syscall(regs)) { |
522 | if (tt == 0x110 || tt == 0x111 || tt == 0x16d) { | 519 | pt_regs_clear_trap_type(regs); |
523 | regs->magic &= ~0x1ff; | ||
524 | cookie.restart_syscall = 1; | 520 | cookie.restart_syscall = 1; |
525 | } else | 521 | } else |
526 | cookie.restart_syscall = 0; | 522 | cookie.restart_syscall = 0; |
@@ -531,7 +527,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
531 | else | 527 | else |
532 | oldset = ¤t->blocked; | 528 | oldset = ¤t->blocked; |
533 | 529 | ||
534 | #ifdef CONFIG_SPARC32_COMPAT | 530 | #ifdef CONFIG_COMPAT |
535 | if (test_thread_flag(TIF_32BIT)) { | 531 | if (test_thread_flag(TIF_32BIT)) { |
536 | extern void do_signal32(sigset_t *, struct pt_regs *, | 532 | extern void do_signal32(sigset_t *, struct pt_regs *, |
537 | struct signal_deliver_cookie *); | 533 | struct signal_deliver_cookie *); |
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 43cdec64d9c9..91f8d0826db1 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* $Id: signal32.c,v 1.74 2002/02/09 19:49:30 davem Exp $ | 1 | /* arch/sparc64/kernel/signal32.c |
2 | * arch/sparc64/kernel/signal32.c | ||
3 | * | 2 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) |
@@ -31,30 +30,6 @@ | |||
31 | 30 | ||
32 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
33 | 32 | ||
34 | /* Signal frames: the original one (compatible with SunOS): | ||
35 | * | ||
36 | * Set up a signal frame... Make the stack look the way SunOS | ||
37 | * expects it to look which is basically: | ||
38 | * | ||
39 | * ---------------------------------- <-- %sp at signal time | ||
40 | * Struct sigcontext | ||
41 | * Signal address | ||
42 | * Ptr to sigcontext area above | ||
43 | * Signal code | ||
44 | * The signal number itself | ||
45 | * One register window | ||
46 | * ---------------------------------- <-- New %sp | ||
47 | */ | ||
48 | struct signal_sframe32 { | ||
49 | struct reg_window32 sig_window; | ||
50 | int sig_num; | ||
51 | int sig_code; | ||
52 | /* struct sigcontext32 * */ u32 sig_scptr; | ||
53 | int sig_address; | ||
54 | struct sigcontext32 sig_context; | ||
55 | unsigned int extramask[_COMPAT_NSIG_WORDS - 1]; | ||
56 | }; | ||
57 | |||
58 | /* This magic should be in g_upper[0] for all upper parts | 33 | /* This magic should be in g_upper[0] for all upper parts |
59 | * to be valid. | 34 | * to be valid. |
60 | */ | 35 | */ |
@@ -65,12 +40,7 @@ typedef struct { | |||
65 | unsigned int asi; | 40 | unsigned int asi; |
66 | } siginfo_extra_v8plus_t; | 41 | } siginfo_extra_v8plus_t; |
67 | 42 | ||
68 | /* | 43 | struct signal_frame32 { |
69 | * And the new one, intended to be used for Linux applications only | ||
70 | * (we have enough in there to work with clone). | ||
71 | * All the interesting bits are in the info field. | ||
72 | */ | ||
73 | struct new_signal_frame32 { | ||
74 | struct sparc_stackf32 ss; | 44 | struct sparc_stackf32 ss; |
75 | __siginfo32_t info; | 45 | __siginfo32_t info; |
76 | /* __siginfo_fpu32_t * */ u32 fpu_save; | 46 | /* __siginfo_fpu32_t * */ u32 fpu_save; |
@@ -149,8 +119,7 @@ struct rt_signal_frame32 { | |||
149 | }; | 119 | }; |
150 | 120 | ||
151 | /* Align macros */ | 121 | /* Align macros */ |
152 | #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7))) | 122 | #define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 7) & (~7))) |
153 | #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) | ||
154 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) | 123 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) |
155 | 124 | ||
156 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | 125 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
@@ -241,17 +210,22 @@ static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu | |||
241 | return err; | 210 | return err; |
242 | } | 211 | } |
243 | 212 | ||
244 | void do_new_sigreturn32(struct pt_regs *regs) | 213 | void do_sigreturn32(struct pt_regs *regs) |
245 | { | 214 | { |
246 | struct new_signal_frame32 __user *sf; | 215 | struct signal_frame32 __user *sf; |
247 | unsigned int psr; | 216 | unsigned int psr; |
248 | unsigned pc, npc, fpu_save; | 217 | unsigned pc, npc, fpu_save; |
249 | sigset_t set; | 218 | sigset_t set; |
250 | unsigned seta[_COMPAT_NSIG_WORDS]; | 219 | unsigned seta[_COMPAT_NSIG_WORDS]; |
251 | int err, i; | 220 | int err, i; |
252 | 221 | ||
222 | /* Always make any pending restarted system calls return -EINTR */ | ||
223 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
224 | |||
225 | synchronize_user_stack(); | ||
226 | |||
253 | regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; | 227 | regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; |
254 | sf = (struct new_signal_frame32 __user *) regs->u_regs[UREG_FP]; | 228 | sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP]; |
255 | 229 | ||
256 | /* 1. Make sure we are not getting garbage from the user */ | 230 | /* 1. Make sure we are not getting garbage from the user */ |
257 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || | 231 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || |
@@ -319,76 +293,6 @@ segv: | |||
319 | force_sig(SIGSEGV, current); | 293 | force_sig(SIGSEGV, current); |
320 | } | 294 | } |
321 | 295 | ||
322 | asmlinkage void do_sigreturn32(struct pt_regs *regs) | ||
323 | { | ||
324 | struct sigcontext32 __user *scptr; | ||
325 | unsigned int pc, npc, psr; | ||
326 | sigset_t set; | ||
327 | unsigned int seta[_COMPAT_NSIG_WORDS]; | ||
328 | int err; | ||
329 | |||
330 | /* Always make any pending restarted system calls return -EINTR */ | ||
331 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
332 | |||
333 | synchronize_user_stack(); | ||
334 | if (test_thread_flag(TIF_NEWSIGNALS)) { | ||
335 | do_new_sigreturn32(regs); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | scptr = (struct sigcontext32 __user *) | ||
340 | (regs->u_regs[UREG_I0] & 0x00000000ffffffffUL); | ||
341 | /* Check sanity of the user arg. */ | ||
342 | if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || | ||
343 | (((unsigned long) scptr) & 3)) | ||
344 | goto segv; | ||
345 | |||
346 | err = __get_user(pc, &scptr->sigc_pc); | ||
347 | err |= __get_user(npc, &scptr->sigc_npc); | ||
348 | |||
349 | if ((pc | npc) & 3) | ||
350 | goto segv; /* Nice try. */ | ||
351 | |||
352 | err |= __get_user(seta[0], &scptr->sigc_mask); | ||
353 | /* Note that scptr + 1 points to extramask */ | ||
354 | err |= copy_from_user(seta+1, scptr + 1, | ||
355 | (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
356 | if (err) | ||
357 | goto segv; | ||
358 | switch (_NSIG_WORDS) { | ||
359 | case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); | ||
360 | case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); | ||
361 | case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); | ||
362 | case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); | ||
363 | } | ||
364 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
365 | spin_lock_irq(¤t->sighand->siglock); | ||
366 | current->blocked = set; | ||
367 | recalc_sigpending(); | ||
368 | spin_unlock_irq(¤t->sighand->siglock); | ||
369 | |||
370 | if (test_thread_flag(TIF_32BIT)) { | ||
371 | pc &= 0xffffffff; | ||
372 | npc &= 0xffffffff; | ||
373 | } | ||
374 | regs->tpc = pc; | ||
375 | regs->tnpc = npc; | ||
376 | err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); | ||
377 | err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); | ||
378 | err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); | ||
379 | |||
380 | /* User can only change condition codes in %tstate. */ | ||
381 | err |= __get_user(psr, &scptr->sigc_psr); | ||
382 | if (err) | ||
383 | goto segv; | ||
384 | regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); | ||
385 | regs->tstate |= psr_to_tstate_icc(psr); | ||
386 | return; | ||
387 | |||
388 | segv: | ||
389 | force_sig(SIGSEGV, current); | ||
390 | } | ||
391 | |||
392 | asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) | 296 | asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) |
393 | { | 297 | { |
394 | struct rt_signal_frame32 __user *sf; | 298 | struct rt_signal_frame32 __user *sf; |
@@ -504,145 +408,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns | |||
504 | return (void __user *)(sp - framesize); | 408 | return (void __user *)(sp - framesize); |
505 | } | 409 | } |
506 | 410 | ||
507 | static void | ||
508 | setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *oldset, siginfo_t *info) | ||
509 | { | ||
510 | struct signal_sframe32 __user *sframep; | ||
511 | struct sigcontext32 __user *sc; | ||
512 | unsigned int seta[_COMPAT_NSIG_WORDS]; | ||
513 | int err = 0; | ||
514 | void __user *sig_address; | ||
515 | int sig_code; | ||
516 | unsigned long pc = regs->tpc; | ||
517 | unsigned long npc = regs->tnpc; | ||
518 | unsigned int psr; | ||
519 | |||
520 | if (test_thread_flag(TIF_32BIT)) { | ||
521 | pc &= 0xffffffff; | ||
522 | npc &= 0xffffffff; | ||
523 | } | ||
524 | |||
525 | synchronize_user_stack(); | ||
526 | save_and_clear_fpu(); | ||
527 | |||
528 | sframep = (struct signal_sframe32 __user *) | ||
529 | get_sigframe(sa, regs, SF_ALIGNEDSZ); | ||
530 | if (invalid_frame_pointer(sframep, sizeof(*sframep))){ | ||
531 | /* Don't change signal code and address, so that | ||
532 | * post mortem debuggers can have a look. | ||
533 | */ | ||
534 | do_exit(SIGILL); | ||
535 | } | ||
536 | |||
537 | sc = &sframep->sig_context; | ||
538 | |||
539 | /* We've already made sure frame pointer isn't in kernel space... */ | ||
540 | err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), | ||
541 | &sc->sigc_onstack); | ||
542 | |||
543 | switch (_NSIG_WORDS) { | ||
544 | case 4: seta[7] = (oldset->sig[3] >> 32); | ||
545 | seta[6] = oldset->sig[3]; | ||
546 | case 3: seta[5] = (oldset->sig[2] >> 32); | ||
547 | seta[4] = oldset->sig[2]; | ||
548 | case 2: seta[3] = (oldset->sig[1] >> 32); | ||
549 | seta[2] = oldset->sig[1]; | ||
550 | case 1: seta[1] = (oldset->sig[0] >> 32); | ||
551 | seta[0] = oldset->sig[0]; | ||
552 | } | ||
553 | err |= __put_user(seta[0], &sc->sigc_mask); | ||
554 | err |= __copy_to_user(sframep->extramask, seta + 1, | ||
555 | (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
556 | err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); | ||
557 | err |= __put_user(pc, &sc->sigc_pc); | ||
558 | err |= __put_user(npc, &sc->sigc_npc); | ||
559 | psr = tstate_to_psr(regs->tstate); | ||
560 | if (current_thread_info()->fpsaved[0] & FPRS_FEF) | ||
561 | psr |= PSR_EF; | ||
562 | err |= __put_user(psr, &sc->sigc_psr); | ||
563 | err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); | ||
564 | err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); | ||
565 | err |= __put_user(get_thread_wsaved(), &sc->sigc_oswins); | ||
566 | |||
567 | err |= copy_in_user((u32 __user *)sframep, | ||
568 | (u32 __user *)(regs->u_regs[UREG_FP]), | ||
569 | sizeof(struct reg_window32)); | ||
570 | |||
571 | set_thread_wsaved(0); /* So process is allowed to execute. */ | ||
572 | err |= __put_user(signr, &sframep->sig_num); | ||
573 | sig_address = NULL; | ||
574 | sig_code = 0; | ||
575 | if (SI_FROMKERNEL (info) && (info->si_code & __SI_MASK) == __SI_FAULT) { | ||
576 | sig_address = info->si_addr; | ||
577 | switch (signr) { | ||
578 | case SIGSEGV: | ||
579 | switch (info->si_code) { | ||
580 | case SEGV_MAPERR: sig_code = SUBSIG_NOMAPPING; break; | ||
581 | default: sig_code = SUBSIG_PROTECTION; break; | ||
582 | } | ||
583 | break; | ||
584 | case SIGILL: | ||
585 | switch (info->si_code) { | ||
586 | case ILL_ILLOPC: sig_code = SUBSIG_ILLINST; break; | ||
587 | case ILL_PRVOPC: sig_code = SUBSIG_PRIVINST; break; | ||
588 | case ILL_ILLTRP: sig_code = SUBSIG_BADTRAP(info->si_trapno); break; | ||
589 | default: sig_code = SUBSIG_STACK; break; | ||
590 | } | ||
591 | break; | ||
592 | case SIGFPE: | ||
593 | switch (info->si_code) { | ||
594 | case FPE_INTDIV: sig_code = SUBSIG_IDIVZERO; break; | ||
595 | case FPE_INTOVF: sig_code = SUBSIG_FPINTOVFL; break; | ||
596 | case FPE_FLTDIV: sig_code = SUBSIG_FPDIVZERO; break; | ||
597 | case FPE_FLTOVF: sig_code = SUBSIG_FPOVFLOW; break; | ||
598 | case FPE_FLTUND: sig_code = SUBSIG_FPUNFLOW; break; | ||
599 | case FPE_FLTRES: sig_code = SUBSIG_FPINEXACT; break; | ||
600 | case FPE_FLTINV: sig_code = SUBSIG_FPOPERROR; break; | ||
601 | default: sig_code = SUBSIG_FPERROR; break; | ||
602 | } | ||
603 | break; | ||
604 | case SIGBUS: | ||
605 | switch (info->si_code) { | ||
606 | case BUS_ADRALN: sig_code = SUBSIG_ALIGNMENT; break; | ||
607 | case BUS_ADRERR: sig_code = SUBSIG_MISCERROR; break; | ||
608 | default: sig_code = SUBSIG_BUSTIMEOUT; break; | ||
609 | } | ||
610 | break; | ||
611 | case SIGEMT: | ||
612 | switch (info->si_code) { | ||
613 | case EMT_TAGOVF: sig_code = SUBSIG_TAG; break; | ||
614 | } | ||
615 | break; | ||
616 | case SIGSYS: | ||
617 | if (info->si_code == (__SI_FAULT|0x100)) { | ||
618 | /* See sys_sunos32.c */ | ||
619 | sig_code = info->si_trapno; | ||
620 | break; | ||
621 | } | ||
622 | default: | ||
623 | sig_address = NULL; | ||
624 | } | ||
625 | } | ||
626 | err |= __put_user(ptr_to_compat(sig_address), &sframep->sig_address); | ||
627 | err |= __put_user(sig_code, &sframep->sig_code); | ||
628 | err |= __put_user(ptr_to_compat(sc), &sframep->sig_scptr); | ||
629 | if (err) | ||
630 | goto sigsegv; | ||
631 | |||
632 | regs->u_regs[UREG_FP] = (unsigned long) sframep; | ||
633 | regs->tpc = (unsigned long) sa->sa_handler; | ||
634 | regs->tnpc = (regs->tpc + 4); | ||
635 | if (test_thread_flag(TIF_32BIT)) { | ||
636 | regs->tpc &= 0xffffffff; | ||
637 | regs->tnpc &= 0xffffffff; | ||
638 | } | ||
639 | return; | ||
640 | |||
641 | sigsegv: | ||
642 | force_sigsegv(signr, current); | ||
643 | } | ||
644 | |||
645 | |||
646 | static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | 411 | static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) |
647 | { | 412 | { |
648 | unsigned long *fpregs = current_thread_info()->fpregs; | 413 | unsigned long *fpregs = current_thread_info()->fpregs; |
@@ -663,10 +428,10 @@ static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | |||
663 | return err; | 428 | return err; |
664 | } | 429 | } |
665 | 430 | ||
666 | static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, | 431 | static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, |
667 | int signo, sigset_t *oldset) | 432 | int signo, sigset_t *oldset) |
668 | { | 433 | { |
669 | struct new_signal_frame32 __user *sf; | 434 | struct signal_frame32 __user *sf; |
670 | int sigframe_size; | 435 | int sigframe_size; |
671 | u32 psr; | 436 | u32 psr; |
672 | int i, err; | 437 | int i, err; |
@@ -676,11 +441,11 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, | |||
676 | synchronize_user_stack(); | 441 | synchronize_user_stack(); |
677 | save_and_clear_fpu(); | 442 | save_and_clear_fpu(); |
678 | 443 | ||
679 | sigframe_size = NF_ALIGNEDSZ; | 444 | sigframe_size = SF_ALIGNEDSZ; |
680 | if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) | 445 | if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) |
681 | sigframe_size -= sizeof(__siginfo_fpu_t); | 446 | sigframe_size -= sizeof(__siginfo_fpu_t); |
682 | 447 | ||
683 | sf = (struct new_signal_frame32 __user *) | 448 | sf = (struct signal_frame32 __user *) |
684 | get_sigframe(&ka->sa, regs, sigframe_size); | 449 | get_sigframe(&ka->sa, regs, sigframe_size); |
685 | 450 | ||
686 | if (invalid_frame_pointer(sf, sigframe_size)) | 451 | if (invalid_frame_pointer(sf, sigframe_size)) |
@@ -944,10 +709,9 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, | |||
944 | { | 709 | { |
945 | if (ka->sa.sa_flags & SA_SIGINFO) | 710 | if (ka->sa.sa_flags & SA_SIGINFO) |
946 | setup_rt_frame32(ka, regs, signr, oldset, info); | 711 | setup_rt_frame32(ka, regs, signr, oldset, info); |
947 | else if (test_thread_flag(TIF_NEWSIGNALS)) | ||
948 | new_setup_frame32(ka, regs, signr, oldset); | ||
949 | else | 712 | else |
950 | setup_frame32(&ka->sa, regs, signr, oldset, info); | 713 | setup_frame32(ka, regs, signr, oldset); |
714 | |||
951 | spin_lock_irq(¤t->sighand->siglock); | 715 | spin_lock_irq(¤t->sighand->siglock); |
952 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 716 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
953 | if (!(ka->sa.sa_flags & SA_NOMASK)) | 717 | if (!(ka->sa.sa_flags & SA_NOMASK)) |
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 66336590e830..8ac0b99f2c55 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #endif | 49 | #endif |
50 | #ifdef CONFIG_PCI | 50 | #ifdef CONFIG_PCI |
51 | #include <asm/ebus.h> | 51 | #include <asm/ebus.h> |
52 | #include <asm/isa.h> | ||
53 | #endif | 52 | #endif |
54 | #include <asm/ns87303.h> | 53 | #include <asm/ns87303.h> |
55 | #include <asm/timer.h> | 54 | #include <asm/timer.h> |
@@ -187,7 +186,6 @@ EXPORT_SYMBOL(insw); | |||
187 | EXPORT_SYMBOL(insl); | 186 | EXPORT_SYMBOL(insl); |
188 | #ifdef CONFIG_PCI | 187 | #ifdef CONFIG_PCI |
189 | EXPORT_SYMBOL(ebus_chain); | 188 | EXPORT_SYMBOL(ebus_chain); |
190 | EXPORT_SYMBOL(isa_chain); | ||
191 | EXPORT_SYMBOL(pci_alloc_consistent); | 189 | EXPORT_SYMBOL(pci_alloc_consistent); |
192 | EXPORT_SYMBOL(pci_free_consistent); | 190 | EXPORT_SYMBOL(pci_free_consistent); |
193 | EXPORT_SYMBOL(pci_map_single); | 191 | EXPORT_SYMBOL(pci_map_single); |
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index c1a61e98899a..161ce4710fe7 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c | |||
@@ -554,10 +554,8 @@ asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act | |||
554 | struct k_sigaction new_ka, old_ka; | 554 | struct k_sigaction new_ka, old_ka; |
555 | int ret; | 555 | int ret; |
556 | 556 | ||
557 | if (sig < 0) { | 557 | WARN_ON_ONCE(sig >= 0); |
558 | set_thread_flag(TIF_NEWSIGNALS); | 558 | sig = -sig; |
559 | sig = -sig; | ||
560 | } | ||
561 | 559 | ||
562 | if (act) { | 560 | if (act) { |
563 | compat_old_sigset_t mask; | 561 | compat_old_sigset_t mask; |
@@ -601,11 +599,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig, | |||
601 | if (sigsetsize != sizeof(compat_sigset_t)) | 599 | if (sigsetsize != sizeof(compat_sigset_t)) |
602 | return -EINVAL; | 600 | return -EINVAL; |
603 | 601 | ||
604 | /* All tasks which use RT signals (effectively) use | ||
605 | * new style signals. | ||
606 | */ | ||
607 | set_thread_flag(TIF_NEWSIGNALS); | ||
608 | |||
609 | if (act) { | 602 | if (act) { |
610 | u32 u_handler, u_restorer; | 603 | u32 u_handler, u_restorer; |
611 | 604 | ||
diff --git a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c index ac556db06973..7120ebbd4d03 100644 --- a/arch/sparc64/lib/iomap.c +++ b/arch/sparc64/lib/iomap.c | |||
@@ -21,8 +21,8 @@ EXPORT_SYMBOL(ioport_unmap); | |||
21 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ | 21 | /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ |
22 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | 22 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) |
23 | { | 23 | { |
24 | unsigned long start = pci_resource_start(dev, bar); | 24 | resource_size_t start = pci_resource_start(dev, bar); |
25 | unsigned long len = pci_resource_len(dev, bar); | 25 | resource_size_t len = pci_resource_len(dev, bar); |
26 | unsigned long flags = pci_resource_flags(dev, bar); | 26 | unsigned long flags = pci_resource_flags(dev, bar); |
27 | 27 | ||
28 | if (!len || !start) | 28 | if (!len || !start) |
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 177d8aaeec42..8c2b50e8abc6 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -1699,9 +1699,21 @@ void __init paging_init(void) | |||
1699 | * functions like clear_dcache_dirty_cpu use the cpu mask | 1699 | * functions like clear_dcache_dirty_cpu use the cpu mask |
1700 | * in 13-bit signed-immediate instruction fields. | 1700 | * in 13-bit signed-immediate instruction fields. |
1701 | */ | 1701 | */ |
1702 | BUILD_BUG_ON(FLAGS_RESERVED != 32); | 1702 | |
1703 | /* | ||
1704 | * Page flags must not reach into upper 32 bits that are used | ||
1705 | * for the cpu number | ||
1706 | */ | ||
1707 | BUILD_BUG_ON(NR_PAGEFLAGS > 32); | ||
1708 | |||
1709 | /* | ||
1710 | * The bit fields placed in the high range must not reach below | ||
1711 | * the 32 bit boundary. Otherwise we cannot place the cpu field | ||
1712 | * at the 32 bit boundary. | ||
1713 | */ | ||
1703 | BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH + | 1714 | BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH + |
1704 | ilog2(roundup_pow_of_two(NR_CPUS)) > FLAGS_RESERVED); | 1715 | ilog2(roundup_pow_of_two(NR_CPUS)) > 32); |
1716 | |||
1705 | BUILD_BUG_ON(NR_CPUS > 4096); | 1717 | BUILD_BUG_ON(NR_CPUS > 4096); |
1706 | 1718 | ||
1707 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; | 1719 | kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; |
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index db3082b4da46..6e51424745ab 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -125,7 +125,7 @@ static int open_one_chan(struct chan *chan) | |||
125 | return 0; | 125 | return 0; |
126 | } | 126 | } |
127 | 127 | ||
128 | int open_chan(struct list_head *chans) | 128 | static int open_chan(struct list_head *chans) |
129 | { | 129 | { |
130 | struct list_head *ele; | 130 | struct list_head *ele; |
131 | struct chan *chan; | 131 | struct chan *chan; |
@@ -583,19 +583,6 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
583 | return 0; | 583 | return 0; |
584 | } | 584 | } |
585 | 585 | ||
586 | int chan_out_fd(struct list_head *chans) | ||
587 | { | ||
588 | struct list_head *ele; | ||
589 | struct chan *chan; | ||
590 | |||
591 | list_for_each(ele, chans) { | ||
592 | chan = list_entry(ele, struct chan, list); | ||
593 | if (chan->primary && chan->output) | ||
594 | return chan->fd; | ||
595 | } | ||
596 | return -1; | ||
597 | } | ||
598 | |||
599 | void chan_interrupt(struct list_head *chans, struct delayed_work *task, | 586 | void chan_interrupt(struct list_head *chans, struct delayed_work *task, |
600 | struct tty_struct *tty, int irq) | 587 | struct tty_struct *tty, int irq) |
601 | { | 588 | { |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 2c898c4d6b6a..10b86e1cc659 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -304,7 +304,7 @@ int line_ioctl(struct tty_struct *tty, struct file * file, | |||
304 | break; | 304 | break; |
305 | if (i == ARRAY_SIZE(tty_ioctls)) { | 305 | if (i == ARRAY_SIZE(tty_ioctls)) { |
306 | printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n", | 306 | printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n", |
307 | __FUNCTION__, tty->name, cmd); | 307 | __func__, tty->name, cmd); |
308 | } | 308 | } |
309 | ret = -ENOIOCTLCMD; | 309 | ret = -ENOIOCTLCMD; |
310 | break; | 310 | break; |
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 822092f149be..8c4378a76d63 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c | |||
@@ -58,7 +58,7 @@ static const struct net_kern_info mcast_kern_info = { | |||
58 | .write = mcast_write, | 58 | .write = mcast_write, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | int mcast_setup(char *str, char **mac_out, void *data) | 61 | static int mcast_setup(char *str, char **mac_out, void *data) |
62 | { | 62 | { |
63 | struct mcast_init *init = data; | 63 | struct mcast_init *init = data; |
64 | char *port_str = NULL, *ttl_str = NULL, *remain; | 64 | char *port_str = NULL, *ttl_str = NULL, *remain; |
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 13af2f03ed84..f8cf4c8bedef 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c | |||
@@ -39,7 +39,7 @@ static struct mconsole_command commands[] = { | |||
39 | /* Initialized in mconsole_init, which is an initcall */ | 39 | /* Initialized in mconsole_init, which is an initcall */ |
40 | char mconsole_socket_name[256]; | 40 | char mconsole_socket_name[256]; |
41 | 41 | ||
42 | int mconsole_reply_v0(struct mc_request *req, char *reply) | 42 | static int mconsole_reply_v0(struct mc_request *req, char *reply) |
43 | { | 43 | { |
44 | struct iovec iov; | 44 | struct iovec iov; |
45 | struct msghdr msg; | 45 | struct msghdr msg; |
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 1d43bdfc20c4..5b4ca8d93682 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -116,7 +116,7 @@ static void uml_dev_close(struct work_struct *work) | |||
116 | dev_close(lp->dev); | 116 | dev_close(lp->dev); |
117 | } | 117 | } |
118 | 118 | ||
119 | irqreturn_t uml_net_interrupt(int irq, void *dev_id) | 119 | static irqreturn_t uml_net_interrupt(int irq, void *dev_id) |
120 | { | 120 | { |
121 | struct net_device *dev = dev_id; | 121 | struct net_device *dev = dev_id; |
122 | struct uml_net_private *lp = dev->priv; | 122 | struct uml_net_private *lp = dev->priv; |
@@ -296,7 +296,7 @@ static struct ethtool_ops uml_net_ethtool_ops = { | |||
296 | .get_link = ethtool_op_get_link, | 296 | .get_link = ethtool_op_get_link, |
297 | }; | 297 | }; |
298 | 298 | ||
299 | void uml_net_user_timer_expire(unsigned long _conn) | 299 | static void uml_net_user_timer_expire(unsigned long _conn) |
300 | { | 300 | { |
301 | #ifdef undef | 301 | #ifdef undef |
302 | struct connection *conn = (struct connection *)_conn; | 302 | struct connection *conn = (struct connection *)_conn; |
@@ -786,7 +786,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
786 | } | 786 | } |
787 | 787 | ||
788 | /* uml_net_init shouldn't be called twice on two CPUs at the same time */ | 788 | /* uml_net_init shouldn't be called twice on two CPUs at the same time */ |
789 | struct notifier_block uml_inetaddr_notifier = { | 789 | static struct notifier_block uml_inetaddr_notifier = { |
790 | .notifier_call = uml_inetaddr_event, | 790 | .notifier_call = uml_inetaddr_event, |
791 | }; | 791 | }; |
792 | 792 | ||
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index addd75902656..d269ca387f10 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c | |||
@@ -153,7 +153,7 @@ struct port_pre_exec_data { | |||
153 | int pipe_fd; | 153 | int pipe_fd; |
154 | }; | 154 | }; |
155 | 155 | ||
156 | void port_pre_exec(void *arg) | 156 | static void port_pre_exec(void *arg) |
157 | { | 157 | { |
158 | struct port_pre_exec_data *data = arg; | 158 | struct port_pre_exec_data *data = arg; |
159 | 159 | ||
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 6b4a0f9e38de..d19faec7046e 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c | |||
@@ -13,7 +13,7 @@ struct slip_init { | |||
13 | char *gate_addr; | 13 | char *gate_addr; |
14 | }; | 14 | }; |
15 | 15 | ||
16 | void slip_init(struct net_device *dev, void *data) | 16 | static void slip_init(struct net_device *dev, void *data) |
17 | { | 17 | { |
18 | struct uml_net_private *private; | 18 | struct uml_net_private *private; |
19 | struct slip_data *spri; | 19 | struct slip_data *spri; |
@@ -57,7 +57,7 @@ static int slip_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) | |||
57 | (struct slip_data *) &lp->user); | 57 | (struct slip_data *) &lp->user); |
58 | } | 58 | } |
59 | 59 | ||
60 | const struct net_kern_info slip_kern_info = { | 60 | static const struct net_kern_info slip_kern_info = { |
61 | .init = slip_init, | 61 | .init = slip_init, |
62 | .protocol = slip_protocol, | 62 | .protocol = slip_protocol, |
63 | .read = slip_read, | 63 | .read = slip_read, |
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index cec0c33cdd39..49266f6108c4 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | static struct tty_driver *console_driver; | 35 | static struct tty_driver *console_driver; |
36 | 36 | ||
37 | void stdio_announce(char *dev_name, int dev) | 37 | static void stdio_announce(char *dev_name, int dev) |
38 | { | 38 | { |
39 | printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, | 39 | printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, |
40 | dev_name); | 40 | dev_name); |
@@ -158,7 +158,7 @@ static struct console stdiocons = { | |||
158 | .index = -1, | 158 | .index = -1, |
159 | }; | 159 | }; |
160 | 160 | ||
161 | int stdio_init(void) | 161 | static int stdio_init(void) |
162 | { | 162 | { |
163 | char *new_title; | 163 | char *new_title; |
164 | 164 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index be3a2797dac4..5e45e39a8a8d 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -72,18 +72,6 @@ struct io_thread_req { | |||
72 | int error; | 72 | int error; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | extern int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
76 | char **backing_file_out, int *bitmap_offset_out, | ||
77 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
78 | int *create_cow_out); | ||
79 | extern int create_cow_file(char *cow_file, char *backing_file, | ||
80 | struct openflags flags, int sectorsize, | ||
81 | int alignment, int *bitmap_offset_out, | ||
82 | unsigned long *bitmap_len_out, | ||
83 | int *data_offset_out); | ||
84 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | ||
85 | extern void do_io(struct io_thread_req *req); | ||
86 | |||
87 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) | 75 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) |
88 | { | 76 | { |
89 | __u64 n; | 77 | __u64 n; |
@@ -200,7 +188,7 @@ struct ubd { | |||
200 | } | 188 | } |
201 | 189 | ||
202 | /* Protected by ubd_lock */ | 190 | /* Protected by ubd_lock */ |
203 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | 191 | static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD }; |
204 | 192 | ||
205 | /* Only changed by fake_ide_setup which is a setup */ | 193 | /* Only changed by fake_ide_setup which is a setup */ |
206 | static int fake_ide = 0; | 194 | static int fake_ide = 0; |
@@ -463,7 +451,7 @@ __uml_help(udb_setup, | |||
463 | static void do_ubd_request(struct request_queue * q); | 451 | static void do_ubd_request(struct request_queue * q); |
464 | 452 | ||
465 | /* Only changed by ubd_init, which is an initcall. */ | 453 | /* Only changed by ubd_init, which is an initcall. */ |
466 | int thread_fd = -1; | 454 | static int thread_fd = -1; |
467 | 455 | ||
468 | static void ubd_end_request(struct request *req, int bytes, int error) | 456 | static void ubd_end_request(struct request *req, int bytes, int error) |
469 | { | 457 | { |
@@ -531,7 +519,7 @@ static irqreturn_t ubd_intr(int irq, void *dev) | |||
531 | /* Only changed by ubd_init, which is an initcall. */ | 519 | /* Only changed by ubd_init, which is an initcall. */ |
532 | static int io_pid = -1; | 520 | static int io_pid = -1; |
533 | 521 | ||
534 | void kill_io_thread(void) | 522 | static void kill_io_thread(void) |
535 | { | 523 | { |
536 | if(io_pid != -1) | 524 | if(io_pid != -1) |
537 | os_kill_process(io_pid, 1); | 525 | os_kill_process(io_pid, 1); |
@@ -547,6 +535,192 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) | |||
547 | return os_file_size(file, size_out); | 535 | return os_file_size(file, size_out); |
548 | } | 536 | } |
549 | 537 | ||
538 | static int read_cow_bitmap(int fd, void *buf, int offset, int len) | ||
539 | { | ||
540 | int err; | ||
541 | |||
542 | err = os_seek_file(fd, offset); | ||
543 | if (err < 0) | ||
544 | return err; | ||
545 | |||
546 | err = os_read_file(fd, buf, len); | ||
547 | if (err < 0) | ||
548 | return err; | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) | ||
554 | { | ||
555 | unsigned long modtime; | ||
556 | unsigned long long actual; | ||
557 | int err; | ||
558 | |||
559 | err = os_file_modtime(file, &modtime); | ||
560 | if (err < 0) { | ||
561 | printk(KERN_ERR "Failed to get modification time of backing " | ||
562 | "file \"%s\", err = %d\n", file, -err); | ||
563 | return err; | ||
564 | } | ||
565 | |||
566 | err = os_file_size(file, &actual); | ||
567 | if (err < 0) { | ||
568 | printk(KERN_ERR "Failed to get size of backing file \"%s\", " | ||
569 | "err = %d\n", file, -err); | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | if (actual != size) { | ||
574 | /*__u64 can be a long on AMD64 and with %lu GCC complains; so | ||
575 | * the typecast.*/ | ||
576 | printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header " | ||
577 | "vs backing file\n", (unsigned long long) size, actual); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | if (modtime != mtime) { | ||
581 | printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs " | ||
582 | "backing file\n", mtime, modtime); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) | ||
589 | { | ||
590 | struct uml_stat buf1, buf2; | ||
591 | int err; | ||
592 | |||
593 | if (from_cmdline == NULL) | ||
594 | return 0; | ||
595 | if (!strcmp(from_cmdline, from_cow)) | ||
596 | return 0; | ||
597 | |||
598 | err = os_stat_file(from_cmdline, &buf1); | ||
599 | if (err < 0) { | ||
600 | printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline, | ||
601 | -err); | ||
602 | return 0; | ||
603 | } | ||
604 | err = os_stat_file(from_cow, &buf2); | ||
605 | if (err < 0) { | ||
606 | printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow, | ||
607 | -err); | ||
608 | return 1; | ||
609 | } | ||
610 | if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) | ||
611 | return 0; | ||
612 | |||
613 | printk(KERN_ERR "Backing file mismatch - \"%s\" requested, " | ||
614 | "\"%s\" specified in COW header of \"%s\"\n", | ||
615 | from_cmdline, from_cow, cow); | ||
616 | return 1; | ||
617 | } | ||
618 | |||
619 | static int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
620 | char **backing_file_out, int *bitmap_offset_out, | ||
621 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
622 | int *create_cow_out) | ||
623 | { | ||
624 | time_t mtime; | ||
625 | unsigned long long size; | ||
626 | __u32 version, align; | ||
627 | char *backing_file; | ||
628 | int fd, err, sectorsize, asked_switch, mode = 0644; | ||
629 | |||
630 | fd = os_open_file(file, *openflags, mode); | ||
631 | if (fd < 0) { | ||
632 | if ((fd == -ENOENT) && (create_cow_out != NULL)) | ||
633 | *create_cow_out = 1; | ||
634 | if (!openflags->w || | ||
635 | ((fd != -EROFS) && (fd != -EACCES))) | ||
636 | return fd; | ||
637 | openflags->w = 0; | ||
638 | fd = os_open_file(file, *openflags, mode); | ||
639 | if (fd < 0) | ||
640 | return fd; | ||
641 | } | ||
642 | |||
643 | if (shared) | ||
644 | printk(KERN_INFO "Not locking \"%s\" on the host\n", file); | ||
645 | else { | ||
646 | err = os_lock_file(fd, openflags->w); | ||
647 | if (err < 0) { | ||
648 | printk(KERN_ERR "Failed to lock '%s', err = %d\n", | ||
649 | file, -err); | ||
650 | goto out_close; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* Successful return case! */ | ||
655 | if (backing_file_out == NULL) | ||
656 | return fd; | ||
657 | |||
658 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, | ||
659 | &size, §orsize, &align, bitmap_offset_out); | ||
660 | if (err && (*backing_file_out != NULL)) { | ||
661 | printk(KERN_ERR "Failed to read COW header from COW file " | ||
662 | "\"%s\", errno = %d\n", file, -err); | ||
663 | goto out_close; | ||
664 | } | ||
665 | if (err) | ||
666 | return fd; | ||
667 | |||
668 | asked_switch = path_requires_switch(*backing_file_out, backing_file, | ||
669 | file); | ||
670 | |||
671 | /* Allow switching only if no mismatch. */ | ||
672 | if (asked_switch && !backing_file_mismatch(*backing_file_out, size, | ||
673 | mtime)) { | ||
674 | printk(KERN_ERR "Switching backing file to '%s'\n", | ||
675 | *backing_file_out); | ||
676 | err = write_cow_header(file, fd, *backing_file_out, | ||
677 | sectorsize, align, &size); | ||
678 | if (err) { | ||
679 | printk(KERN_ERR "Switch failed, errno = %d\n", -err); | ||
680 | goto out_close; | ||
681 | } | ||
682 | } else { | ||
683 | *backing_file_out = backing_file; | ||
684 | err = backing_file_mismatch(*backing_file_out, size, mtime); | ||
685 | if (err) | ||
686 | goto out_close; | ||
687 | } | ||
688 | |||
689 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, | ||
690 | bitmap_len_out, data_offset_out); | ||
691 | |||
692 | return fd; | ||
693 | out_close: | ||
694 | os_close_file(fd); | ||
695 | return err; | ||
696 | } | ||
697 | |||
698 | static int create_cow_file(char *cow_file, char *backing_file, | ||
699 | struct openflags flags, | ||
700 | int sectorsize, int alignment, int *bitmap_offset_out, | ||
701 | unsigned long *bitmap_len_out, int *data_offset_out) | ||
702 | { | ||
703 | int err, fd; | ||
704 | |||
705 | flags.c = 1; | ||
706 | fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); | ||
707 | if (fd < 0) { | ||
708 | err = fd; | ||
709 | printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n", | ||
710 | cow_file, -err); | ||
711 | goto out; | ||
712 | } | ||
713 | |||
714 | err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, | ||
715 | bitmap_offset_out, bitmap_len_out, | ||
716 | data_offset_out); | ||
717 | if (!err) | ||
718 | return fd; | ||
719 | os_close_file(fd); | ||
720 | out: | ||
721 | return err; | ||
722 | } | ||
723 | |||
550 | static void ubd_close_dev(struct ubd *ubd_dev) | 724 | static void ubd_close_dev(struct ubd *ubd_dev) |
551 | { | 725 | { |
552 | os_close_file(ubd_dev->fd); | 726 | os_close_file(ubd_dev->fd); |
@@ -1166,185 +1340,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
1166 | return -EINVAL; | 1340 | return -EINVAL; |
1167 | } | 1341 | } |
1168 | 1342 | ||
1169 | static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) | ||
1170 | { | ||
1171 | struct uml_stat buf1, buf2; | ||
1172 | int err; | ||
1173 | |||
1174 | if(from_cmdline == NULL) | ||
1175 | return 0; | ||
1176 | if(!strcmp(from_cmdline, from_cow)) | ||
1177 | return 0; | ||
1178 | |||
1179 | err = os_stat_file(from_cmdline, &buf1); | ||
1180 | if(err < 0){ | ||
1181 | printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); | ||
1182 | return 0; | ||
1183 | } | ||
1184 | err = os_stat_file(from_cow, &buf2); | ||
1185 | if(err < 0){ | ||
1186 | printk("Couldn't stat '%s', err = %d\n", from_cow, -err); | ||
1187 | return 1; | ||
1188 | } | ||
1189 | if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) | ||
1190 | return 0; | ||
1191 | |||
1192 | printk("Backing file mismatch - \"%s\" requested,\n" | ||
1193 | "\"%s\" specified in COW header of \"%s\"\n", | ||
1194 | from_cmdline, from_cow, cow); | ||
1195 | return 1; | ||
1196 | } | ||
1197 | |||
1198 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) | ||
1199 | { | ||
1200 | unsigned long modtime; | ||
1201 | unsigned long long actual; | ||
1202 | int err; | ||
1203 | |||
1204 | err = os_file_modtime(file, &modtime); | ||
1205 | if(err < 0){ | ||
1206 | printk("Failed to get modification time of backing file " | ||
1207 | "\"%s\", err = %d\n", file, -err); | ||
1208 | return err; | ||
1209 | } | ||
1210 | |||
1211 | err = os_file_size(file, &actual); | ||
1212 | if(err < 0){ | ||
1213 | printk("Failed to get size of backing file \"%s\", " | ||
1214 | "err = %d\n", file, -err); | ||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | if(actual != size){ | ||
1219 | /*__u64 can be a long on AMD64 and with %lu GCC complains; so | ||
1220 | * the typecast.*/ | ||
1221 | printk("Size mismatch (%llu vs %llu) of COW header vs backing " | ||
1222 | "file\n", (unsigned long long) size, actual); | ||
1223 | return -EINVAL; | ||
1224 | } | ||
1225 | if(modtime != mtime){ | ||
1226 | printk("mtime mismatch (%ld vs %ld) of COW header vs backing " | ||
1227 | "file\n", mtime, modtime); | ||
1228 | return -EINVAL; | ||
1229 | } | ||
1230 | return 0; | ||
1231 | } | ||
1232 | |||
1233 | int read_cow_bitmap(int fd, void *buf, int offset, int len) | ||
1234 | { | ||
1235 | int err; | ||
1236 | |||
1237 | err = os_seek_file(fd, offset); | ||
1238 | if(err < 0) | ||
1239 | return err; | ||
1240 | |||
1241 | err = os_read_file(fd, buf, len); | ||
1242 | if(err < 0) | ||
1243 | return err; | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
1249 | char **backing_file_out, int *bitmap_offset_out, | ||
1250 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
1251 | int *create_cow_out) | ||
1252 | { | ||
1253 | time_t mtime; | ||
1254 | unsigned long long size; | ||
1255 | __u32 version, align; | ||
1256 | char *backing_file; | ||
1257 | int fd, err, sectorsize, asked_switch, mode = 0644; | ||
1258 | |||
1259 | fd = os_open_file(file, *openflags, mode); | ||
1260 | if (fd < 0) { | ||
1261 | if ((fd == -ENOENT) && (create_cow_out != NULL)) | ||
1262 | *create_cow_out = 1; | ||
1263 | if (!openflags->w || | ||
1264 | ((fd != -EROFS) && (fd != -EACCES))) | ||
1265 | return fd; | ||
1266 | openflags->w = 0; | ||
1267 | fd = os_open_file(file, *openflags, mode); | ||
1268 | if (fd < 0) | ||
1269 | return fd; | ||
1270 | } | ||
1271 | |||
1272 | if(shared) | ||
1273 | printk("Not locking \"%s\" on the host\n", file); | ||
1274 | else { | ||
1275 | err = os_lock_file(fd, openflags->w); | ||
1276 | if(err < 0){ | ||
1277 | printk("Failed to lock '%s', err = %d\n", file, -err); | ||
1278 | goto out_close; | ||
1279 | } | ||
1280 | } | ||
1281 | |||
1282 | /* Successful return case! */ | ||
1283 | if(backing_file_out == NULL) | ||
1284 | return fd; | ||
1285 | |||
1286 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, | ||
1287 | &size, §orsize, &align, bitmap_offset_out); | ||
1288 | if(err && (*backing_file_out != NULL)){ | ||
1289 | printk("Failed to read COW header from COW file \"%s\", " | ||
1290 | "errno = %d\n", file, -err); | ||
1291 | goto out_close; | ||
1292 | } | ||
1293 | if(err) | ||
1294 | return fd; | ||
1295 | |||
1296 | asked_switch = path_requires_switch(*backing_file_out, backing_file, file); | ||
1297 | |||
1298 | /* Allow switching only if no mismatch. */ | ||
1299 | if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) { | ||
1300 | printk("Switching backing file to '%s'\n", *backing_file_out); | ||
1301 | err = write_cow_header(file, fd, *backing_file_out, | ||
1302 | sectorsize, align, &size); | ||
1303 | if (err) { | ||
1304 | printk("Switch failed, errno = %d\n", -err); | ||
1305 | goto out_close; | ||
1306 | } | ||
1307 | } else { | ||
1308 | *backing_file_out = backing_file; | ||
1309 | err = backing_file_mismatch(*backing_file_out, size, mtime); | ||
1310 | if (err) | ||
1311 | goto out_close; | ||
1312 | } | ||
1313 | |||
1314 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, | ||
1315 | bitmap_len_out, data_offset_out); | ||
1316 | |||
1317 | return fd; | ||
1318 | out_close: | ||
1319 | os_close_file(fd); | ||
1320 | return err; | ||
1321 | } | ||
1322 | |||
1323 | int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | ||
1324 | int sectorsize, int alignment, int *bitmap_offset_out, | ||
1325 | unsigned long *bitmap_len_out, int *data_offset_out) | ||
1326 | { | ||
1327 | int err, fd; | ||
1328 | |||
1329 | flags.c = 1; | ||
1330 | fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); | ||
1331 | if(fd < 0){ | ||
1332 | err = fd; | ||
1333 | printk("Open of COW file '%s' failed, errno = %d\n", cow_file, | ||
1334 | -err); | ||
1335 | goto out; | ||
1336 | } | ||
1337 | |||
1338 | err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, | ||
1339 | bitmap_offset_out, bitmap_len_out, | ||
1340 | data_offset_out); | ||
1341 | if(!err) | ||
1342 | return fd; | ||
1343 | os_close_file(fd); | ||
1344 | out: | ||
1345 | return err; | ||
1346 | } | ||
1347 | |||
1348 | static int update_bitmap(struct io_thread_req *req) | 1343 | static int update_bitmap(struct io_thread_req *req) |
1349 | { | 1344 | { |
1350 | int n; | 1345 | int n; |
@@ -1369,7 +1364,7 @@ static int update_bitmap(struct io_thread_req *req) | |||
1369 | return 0; | 1364 | return 0; |
1370 | } | 1365 | } |
1371 | 1366 | ||
1372 | void do_io(struct io_thread_req *req) | 1367 | static void do_io(struct io_thread_req *req) |
1373 | { | 1368 | { |
1374 | char *buf; | 1369 | char *buf; |
1375 | unsigned long len; | 1370 | unsigned long len; |
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 624b5100a3cd..1e651457e049 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h | |||
@@ -31,7 +31,6 @@ extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, | |||
31 | struct tty_struct *tty, int irq); | 31 | struct tty_struct *tty, int irq); |
32 | extern int parse_chan_pair(char *str, struct line *line, int device, | 32 | extern int parse_chan_pair(char *str, struct line *line, int device, |
33 | const struct chan_opts *opts, char **error_out); | 33 | const struct chan_opts *opts, char **error_out); |
34 | extern int open_chan(struct list_head *chans); | ||
35 | extern int write_chan(struct list_head *chans, const char *buf, int len, | 34 | extern int write_chan(struct list_head *chans, const char *buf, int len, |
36 | int write_irq); | 35 | int write_irq); |
37 | extern int console_write_chan(struct list_head *chans, const char *buf, | 36 | extern int console_write_chan(struct list_head *chans, const char *buf, |
@@ -45,7 +44,6 @@ extern void close_chan(struct list_head *chans, int delay_free_irq); | |||
45 | extern int chan_window_size(struct list_head *chans, | 44 | extern int chan_window_size(struct list_head *chans, |
46 | unsigned short *rows_out, | 45 | unsigned short *rows_out, |
47 | unsigned short *cols_out); | 46 | unsigned short *cols_out); |
48 | extern int chan_out_fd(struct list_head *chans); | ||
49 | extern int chan_config_string(struct list_head *chans, char *str, int size, | 47 | extern int chan_config_string(struct list_head *chans, char *str, int size, |
50 | char **error_out); | 48 | char **error_out); |
51 | 49 | ||
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 984f80e668ca..6540d2c9fbb7 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c | |||
@@ -59,7 +59,7 @@ static int make_proc_exitcode(void) | |||
59 | { | 59 | { |
60 | struct proc_dir_entry *ent; | 60 | struct proc_dir_entry *ent; |
61 | 61 | ||
62 | ent = create_proc_entry("exitcode", 0600, &proc_root); | 62 | ent = create_proc_entry("exitcode", 0600, NULL); |
63 | if (ent == NULL) { | 63 | if (ent == NULL) { |
64 | printk(KERN_WARNING "make_proc_exitcode : Failed to register " | 64 | printk(KERN_WARNING "make_proc_exitcode : Failed to register " |
65 | "/proc/exitcode\n"); | 65 | "/proc/exitcode\n"); |
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index e8cb9ff183e9..83603cfbde81 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -364,7 +364,7 @@ int __init make_proc_sysemu(void) | |||
364 | if (!sysemu_supported) | 364 | if (!sysemu_supported) |
365 | return 0; | 365 | return 0; |
366 | 366 | ||
367 | ent = create_proc_entry("sysemu", 0600, &proc_root); | 367 | ent = create_proc_entry("sysemu", 0600, NULL); |
368 | 368 | ||
369 | if (ent == NULL) | 369 | if (ent == NULL) |
370 | { | 370 | { |
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index e066e84493b1..0d0cea2ac98d 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c | |||
@@ -4,6 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/clockchips.h> | 6 | #include <linux/clockchips.h> |
7 | #include <linux/init.h> | ||
7 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
8 | #include <linux/jiffies.h> | 9 | #include <linux/jiffies.h> |
9 | #include <linux/threads.h> | 10 | #include <linux/threads.h> |
@@ -109,8 +110,6 @@ static void __init setup_itimer(void) | |||
109 | clockevents_register_device(&itimer_clockevent); | 110 | clockevents_register_device(&itimer_clockevent); |
110 | } | 111 | } |
111 | 112 | ||
112 | extern void (*late_time_init)(void); | ||
113 | |||
114 | void __init time_init(void) | 113 | void __init time_init(void) |
115 | { | 114 | { |
116 | long long nsecs; | 115 | long long nsecs; |
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index a6c1dd1cf5a1..56deed623446 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
@@ -115,7 +115,7 @@ static int have_root __initdata = 0; | |||
115 | /* Set in uml_mem_setup and modified in linux_main */ | 115 | /* Set in uml_mem_setup and modified in linux_main */ |
116 | long long physmem_size = 32 * 1024 * 1024; | 116 | long long physmem_size = 32 * 1024 * 1024; |
117 | 117 | ||
118 | static char *usage_string = | 118 | static const char *usage_string = |
119 | "User Mode Linux v%s\n" | 119 | "User Mode Linux v%s\n" |
120 | " available at http://user-mode-linux.sourceforge.net/\n\n"; | 120 | " available at http://user-mode-linux.sourceforge.net/\n\n"; |
121 | 121 | ||
@@ -202,7 +202,7 @@ static void __init uml_checksetup(char *line, int *add) | |||
202 | 202 | ||
203 | p = &__uml_setup_start; | 203 | p = &__uml_setup_start; |
204 | while (p < &__uml_setup_end) { | 204 | while (p < &__uml_setup_end) { |
205 | int n; | 205 | size_t n; |
206 | 206 | ||
207 | n = strlen(p->str); | 207 | n = strlen(p->str); |
208 | if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) | 208 | if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) |
@@ -258,7 +258,8 @@ int __init linux_main(int argc, char **argv) | |||
258 | { | 258 | { |
259 | unsigned long avail, diff; | 259 | unsigned long avail, diff; |
260 | unsigned long virtmem_size, max_physmem; | 260 | unsigned long virtmem_size, max_physmem; |
261 | unsigned int i, add; | 261 | unsigned int i; |
262 | int add; | ||
262 | char * mode; | 263 | char * mode; |
263 | 264 | ||
264 | for (i = 1; i < argc; i++) { | 265 | for (i = 1; i < argc; i++) { |
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b616e15638fb..997d01944f91 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -25,15 +25,15 @@ | |||
25 | #include "registers.h" | 25 | #include "registers.h" |
26 | #include "skas_ptrace.h" | 26 | #include "skas_ptrace.h" |
27 | 27 | ||
28 | static int ptrace_child(void) | 28 | static void ptrace_child(void) |
29 | { | 29 | { |
30 | int ret; | 30 | int ret; |
31 | /* Calling os_getpid because some libcs cached getpid incorrectly */ | 31 | /* Calling os_getpid because some libcs cached getpid incorrectly */ |
32 | int pid = os_getpid(), ppid = getppid(); | 32 | int pid = os_getpid(), ppid = getppid(); |
33 | int sc_result; | 33 | int sc_result; |
34 | 34 | ||
35 | change_sig(SIGWINCH, 0); | 35 | if (change_sig(SIGWINCH, 0) < 0 || |
36 | if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { | 36 | ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { |
37 | perror("ptrace"); | 37 | perror("ptrace"); |
38 | kill(pid, SIGKILL); | 38 | kill(pid, SIGKILL); |
39 | } | 39 | } |
@@ -75,9 +75,8 @@ static void fatal(char *fmt, ...) | |||
75 | va_list list; | 75 | va_list list; |
76 | 76 | ||
77 | va_start(list, fmt); | 77 | va_start(list, fmt); |
78 | vprintf(fmt, list); | 78 | vfprintf(stderr, fmt, list); |
79 | va_end(list); | 79 | va_end(list); |
80 | fflush(stdout); | ||
81 | 80 | ||
82 | exit(1); | 81 | exit(1); |
83 | } | 82 | } |
@@ -87,9 +86,8 @@ static void non_fatal(char *fmt, ...) | |||
87 | va_list list; | 86 | va_list list; |
88 | 87 | ||
89 | va_start(list, fmt); | 88 | va_start(list, fmt); |
90 | vprintf(fmt, list); | 89 | vfprintf(stderr, fmt, list); |
91 | va_end(list); | 90 | va_end(list); |
92 | fflush(stdout); | ||
93 | } | 91 | } |
94 | 92 | ||
95 | static int start_ptraced_child(void) | 93 | static int start_ptraced_child(void) |
@@ -495,7 +493,7 @@ int __init parse_iomem(char *str, int *add) | |||
495 | driver = str; | 493 | driver = str; |
496 | file = strchr(str,','); | 494 | file = strchr(str,','); |
497 | if (file == NULL) { | 495 | if (file == NULL) { |
498 | printf("parse_iomem : failed to parse iomem\n"); | 496 | fprintf(stderr, "parse_iomem : failed to parse iomem\n"); |
499 | goto out; | 497 | goto out; |
500 | } | 498 | } |
501 | *file = '\0'; | 499 | *file = '\0'; |
diff --git a/arch/um/os-Linux/sys-i386/task_size.c b/arch/um/os-Linux/sys-i386/task_size.c index 48d211b3d9a1..ccb49b0aff59 100644 --- a/arch/um/os-Linux/sys-i386/task_size.c +++ b/arch/um/os-Linux/sys-i386/task_size.c | |||
@@ -88,7 +88,10 @@ unsigned long os_get_task_size(void) | |||
88 | sa.sa_handler = segfault; | 88 | sa.sa_handler = segfault; |
89 | sigemptyset(&sa.sa_mask); | 89 | sigemptyset(&sa.sa_mask); |
90 | sa.sa_flags = SA_NODEFER; | 90 | sa.sa_flags = SA_NODEFER; |
91 | sigaction(SIGSEGV, &sa, &old); | 91 | if (sigaction(SIGSEGV, &sa, &old)) { |
92 | perror("os_get_task_size"); | ||
93 | exit(1); | ||
94 | } | ||
92 | 95 | ||
93 | if (!page_ok(bottom)) { | 96 | if (!page_ok(bottom)) { |
94 | fprintf(stderr, "Address 0x%x no good?\n", | 97 | fprintf(stderr, "Address 0x%x no good?\n", |
@@ -110,11 +113,12 @@ unsigned long os_get_task_size(void) | |||
110 | 113 | ||
111 | out: | 114 | out: |
112 | /* Restore the old SIGSEGV handling */ | 115 | /* Restore the old SIGSEGV handling */ |
113 | sigaction(SIGSEGV, &old, NULL); | 116 | if (sigaction(SIGSEGV, &old, NULL)) { |
114 | 117 | perror("os_get_task_size"); | |
118 | exit(1); | ||
119 | } | ||
115 | top <<= UM_KERN_PAGE_SHIFT; | 120 | top <<= UM_KERN_PAGE_SHIFT; |
116 | printf("0x%x\n", top); | 121 | printf("0x%x\n", top); |
117 | fflush(stdout); | ||
118 | 122 | ||
119 | return top; | 123 | return top; |
120 | } | 124 | } |
diff --git a/arch/v850/kernel/asm-offsets.c b/arch/v850/kernel/asm-offsets.c index cee5c3142d41..581e6986a776 100644 --- a/arch/v850/kernel/asm-offsets.c +++ b/arch/v850/kernel/asm-offsets.c | |||
@@ -13,14 +13,11 @@ | |||
13 | #include <linux/kernel_stat.h> | 13 | #include <linux/kernel_stat.h> |
14 | #include <linux/ptrace.h> | 14 | #include <linux/ptrace.h> |
15 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
16 | #include <linux/kbuild.h> | ||
17 | |||
16 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
17 | #include <asm/errno.h> | 19 | #include <asm/errno.h> |
18 | 20 | ||
19 | #define DEFINE(sym, val) \ | ||
20 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
21 | |||
22 | #define BLANK() asm volatile("\n->" : : ) | ||
23 | |||
24 | int main (void) | 21 | int main (void) |
25 | { | 22 | { |
26 | /* offsets into the task struct */ | 23 | /* offsets into the task struct */ |
diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c index 7165478824e7..687e367d8b64 100644 --- a/arch/v850/kernel/rte_mb_a_pci.c +++ b/arch/v850/kernel/rte_mb_a_pci.c | |||
@@ -790,8 +790,8 @@ pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr, | |||
790 | 790 | ||
791 | void __iomem *pci_iomap (struct pci_dev *dev, int bar, unsigned long max) | 791 | void __iomem *pci_iomap (struct pci_dev *dev, int bar, unsigned long max) |
792 | { | 792 | { |
793 | unsigned long start = pci_resource_start (dev, bar); | 793 | resource_size_t start = pci_resource_start (dev, bar); |
794 | unsigned long len = pci_resource_len (dev, bar); | 794 | resource_size_t len = pci_resource_len (dev, bar); |
795 | 795 | ||
796 | if (!start || len == 0) | 796 | if (!start || len == 0) |
797 | return 0; | 797 | return 0; |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2fadf794483d..f70e3e3a9fa7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -86,9 +86,6 @@ config GENERIC_GPIO | |||
86 | config ARCH_MAY_HAVE_PC_FDC | 86 | config ARCH_MAY_HAVE_PC_FDC |
87 | def_bool y | 87 | def_bool y |
88 | 88 | ||
89 | config DMI | ||
90 | def_bool y | ||
91 | |||
92 | config RWSEM_GENERIC_SPINLOCK | 89 | config RWSEM_GENERIC_SPINLOCK |
93 | def_bool !X86_XADD | 90 | def_bool !X86_XADD |
94 | 91 | ||
@@ -114,6 +111,9 @@ config GENERIC_TIME_VSYSCALL | |||
114 | config ARCH_HAS_CPU_RELAX | 111 | config ARCH_HAS_CPU_RELAX |
115 | def_bool y | 112 | def_bool y |
116 | 113 | ||
114 | config ARCH_HAS_CACHE_LINE_SIZE | ||
115 | def_bool y | ||
116 | |||
117 | config HAVE_SETUP_PER_CPU_AREA | 117 | config HAVE_SETUP_PER_CPU_AREA |
118 | def_bool X86_64 || (X86_SMP && !X86_VOYAGER) | 118 | def_bool X86_64 || (X86_SMP && !X86_VOYAGER) |
119 | 119 | ||
@@ -373,6 +373,25 @@ config VMI | |||
373 | at the moment), by linking the kernel to a GPL-ed ROM module | 373 | at the moment), by linking the kernel to a GPL-ed ROM module |
374 | provided by the hypervisor. | 374 | provided by the hypervisor. |
375 | 375 | ||
376 | config KVM_CLOCK | ||
377 | bool "KVM paravirtualized clock" | ||
378 | select PARAVIRT | ||
379 | depends on !(X86_VISWS || X86_VOYAGER) | ||
380 | help | ||
381 | Turning on this option will allow you to run a paravirtualized clock | ||
382 | when running over the KVM hypervisor. Instead of relying on a PIT | ||
383 | (or probably other) emulation by the underlying device model, the host | ||
384 | provides the guest with timing infrastructure such as time of day, and | ||
385 | system time | ||
386 | |||
387 | config KVM_GUEST | ||
388 | bool "KVM Guest support" | ||
389 | select PARAVIRT | ||
390 | depends on !(X86_VISWS || X86_VOYAGER) | ||
391 | help | ||
392 | This option enables various optimizations for running under the KVM | ||
393 | hypervisor. | ||
394 | |||
376 | source "arch/x86/lguest/Kconfig" | 395 | source "arch/x86/lguest/Kconfig" |
377 | 396 | ||
378 | config PARAVIRT | 397 | config PARAVIRT |
@@ -463,6 +482,15 @@ config HPET_EMULATE_RTC | |||
463 | 482 | ||
464 | # Mark as embedded because too many people got it wrong. | 483 | # Mark as embedded because too many people got it wrong. |
465 | # The code disables itself when not needed. | 484 | # The code disables itself when not needed. |
485 | config DMI | ||
486 | default y | ||
487 | bool "Enable DMI scanning" if EMBEDDED | ||
488 | help | ||
489 | Enabled scanning of DMI to identify machine quirks. Say Y | ||
490 | here unless you have verified that your setup is not | ||
491 | affected by entries in the DMI blacklist. Required by PNP | ||
492 | BIOS code. | ||
493 | |||
466 | config GART_IOMMU | 494 | config GART_IOMMU |
467 | bool "GART IOMMU support" if EMBEDDED | 495 | bool "GART IOMMU support" if EMBEDDED |
468 | default y | 496 | default y |
@@ -509,9 +537,6 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT | |||
509 | Calgary anyway, pass 'iommu=calgary' on the kernel command line. | 537 | Calgary anyway, pass 'iommu=calgary' on the kernel command line. |
510 | If unsure, say Y. | 538 | If unsure, say Y. |
511 | 539 | ||
512 | config IOMMU_HELPER | ||
513 | def_bool (CALGARY_IOMMU || GART_IOMMU) | ||
514 | |||
515 | # need this always selected by IOMMU for the VIA workaround | 540 | # need this always selected by IOMMU for the VIA workaround |
516 | config SWIOTLB | 541 | config SWIOTLB |
517 | bool | 542 | bool |
@@ -522,6 +547,8 @@ config SWIOTLB | |||
522 | access 32-bits of memory can be used on systems with more than | 547 | access 32-bits of memory can be used on systems with more than |
523 | 3 GB of memory. If unsure, say Y. | 548 | 3 GB of memory. If unsure, say Y. |
524 | 549 | ||
550 | config IOMMU_HELPER | ||
551 | def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB) | ||
525 | 552 | ||
526 | config NR_CPUS | 553 | config NR_CPUS |
527 | int "Maximum number of CPUs (2-255)" | 554 | int "Maximum number of CPUs (2-255)" |
@@ -1477,6 +1504,10 @@ config PCI_GODIRECT | |||
1477 | config PCI_GOANY | 1504 | config PCI_GOANY |
1478 | bool "Any" | 1505 | bool "Any" |
1479 | 1506 | ||
1507 | config PCI_GOOLPC | ||
1508 | bool "OLPC" | ||
1509 | depends on OLPC | ||
1510 | |||
1480 | endchoice | 1511 | endchoice |
1481 | 1512 | ||
1482 | config PCI_BIOS | 1513 | config PCI_BIOS |
@@ -1486,12 +1517,17 @@ config PCI_BIOS | |||
1486 | # x86-64 doesn't support PCI BIOS access from long mode so always go direct. | 1517 | # x86-64 doesn't support PCI BIOS access from long mode so always go direct. |
1487 | config PCI_DIRECT | 1518 | config PCI_DIRECT |
1488 | def_bool y | 1519 | def_bool y |
1489 | depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS) | 1520 | depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS) |
1490 | 1521 | ||
1491 | config PCI_MMCONFIG | 1522 | config PCI_MMCONFIG |
1492 | def_bool y | 1523 | def_bool y |
1493 | depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) | 1524 | depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) |
1494 | 1525 | ||
1526 | config PCI_OLPC | ||
1527 | bool | ||
1528 | depends on PCI && PCI_GOOLPC | ||
1529 | default y | ||
1530 | |||
1495 | config PCI_DOMAINS | 1531 | config PCI_DOMAINS |
1496 | def_bool y | 1532 | def_bool y |
1497 | depends on PCI | 1533 | depends on PCI |
@@ -1611,6 +1647,13 @@ config GEODE_MFGPT_TIMER | |||
1611 | MFGPTs have a better resolution and max interval than the | 1647 | MFGPTs have a better resolution and max interval than the |
1612 | generic PIT, and are suitable for use as high-res timers. | 1648 | generic PIT, and are suitable for use as high-res timers. |
1613 | 1649 | ||
1650 | config OLPC | ||
1651 | bool "One Laptop Per Child support" | ||
1652 | default n | ||
1653 | help | ||
1654 | Add support for detecting the unique features of the OLPC | ||
1655 | XO hardware. | ||
1656 | |||
1614 | endif # X86_32 | 1657 | endif # X86_32 |
1615 | 1658 | ||
1616 | config K8_NB | 1659 | config K8_NB |
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c index d84a48ece785..03399d64013b 100644 --- a/arch/x86/boot/edd.c +++ b/arch/x86/boot/edd.c | |||
@@ -126,17 +126,25 @@ void query_edd(void) | |||
126 | { | 126 | { |
127 | char eddarg[8]; | 127 | char eddarg[8]; |
128 | int do_mbr = 1; | 128 | int do_mbr = 1; |
129 | #ifdef CONFIG_EDD_OFF | ||
130 | int do_edd = 0; | ||
131 | #else | ||
129 | int do_edd = 1; | 132 | int do_edd = 1; |
133 | #endif | ||
130 | int be_quiet; | 134 | int be_quiet; |
131 | int devno; | 135 | int devno; |
132 | struct edd_info ei, *edp; | 136 | struct edd_info ei, *edp; |
133 | u32 *mbrptr; | 137 | u32 *mbrptr; |
134 | 138 | ||
135 | if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) { | 139 | if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) { |
136 | if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) | 140 | if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) { |
141 | do_edd = 1; | ||
137 | do_mbr = 0; | 142 | do_mbr = 0; |
143 | } | ||
138 | else if (!strcmp(eddarg, "off")) | 144 | else if (!strcmp(eddarg, "off")) |
139 | do_edd = 0; | 145 | do_edd = 0; |
146 | else if (!strcmp(eddarg, "on")) | ||
147 | do_edd = 1; | ||
140 | } | 148 | } |
141 | 149 | ||
142 | be_quiet = cmdline_find_option_bool("quiet"); | 150 | be_quiet = cmdline_find_option_bool("quiet"); |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 815b650977b4..30d54ed27e55 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -80,6 +80,8 @@ obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o | |||
80 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o | 80 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o |
81 | 81 | ||
82 | obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o | 82 | obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o |
83 | obj-$(CONFIG_KVM_GUEST) += kvm.o | ||
84 | obj-$(CONFIG_KVM_CLOCK) += kvmclock.o | ||
83 | obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o | 85 | obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o |
84 | 86 | ||
85 | ifdef CONFIG_INPUT_PCSPKR | 87 | ifdef CONFIG_INPUT_PCSPKR |
@@ -89,6 +91,8 @@ endif | |||
89 | obj-$(CONFIG_SCx200) += scx200.o | 91 | obj-$(CONFIG_SCx200) += scx200.o |
90 | scx200-y += scx200_32.o | 92 | scx200-y += scx200_32.o |
91 | 93 | ||
94 | obj-$(CONFIG_OLPC) += olpc.o | ||
95 | |||
92 | ### | 96 | ### |
93 | # 64 bit specific files | 97 | # 64 bit specific files |
94 | ifeq ($(CONFIG_X86_64),y) | 98 | ifeq ($(CONFIG_X86_64),y) |
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index f0030a0999c7..e4ea362e8480 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
@@ -904,6 +904,7 @@ recalc: | |||
904 | original_pm_idle(); | 904 | original_pm_idle(); |
905 | else | 905 | else |
906 | default_idle(); | 906 | default_idle(); |
907 | local_irq_disable(); | ||
907 | jiffies_since_last_check = jiffies - last_jiffies; | 908 | jiffies_since_last_check = jiffies - last_jiffies; |
908 | if (jiffies_since_last_check > idle_period) | 909 | if (jiffies_since_last_check > idle_period) |
909 | goto recalc; | 910 | goto recalc; |
@@ -911,6 +912,8 @@ recalc: | |||
911 | 912 | ||
912 | if (apm_idle_done) | 913 | if (apm_idle_done) |
913 | apm_do_busy(); | 914 | apm_do_busy(); |
915 | |||
916 | local_irq_enable(); | ||
914 | } | 917 | } |
915 | 918 | ||
916 | /** | 919 | /** |
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index 670c3c311289..92588083950f 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/signal.h> | 9 | #include <linux/signal.h> |
10 | #include <linux/personality.h> | 10 | #include <linux/personality.h> |
11 | #include <linux/suspend.h> | 11 | #include <linux/suspend.h> |
12 | #include <linux/kbuild.h> | ||
12 | #include <asm/ucontext.h> | 13 | #include <asm/ucontext.h> |
13 | #include "sigframe.h" | 14 | #include "sigframe.h" |
14 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
@@ -23,14 +24,6 @@ | |||
23 | #include <linux/lguest.h> | 24 | #include <linux/lguest.h> |
24 | #include "../../../drivers/lguest/lg.h" | 25 | #include "../../../drivers/lguest/lg.h" |
25 | 26 | ||
26 | #define DEFINE(sym, val) \ | ||
27 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
28 | |||
29 | #define BLANK() asm volatile("\n->" : : ) | ||
30 | |||
31 | #define OFFSET(sym, str, mem) \ | ||
32 | DEFINE(sym, offsetof(struct str, mem)); | ||
33 | |||
34 | /* workaround for a warning with -Wmissing-prototypes */ | 27 | /* workaround for a warning with -Wmissing-prototypes */ |
35 | void foo(void); | 28 | void foo(void); |
36 | 29 | ||
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index 494e1e096ee6..f126c05d6170 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
12 | #include <linux/suspend.h> | 12 | #include <linux/suspend.h> |
13 | #include <linux/kbuild.h> | ||
13 | #include <asm/pda.h> | 14 | #include <asm/pda.h> |
14 | #include <asm/processor.h> | 15 | #include <asm/processor.h> |
15 | #include <asm/segment.h> | 16 | #include <asm/segment.h> |
@@ -17,14 +18,6 @@ | |||
17 | #include <asm/ia32.h> | 18 | #include <asm/ia32.h> |
18 | #include <asm/bootparam.h> | 19 | #include <asm/bootparam.h> |
19 | 20 | ||
20 | #define DEFINE(sym, val) \ | ||
21 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
22 | |||
23 | #define BLANK() asm volatile("\n->" : : ) | ||
24 | |||
25 | #define OFFSET(sym, str, mem) \ | ||
26 | DEFINE(sym, offsetof(struct str, mem)) | ||
27 | |||
28 | #define __NO_STUBS 1 | 21 | #define __NO_STUBS 1 |
29 | #undef __SYSCALL | 22 | #undef __SYSCALL |
30 | #undef _ASM_X86_64_UNISTD_H_ | 23 | #undef _ASM_X86_64_UNISTD_H_ |
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index e2d870de837c..b0c8208df9fa 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -339,6 +339,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | |||
339 | { | 339 | { |
340 | struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu); | 340 | struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu); |
341 | unsigned int freq; | 341 | unsigned int freq; |
342 | unsigned int cached_freq; | ||
342 | 343 | ||
343 | dprintk("get_cur_freq_on_cpu (%d)\n", cpu); | 344 | dprintk("get_cur_freq_on_cpu (%d)\n", cpu); |
344 | 345 | ||
@@ -347,7 +348,16 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) | |||
347 | return 0; | 348 | return 0; |
348 | } | 349 | } |
349 | 350 | ||
351 | cached_freq = data->freq_table[data->acpi_data->state].frequency; | ||
350 | freq = extract_freq(get_cur_val(&cpumask_of_cpu(cpu)), data); | 352 | freq = extract_freq(get_cur_val(&cpumask_of_cpu(cpu)), data); |
353 | if (freq != cached_freq) { | ||
354 | /* | ||
355 | * The dreaded BIOS frequency change behind our back. | ||
356 | * Force set the frequency on next target call. | ||
357 | */ | ||
358 | data->resume = 1; | ||
359 | } | ||
360 | |||
351 | dprintk("cur freq = %u\n", freq); | 361 | dprintk("cur freq = %u\n", freq); |
352 | 362 | ||
353 | return freq; | 363 | return freq; |
@@ -591,6 +601,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
591 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { | 601 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { |
592 | policy->cpus = perf->shared_cpu_map; | 602 | policy->cpus = perf->shared_cpu_map; |
593 | } | 603 | } |
604 | policy->related_cpus = perf->shared_cpu_map; | ||
594 | 605 | ||
595 | #ifdef CONFIG_SMP | 606 | #ifdef CONFIG_SMP |
596 | dmi_check_system(sw_any_bug_dmi_table); | 607 | dmi_check_system(sw_any_bug_dmi_table); |
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c index 1960f1985e5e..84c480bb3715 100644 --- a/arch/x86/kernel/cpu/mtrr/if.c +++ b/arch/x86/kernel/cpu/mtrr/if.c | |||
@@ -424,7 +424,7 @@ static int __init mtrr_if_init(void) | |||
424 | return -ENODEV; | 424 | return -ENODEV; |
425 | 425 | ||
426 | proc_root_mtrr = | 426 | proc_root_mtrr = |
427 | proc_create("mtrr", S_IWUSR | S_IRUGO, &proc_root, &mtrr_fops); | 427 | proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops); |
428 | 428 | ||
429 | if (proc_root_mtrr) | 429 | if (proc_root_mtrr) |
430 | proc_root_mtrr->owner = THIS_MODULE; | 430 | proc_root_mtrr->owner = THIS_MODULE; |
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 2251d0ae9570..268553817909 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/hpet.h> | 25 | #include <asm/hpet.h> |
26 | #include <linux/kdebug.h> | 26 | #include <linux/kdebug.h> |
27 | #include <asm/smp.h> | 27 | #include <asm/smp.h> |
28 | #include <asm/reboot.h> | ||
28 | 29 | ||
29 | #include <mach_ipi.h> | 30 | #include <mach_ipi.h> |
30 | 31 | ||
@@ -117,7 +118,7 @@ static void nmi_shootdown_cpus(void) | |||
117 | } | 118 | } |
118 | #endif | 119 | #endif |
119 | 120 | ||
120 | void machine_crash_shutdown(struct pt_regs *regs) | 121 | void native_machine_crash_shutdown(struct pt_regs *regs) |
121 | { | 122 | { |
122 | /* This function is only called after the system | 123 | /* This function is only called after the system |
123 | * has panicked or is otherwise in a critical state. | 124 | * has panicked or is otherwise in a critical state. |
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index 696b8e4e66bb..a40d54fc1fdd 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
@@ -2444,6 +2444,7 @@ void destroy_irq(unsigned int irq) | |||
2444 | dynamic_irq_cleanup(irq); | 2444 | dynamic_irq_cleanup(irq); |
2445 | 2445 | ||
2446 | spin_lock_irqsave(&vector_lock, flags); | 2446 | spin_lock_irqsave(&vector_lock, flags); |
2447 | clear_bit(irq_vector[irq], used_vectors); | ||
2447 | irq_vector[irq] = 0; | 2448 | irq_vector[irq] = 0; |
2448 | spin_unlock_irqrestore(&vector_lock, flags); | 2449 | spin_unlock_irqrestore(&vector_lock, flags); |
2449 | } | 2450 | } |
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 00bda7bcda63..147352df28b9 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c | |||
@@ -190,8 +190,6 @@ void irq_ctx_exit(int cpu) | |||
190 | hardirq_ctx[cpu] = NULL; | 190 | hardirq_ctx[cpu] = NULL; |
191 | } | 191 | } |
192 | 192 | ||
193 | extern asmlinkage void __do_softirq(void); | ||
194 | |||
195 | asmlinkage void do_softirq(void) | 193 | asmlinkage void do_softirq(void) |
196 | { | 194 | { |
197 | unsigned long flags; | 195 | unsigned long flags; |
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c new file mode 100644 index 000000000000..8b7a3cf37d2b --- /dev/null +++ b/arch/x86/kernel/kvm.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * KVM paravirt_ops implementation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
17 | * | ||
18 | * Copyright (C) 2007, Red Hat, Inc., Ingo Molnar <mingo@redhat.com> | ||
19 | * Copyright IBM Corporation, 2007 | ||
20 | * Authors: Anthony Liguori <aliguori@us.ibm.com> | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/kvm_para.h> | ||
26 | #include <linux/cpu.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/highmem.h> | ||
29 | #include <linux/hardirq.h> | ||
30 | |||
31 | #define MMU_QUEUE_SIZE 1024 | ||
32 | |||
33 | struct kvm_para_state { | ||
34 | u8 mmu_queue[MMU_QUEUE_SIZE]; | ||
35 | int mmu_queue_len; | ||
36 | enum paravirt_lazy_mode mode; | ||
37 | }; | ||
38 | |||
39 | static DEFINE_PER_CPU(struct kvm_para_state, para_state); | ||
40 | |||
41 | static struct kvm_para_state *kvm_para_state(void) | ||
42 | { | ||
43 | return &per_cpu(para_state, raw_smp_processor_id()); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * No need for any "IO delay" on KVM | ||
48 | */ | ||
49 | static void kvm_io_delay(void) | ||
50 | { | ||
51 | } | ||
52 | |||
53 | static void kvm_mmu_op(void *buffer, unsigned len) | ||
54 | { | ||
55 | int r; | ||
56 | unsigned long a1, a2; | ||
57 | |||
58 | do { | ||
59 | a1 = __pa(buffer); | ||
60 | a2 = 0; /* on i386 __pa() always returns <4G */ | ||
61 | r = kvm_hypercall3(KVM_HC_MMU_OP, len, a1, a2); | ||
62 | buffer += r; | ||
63 | len -= r; | ||
64 | } while (len); | ||
65 | } | ||
66 | |||
67 | static void mmu_queue_flush(struct kvm_para_state *state) | ||
68 | { | ||
69 | if (state->mmu_queue_len) { | ||
70 | kvm_mmu_op(state->mmu_queue, state->mmu_queue_len); | ||
71 | state->mmu_queue_len = 0; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static void kvm_deferred_mmu_op(void *buffer, int len) | ||
76 | { | ||
77 | struct kvm_para_state *state = kvm_para_state(); | ||
78 | |||
79 | if (state->mode != PARAVIRT_LAZY_MMU) { | ||
80 | kvm_mmu_op(buffer, len); | ||
81 | return; | ||
82 | } | ||
83 | if (state->mmu_queue_len + len > sizeof state->mmu_queue) | ||
84 | mmu_queue_flush(state); | ||
85 | memcpy(state->mmu_queue + state->mmu_queue_len, buffer, len); | ||
86 | state->mmu_queue_len += len; | ||
87 | } | ||
88 | |||
89 | static void kvm_mmu_write(void *dest, u64 val) | ||
90 | { | ||
91 | __u64 pte_phys; | ||
92 | struct kvm_mmu_op_write_pte wpte; | ||
93 | |||
94 | #ifdef CONFIG_HIGHPTE | ||
95 | struct page *page; | ||
96 | unsigned long dst = (unsigned long) dest; | ||
97 | |||
98 | page = kmap_atomic_to_page(dest); | ||
99 | pte_phys = page_to_pfn(page); | ||
100 | pte_phys <<= PAGE_SHIFT; | ||
101 | pte_phys += (dst & ~(PAGE_MASK)); | ||
102 | #else | ||
103 | pte_phys = (unsigned long)__pa(dest); | ||
104 | #endif | ||
105 | wpte.header.op = KVM_MMU_OP_WRITE_PTE; | ||
106 | wpte.pte_val = val; | ||
107 | wpte.pte_phys = pte_phys; | ||
108 | |||
109 | kvm_deferred_mmu_op(&wpte, sizeof wpte); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * We only need to hook operations that are MMU writes. We hook these so that | ||
114 | * we can use lazy MMU mode to batch these operations. We could probably | ||
115 | * improve the performance of the host code if we used some of the information | ||
116 | * here to simplify processing of batched writes. | ||
117 | */ | ||
118 | static void kvm_set_pte(pte_t *ptep, pte_t pte) | ||
119 | { | ||
120 | kvm_mmu_write(ptep, pte_val(pte)); | ||
121 | } | ||
122 | |||
123 | static void kvm_set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
124 | pte_t *ptep, pte_t pte) | ||
125 | { | ||
126 | kvm_mmu_write(ptep, pte_val(pte)); | ||
127 | } | ||
128 | |||
129 | static void kvm_set_pmd(pmd_t *pmdp, pmd_t pmd) | ||
130 | { | ||
131 | kvm_mmu_write(pmdp, pmd_val(pmd)); | ||
132 | } | ||
133 | |||
134 | #if PAGETABLE_LEVELS >= 3 | ||
135 | #ifdef CONFIG_X86_PAE | ||
136 | static void kvm_set_pte_atomic(pte_t *ptep, pte_t pte) | ||
137 | { | ||
138 | kvm_mmu_write(ptep, pte_val(pte)); | ||
139 | } | ||
140 | |||
141 | static void kvm_set_pte_present(struct mm_struct *mm, unsigned long addr, | ||
142 | pte_t *ptep, pte_t pte) | ||
143 | { | ||
144 | kvm_mmu_write(ptep, pte_val(pte)); | ||
145 | } | ||
146 | |||
147 | static void kvm_pte_clear(struct mm_struct *mm, | ||
148 | unsigned long addr, pte_t *ptep) | ||
149 | { | ||
150 | kvm_mmu_write(ptep, 0); | ||
151 | } | ||
152 | |||
153 | static void kvm_pmd_clear(pmd_t *pmdp) | ||
154 | { | ||
155 | kvm_mmu_write(pmdp, 0); | ||
156 | } | ||
157 | #endif | ||
158 | |||
159 | static void kvm_set_pud(pud_t *pudp, pud_t pud) | ||
160 | { | ||
161 | kvm_mmu_write(pudp, pud_val(pud)); | ||
162 | } | ||
163 | |||
164 | #if PAGETABLE_LEVELS == 4 | ||
165 | static void kvm_set_pgd(pgd_t *pgdp, pgd_t pgd) | ||
166 | { | ||
167 | kvm_mmu_write(pgdp, pgd_val(pgd)); | ||
168 | } | ||
169 | #endif | ||
170 | #endif /* PAGETABLE_LEVELS >= 3 */ | ||
171 | |||
172 | static void kvm_flush_tlb(void) | ||
173 | { | ||
174 | struct kvm_mmu_op_flush_tlb ftlb = { | ||
175 | .header.op = KVM_MMU_OP_FLUSH_TLB, | ||
176 | }; | ||
177 | |||
178 | kvm_deferred_mmu_op(&ftlb, sizeof ftlb); | ||
179 | } | ||
180 | |||
181 | static void kvm_release_pt(u32 pfn) | ||
182 | { | ||
183 | struct kvm_mmu_op_release_pt rpt = { | ||
184 | .header.op = KVM_MMU_OP_RELEASE_PT, | ||
185 | .pt_phys = (u64)pfn << PAGE_SHIFT, | ||
186 | }; | ||
187 | |||
188 | kvm_mmu_op(&rpt, sizeof rpt); | ||
189 | } | ||
190 | |||
191 | static void kvm_enter_lazy_mmu(void) | ||
192 | { | ||
193 | struct kvm_para_state *state = kvm_para_state(); | ||
194 | |||
195 | paravirt_enter_lazy_mmu(); | ||
196 | state->mode = paravirt_get_lazy_mode(); | ||
197 | } | ||
198 | |||
199 | static void kvm_leave_lazy_mmu(void) | ||
200 | { | ||
201 | struct kvm_para_state *state = kvm_para_state(); | ||
202 | |||
203 | mmu_queue_flush(state); | ||
204 | paravirt_leave_lazy(paravirt_get_lazy_mode()); | ||
205 | state->mode = paravirt_get_lazy_mode(); | ||
206 | } | ||
207 | |||
208 | static void paravirt_ops_setup(void) | ||
209 | { | ||
210 | pv_info.name = "KVM"; | ||
211 | pv_info.paravirt_enabled = 1; | ||
212 | |||
213 | if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY)) | ||
214 | pv_cpu_ops.io_delay = kvm_io_delay; | ||
215 | |||
216 | if (kvm_para_has_feature(KVM_FEATURE_MMU_OP)) { | ||
217 | pv_mmu_ops.set_pte = kvm_set_pte; | ||
218 | pv_mmu_ops.set_pte_at = kvm_set_pte_at; | ||
219 | pv_mmu_ops.set_pmd = kvm_set_pmd; | ||
220 | #if PAGETABLE_LEVELS >= 3 | ||
221 | #ifdef CONFIG_X86_PAE | ||
222 | pv_mmu_ops.set_pte_atomic = kvm_set_pte_atomic; | ||
223 | pv_mmu_ops.set_pte_present = kvm_set_pte_present; | ||
224 | pv_mmu_ops.pte_clear = kvm_pte_clear; | ||
225 | pv_mmu_ops.pmd_clear = kvm_pmd_clear; | ||
226 | #endif | ||
227 | pv_mmu_ops.set_pud = kvm_set_pud; | ||
228 | #if PAGETABLE_LEVELS == 4 | ||
229 | pv_mmu_ops.set_pgd = kvm_set_pgd; | ||
230 | #endif | ||
231 | #endif | ||
232 | pv_mmu_ops.flush_tlb_user = kvm_flush_tlb; | ||
233 | pv_mmu_ops.release_pte = kvm_release_pt; | ||
234 | pv_mmu_ops.release_pmd = kvm_release_pt; | ||
235 | pv_mmu_ops.release_pud = kvm_release_pt; | ||
236 | |||
237 | pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu; | ||
238 | pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | void __init kvm_guest_init(void) | ||
243 | { | ||
244 | if (!kvm_para_available()) | ||
245 | return; | ||
246 | |||
247 | paravirt_ops_setup(); | ||
248 | } | ||
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c new file mode 100644 index 000000000000..ddee04043aeb --- /dev/null +++ b/arch/x86/kernel/kvmclock.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* KVM paravirtual clock driver. A clocksource implementation | ||
2 | Copyright (C) 2008 Glauber de Oliveira Costa, Red Hat Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | |||
19 | #include <linux/clocksource.h> | ||
20 | #include <linux/kvm_para.h> | ||
21 | #include <asm/arch_hooks.h> | ||
22 | #include <asm/msr.h> | ||
23 | #include <asm/apic.h> | ||
24 | #include <linux/percpu.h> | ||
25 | #include <asm/reboot.h> | ||
26 | |||
27 | #define KVM_SCALE 22 | ||
28 | |||
29 | static int kvmclock = 1; | ||
30 | |||
31 | static int parse_no_kvmclock(char *arg) | ||
32 | { | ||
33 | kvmclock = 0; | ||
34 | return 0; | ||
35 | } | ||
36 | early_param("no-kvmclock", parse_no_kvmclock); | ||
37 | |||
38 | /* The hypervisor will put information about time periodically here */ | ||
39 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct kvm_vcpu_time_info, hv_clock); | ||
40 | #define get_clock(cpu, field) per_cpu(hv_clock, cpu).field | ||
41 | |||
42 | static inline u64 kvm_get_delta(u64 last_tsc) | ||
43 | { | ||
44 | int cpu = smp_processor_id(); | ||
45 | u64 delta = native_read_tsc() - last_tsc; | ||
46 | return (delta * get_clock(cpu, tsc_to_system_mul)) >> KVM_SCALE; | ||
47 | } | ||
48 | |||
49 | static struct kvm_wall_clock wall_clock; | ||
50 | static cycle_t kvm_clock_read(void); | ||
51 | /* | ||
52 | * The wallclock is the time of day when we booted. Since then, some time may | ||
53 | * have elapsed since the hypervisor wrote the data. So we try to account for | ||
54 | * that with system time | ||
55 | */ | ||
56 | unsigned long kvm_get_wallclock(void) | ||
57 | { | ||
58 | u32 wc_sec, wc_nsec; | ||
59 | u64 delta; | ||
60 | struct timespec ts; | ||
61 | int version, nsec; | ||
62 | int low, high; | ||
63 | |||
64 | low = (int)__pa(&wall_clock); | ||
65 | high = ((u64)__pa(&wall_clock) >> 32); | ||
66 | |||
67 | delta = kvm_clock_read(); | ||
68 | |||
69 | native_write_msr(MSR_KVM_WALL_CLOCK, low, high); | ||
70 | do { | ||
71 | version = wall_clock.wc_version; | ||
72 | rmb(); | ||
73 | wc_sec = wall_clock.wc_sec; | ||
74 | wc_nsec = wall_clock.wc_nsec; | ||
75 | rmb(); | ||
76 | } while ((wall_clock.wc_version != version) || (version & 1)); | ||
77 | |||
78 | delta = kvm_clock_read() - delta; | ||
79 | delta += wc_nsec; | ||
80 | nsec = do_div(delta, NSEC_PER_SEC); | ||
81 | set_normalized_timespec(&ts, wc_sec + delta, nsec); | ||
82 | /* | ||
83 | * Of all mechanisms of time adjustment I've tested, this one | ||
84 | * was the champion! | ||
85 | */ | ||
86 | return ts.tv_sec + 1; | ||
87 | } | ||
88 | |||
89 | int kvm_set_wallclock(unsigned long now) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * This is our read_clock function. The host puts an tsc timestamp each time | ||
96 | * it updates a new time. Without the tsc adjustment, we can have a situation | ||
97 | * in which a vcpu starts to run earlier (smaller system_time), but probes | ||
98 | * time later (compared to another vcpu), leading to backwards time | ||
99 | */ | ||
100 | static cycle_t kvm_clock_read(void) | ||
101 | { | ||
102 | u64 last_tsc, now; | ||
103 | int cpu; | ||
104 | |||
105 | preempt_disable(); | ||
106 | cpu = smp_processor_id(); | ||
107 | |||
108 | last_tsc = get_clock(cpu, tsc_timestamp); | ||
109 | now = get_clock(cpu, system_time); | ||
110 | |||
111 | now += kvm_get_delta(last_tsc); | ||
112 | preempt_enable(); | ||
113 | |||
114 | return now; | ||
115 | } | ||
116 | static struct clocksource kvm_clock = { | ||
117 | .name = "kvm-clock", | ||
118 | .read = kvm_clock_read, | ||
119 | .rating = 400, | ||
120 | .mask = CLOCKSOURCE_MASK(64), | ||
121 | .mult = 1 << KVM_SCALE, | ||
122 | .shift = KVM_SCALE, | ||
123 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
124 | }; | ||
125 | |||
126 | static int kvm_register_clock(void) | ||
127 | { | ||
128 | int cpu = smp_processor_id(); | ||
129 | int low, high; | ||
130 | low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1; | ||
131 | high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32); | ||
132 | |||
133 | return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high); | ||
134 | } | ||
135 | |||
136 | static void kvm_setup_secondary_clock(void) | ||
137 | { | ||
138 | /* | ||
139 | * Now that the first cpu already had this clocksource initialized, | ||
140 | * we shouldn't fail. | ||
141 | */ | ||
142 | WARN_ON(kvm_register_clock()); | ||
143 | /* ok, done with our trickery, call native */ | ||
144 | setup_secondary_APIC_clock(); | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * After the clock is registered, the host will keep writing to the | ||
149 | * registered memory location. If the guest happens to shutdown, this memory | ||
150 | * won't be valid. In cases like kexec, in which you install a new kernel, this | ||
151 | * means a random memory location will be kept being written. So before any | ||
152 | * kind of shutdown from our side, we unregister the clock by writting anything | ||
153 | * that does not have the 'enable' bit set in the msr | ||
154 | */ | ||
155 | #ifdef CONFIG_KEXEC | ||
156 | static void kvm_crash_shutdown(struct pt_regs *regs) | ||
157 | { | ||
158 | native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0); | ||
159 | native_machine_crash_shutdown(regs); | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | static void kvm_shutdown(void) | ||
164 | { | ||
165 | native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0); | ||
166 | native_machine_shutdown(); | ||
167 | } | ||
168 | |||
169 | void __init kvmclock_init(void) | ||
170 | { | ||
171 | if (!kvm_para_available()) | ||
172 | return; | ||
173 | |||
174 | if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { | ||
175 | if (kvm_register_clock()) | ||
176 | return; | ||
177 | pv_time_ops.get_wallclock = kvm_get_wallclock; | ||
178 | pv_time_ops.set_wallclock = kvm_set_wallclock; | ||
179 | pv_time_ops.sched_clock = kvm_clock_read; | ||
180 | pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock; | ||
181 | machine_ops.shutdown = kvm_shutdown; | ||
182 | #ifdef CONFIG_KEXEC | ||
183 | machine_ops.crash_shutdown = kvm_crash_shutdown; | ||
184 | #endif | ||
185 | clocksource_register(&kvm_clock); | ||
186 | } | ||
187 | } | ||
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index cfc2648d25ff..3cad17fe026b 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c | |||
@@ -63,7 +63,7 @@ static int __init mfgpt_fix(char *s) | |||
63 | 63 | ||
64 | /* The following udocumented bit resets the MFGPT timers */ | 64 | /* The following udocumented bit resets the MFGPT timers */ |
65 | val = 0xFF; dummy = 0; | 65 | val = 0xFF; dummy = 0; |
66 | wrmsr(0x5140002B, val, dummy); | 66 | wrmsr(MSR_MFGPT_SETUP, val, dummy); |
67 | return 1; | 67 | return 1; |
68 | } | 68 | } |
69 | __setup("mfgptfix", mfgpt_fix); | 69 | __setup("mfgptfix", mfgpt_fix); |
@@ -127,17 +127,17 @@ int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) | |||
127 | * 6; that is, resets for 7 and 8 will be ignored. Is this | 127 | * 6; that is, resets for 7 and 8 will be ignored. Is this |
128 | * a problem? -dilinger | 128 | * a problem? -dilinger |
129 | */ | 129 | */ |
130 | msr = MFGPT_NR_MSR; | 130 | msr = MSR_MFGPT_NR; |
131 | mask = 1 << (timer + 24); | 131 | mask = 1 << (timer + 24); |
132 | break; | 132 | break; |
133 | 133 | ||
134 | case MFGPT_EVENT_NMI: | 134 | case MFGPT_EVENT_NMI: |
135 | msr = MFGPT_NR_MSR; | 135 | msr = MSR_MFGPT_NR; |
136 | mask = 1 << (timer + shift); | 136 | mask = 1 << (timer + shift); |
137 | break; | 137 | break; |
138 | 138 | ||
139 | case MFGPT_EVENT_IRQ: | 139 | case MFGPT_EVENT_IRQ: |
140 | msr = MFGPT_IRQ_MSR; | 140 | msr = MSR_MFGPT_IRQ; |
141 | mask = 1 << (timer + shift); | 141 | mask = 1 << (timer + shift); |
142 | break; | 142 | break; |
143 | 143 | ||
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c new file mode 100644 index 000000000000..3e6672274807 --- /dev/null +++ b/arch/x86/kernel/olpc.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * Support for the OLPC DCON and OLPC EC access | ||
3 | * | ||
4 | * Copyright © 2006 Advanced Micro Devices, Inc. | ||
5 | * Copyright © 2007-2008 Andres Salomon <dilinger@debian.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <asm/geode.h> | ||
21 | #include <asm/olpc.h> | ||
22 | |||
23 | #ifdef CONFIG_OPEN_FIRMWARE | ||
24 | #include <asm/ofw.h> | ||
25 | #endif | ||
26 | |||
27 | struct olpc_platform_t olpc_platform_info; | ||
28 | EXPORT_SYMBOL_GPL(olpc_platform_info); | ||
29 | |||
30 | static DEFINE_SPINLOCK(ec_lock); | ||
31 | |||
32 | /* what the timeout *should* be (in ms) */ | ||
33 | #define EC_BASE_TIMEOUT 20 | ||
34 | |||
35 | /* the timeout that bugs in the EC might force us to actually use */ | ||
36 | static int ec_timeout = EC_BASE_TIMEOUT; | ||
37 | |||
38 | static int __init olpc_ec_timeout_set(char *str) | ||
39 | { | ||
40 | if (get_option(&str, &ec_timeout) != 1) { | ||
41 | ec_timeout = EC_BASE_TIMEOUT; | ||
42 | printk(KERN_ERR "olpc-ec: invalid argument to " | ||
43 | "'olpc_ec_timeout=', ignoring!\n"); | ||
44 | } | ||
45 | printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n", | ||
46 | ec_timeout); | ||
47 | return 1; | ||
48 | } | ||
49 | __setup("olpc_ec_timeout=", olpc_ec_timeout_set); | ||
50 | |||
51 | /* | ||
52 | * These {i,o}bf_status functions return whether the buffers are full or not. | ||
53 | */ | ||
54 | |||
55 | static inline unsigned int ibf_status(unsigned int port) | ||
56 | { | ||
57 | return !!(inb(port) & 0x02); | ||
58 | } | ||
59 | |||
60 | static inline unsigned int obf_status(unsigned int port) | ||
61 | { | ||
62 | return inb(port) & 0x01; | ||
63 | } | ||
64 | |||
65 | #define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d)) | ||
66 | static int __wait_on_ibf(unsigned int line, unsigned int port, int desired) | ||
67 | { | ||
68 | unsigned int timeo; | ||
69 | int state = ibf_status(port); | ||
70 | |||
71 | for (timeo = ec_timeout; state != desired && timeo; timeo--) { | ||
72 | mdelay(1); | ||
73 | state = ibf_status(port); | ||
74 | } | ||
75 | |||
76 | if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && | ||
77 | timeo < (ec_timeout - EC_BASE_TIMEOUT)) { | ||
78 | printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n", | ||
79 | line, ec_timeout - timeo); | ||
80 | } | ||
81 | |||
82 | return !(state == desired); | ||
83 | } | ||
84 | |||
85 | #define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d)) | ||
86 | static int __wait_on_obf(unsigned int line, unsigned int port, int desired) | ||
87 | { | ||
88 | unsigned int timeo; | ||
89 | int state = obf_status(port); | ||
90 | |||
91 | for (timeo = ec_timeout; state != desired && timeo; timeo--) { | ||
92 | mdelay(1); | ||
93 | state = obf_status(port); | ||
94 | } | ||
95 | |||
96 | if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) && | ||
97 | timeo < (ec_timeout - EC_BASE_TIMEOUT)) { | ||
98 | printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n", | ||
99 | line, ec_timeout - timeo); | ||
100 | } | ||
101 | |||
102 | return !(state == desired); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * This allows the kernel to run Embedded Controller commands. The EC is | ||
107 | * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the | ||
108 | * available EC commands are here: | ||
109 | * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while | ||
110 | * OpenFirmware's source is available, the EC's is not. | ||
111 | */ | ||
112 | int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, | ||
113 | unsigned char *outbuf, size_t outlen) | ||
114 | { | ||
115 | unsigned long flags; | ||
116 | int ret = -EIO; | ||
117 | int i; | ||
118 | |||
119 | spin_lock_irqsave(&ec_lock, flags); | ||
120 | |||
121 | /* Clear OBF */ | ||
122 | for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++) | ||
123 | inb(0x68); | ||
124 | if (i == 10) { | ||
125 | printk(KERN_ERR "olpc-ec: timeout while attempting to " | ||
126 | "clear OBF flag!\n"); | ||
127 | goto err; | ||
128 | } | ||
129 | |||
130 | if (wait_on_ibf(0x6c, 0)) { | ||
131 | printk(KERN_ERR "olpc-ec: timeout waiting for EC to " | ||
132 | "quiesce!\n"); | ||
133 | goto err; | ||
134 | } | ||
135 | |||
136 | restart: | ||
137 | /* | ||
138 | * Note that if we time out during any IBF checks, that's a failure; | ||
139 | * we have to return. There's no way for the kernel to clear that. | ||
140 | * | ||
141 | * If we time out during an OBF check, we can restart the command; | ||
142 | * reissuing it will clear the OBF flag, and we should be alright. | ||
143 | * The OBF flag will sometimes misbehave due to what we believe | ||
144 | * is a hardware quirk.. | ||
145 | */ | ||
146 | printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd); | ||
147 | outb(cmd, 0x6c); | ||
148 | |||
149 | if (wait_on_ibf(0x6c, 0)) { | ||
150 | printk(KERN_ERR "olpc-ec: timeout waiting for EC to read " | ||
151 | "command!\n"); | ||
152 | goto err; | ||
153 | } | ||
154 | |||
155 | if (inbuf && inlen) { | ||
156 | /* write data to EC */ | ||
157 | for (i = 0; i < inlen; i++) { | ||
158 | if (wait_on_ibf(0x6c, 0)) { | ||
159 | printk(KERN_ERR "olpc-ec: timeout waiting for" | ||
160 | " EC accept data!\n"); | ||
161 | goto err; | ||
162 | } | ||
163 | printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n", | ||
164 | inbuf[i]); | ||
165 | outb(inbuf[i], 0x68); | ||
166 | } | ||
167 | } | ||
168 | if (outbuf && outlen) { | ||
169 | /* read data from EC */ | ||
170 | for (i = 0; i < outlen; i++) { | ||
171 | if (wait_on_obf(0x6c, 1)) { | ||
172 | printk(KERN_ERR "olpc-ec: timeout waiting for" | ||
173 | " EC to provide data!\n"); | ||
174 | goto restart; | ||
175 | } | ||
176 | outbuf[i] = inb(0x68); | ||
177 | printk(KERN_DEBUG "olpc-ec: received 0x%x\n", | ||
178 | outbuf[i]); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | ret = 0; | ||
183 | err: | ||
184 | spin_unlock_irqrestore(&ec_lock, flags); | ||
185 | return ret; | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(olpc_ec_cmd); | ||
188 | |||
189 | #ifdef CONFIG_OPEN_FIRMWARE | ||
190 | static void __init platform_detect(void) | ||
191 | { | ||
192 | size_t propsize; | ||
193 | u32 rev; | ||
194 | |||
195 | if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4, | ||
196 | &propsize) || propsize != 4) { | ||
197 | printk(KERN_ERR "ofw: getprop call failed!\n"); | ||
198 | rev = 0; | ||
199 | } | ||
200 | olpc_platform_info.boardrev = be32_to_cpu(rev); | ||
201 | } | ||
202 | #else | ||
203 | static void __init platform_detect(void) | ||
204 | { | ||
205 | /* stopgap until OFW support is added to the kernel */ | ||
206 | olpc_platform_info.boardrev = be32_to_cpu(0xc2); | ||
207 | } | ||
208 | #endif | ||
209 | |||
210 | static int __init olpc_init(void) | ||
211 | { | ||
212 | unsigned char *romsig; | ||
213 | |||
214 | /* The ioremap check is dangerous; limit what we run it on */ | ||
215 | if (!is_geode() || geode_has_vsa2()) | ||
216 | return 0; | ||
217 | |||
218 | spin_lock_init(&ec_lock); | ||
219 | |||
220 | romsig = ioremap(0xffffffc0, 16); | ||
221 | if (!romsig) | ||
222 | return 0; | ||
223 | |||
224 | if (strncmp(romsig, "CL1 Q", 7)) | ||
225 | goto unmap; | ||
226 | if (strncmp(romsig+6, romsig+13, 3)) { | ||
227 | printk(KERN_INFO "OLPC BIOS signature looks invalid. " | ||
228 | "Assuming not OLPC\n"); | ||
229 | goto unmap; | ||
230 | } | ||
231 | |||
232 | printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig); | ||
233 | olpc_platform_info.flags |= OLPC_F_PRESENT; | ||
234 | |||
235 | /* get the platform revision */ | ||
236 | platform_detect(); | ||
237 | |||
238 | /* assume B1 and above models always have a DCON */ | ||
239 | if (olpc_board_at_least(olpc_board(0xb1))) | ||
240 | olpc_platform_info.flags |= OLPC_F_DCON; | ||
241 | |||
242 | /* get the EC revision */ | ||
243 | olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, | ||
244 | (unsigned char *) &olpc_platform_info.ecver, 1); | ||
245 | |||
246 | /* check to see if the VSA exists */ | ||
247 | if (geode_has_vsa2()) | ||
248 | olpc_platform_info.flags |= OLPC_F_VSA; | ||
249 | |||
250 | printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", | ||
251 | ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", | ||
252 | olpc_platform_info.boardrev >> 4, | ||
253 | olpc_platform_info.ecver); | ||
254 | |||
255 | unmap: | ||
256 | iounmap(romsig); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | postcore_initcall(olpc_init); | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 3004d716539d..67e9b4a1e89d 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/smp.h> | 4 | #include <linux/smp.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/module.h> | ||
8 | #include <linux/pm.h> | ||
7 | 9 | ||
8 | struct kmem_cache *task_xstate_cachep; | 10 | struct kmem_cache *task_xstate_cachep; |
9 | 11 | ||
@@ -42,3 +44,118 @@ void arch_task_cache_init(void) | |||
42 | __alignof__(union thread_xstate), | 44 | __alignof__(union thread_xstate), |
43 | SLAB_PANIC, NULL); | 45 | SLAB_PANIC, NULL); |
44 | } | 46 | } |
47 | |||
48 | static void do_nothing(void *unused) | ||
49 | { | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of | ||
54 | * pm_idle and update to new pm_idle value. Required while changing pm_idle | ||
55 | * handler on SMP systems. | ||
56 | * | ||
57 | * Caller must have changed pm_idle to the new value before the call. Old | ||
58 | * pm_idle value will not be used by any CPU after the return of this function. | ||
59 | */ | ||
60 | void cpu_idle_wait(void) | ||
61 | { | ||
62 | smp_mb(); | ||
63 | /* kick all the CPUs so that they exit out of pm_idle */ | ||
64 | smp_call_function(do_nothing, NULL, 0, 1); | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | ||
67 | |||
68 | /* | ||
69 | * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, | ||
70 | * which can obviate IPI to trigger checking of need_resched. | ||
71 | * We execute MONITOR against need_resched and enter optimized wait state | ||
72 | * through MWAIT. Whenever someone changes need_resched, we would be woken | ||
73 | * up from MWAIT (without an IPI). | ||
74 | * | ||
75 | * New with Core Duo processors, MWAIT can take some hints based on CPU | ||
76 | * capability. | ||
77 | */ | ||
78 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) | ||
79 | { | ||
80 | if (!need_resched()) { | ||
81 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | ||
82 | smp_mb(); | ||
83 | if (!need_resched()) | ||
84 | __mwait(ax, cx); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | /* Default MONITOR/MWAIT with no hints, used for default C1 state */ | ||
89 | static void mwait_idle(void) | ||
90 | { | ||
91 | if (!need_resched()) { | ||
92 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | ||
93 | smp_mb(); | ||
94 | if (!need_resched()) | ||
95 | __sti_mwait(0, 0); | ||
96 | else | ||
97 | local_irq_enable(); | ||
98 | } else | ||
99 | local_irq_enable(); | ||
100 | } | ||
101 | |||
102 | |||
103 | static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) | ||
104 | { | ||
105 | if (force_mwait) | ||
106 | return 1; | ||
107 | /* Any C1 states supported? */ | ||
108 | return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * On SMP it's slightly faster (but much more power-consuming!) | ||
113 | * to poll the ->work.need_resched flag instead of waiting for the | ||
114 | * cross-CPU IPI to arrive. Use this option with caution. | ||
115 | */ | ||
116 | static void poll_idle(void) | ||
117 | { | ||
118 | local_irq_enable(); | ||
119 | cpu_relax(); | ||
120 | } | ||
121 | |||
122 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) | ||
123 | { | ||
124 | static int selected; | ||
125 | |||
126 | if (selected) | ||
127 | return; | ||
128 | #ifdef CONFIG_X86_SMP | ||
129 | if (pm_idle == poll_idle && smp_num_siblings > 1) { | ||
130 | printk(KERN_WARNING "WARNING: polling idle and HT enabled," | ||
131 | " performance may degrade.\n"); | ||
132 | } | ||
133 | #endif | ||
134 | if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) { | ||
135 | /* | ||
136 | * Skip, if setup has overridden idle. | ||
137 | * One CPU supports mwait => All CPUs supports mwait | ||
138 | */ | ||
139 | if (!pm_idle) { | ||
140 | printk(KERN_INFO "using mwait in idle threads.\n"); | ||
141 | pm_idle = mwait_idle; | ||
142 | } | ||
143 | } | ||
144 | selected = 1; | ||
145 | } | ||
146 | |||
147 | static int __init idle_setup(char *str) | ||
148 | { | ||
149 | if (!strcmp(str, "poll")) { | ||
150 | printk("using polling idle threads.\n"); | ||
151 | pm_idle = poll_idle; | ||
152 | } else if (!strcmp(str, "mwait")) | ||
153 | force_mwait = 1; | ||
154 | else | ||
155 | return -1; | ||
156 | |||
157 | boot_option_idle_override = 1; | ||
158 | return 0; | ||
159 | } | ||
160 | early_param("idle", idle_setup); | ||
161 | |||
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 77de848bd1fb..f8476dfbb60d 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -111,12 +111,10 @@ void default_idle(void) | |||
111 | */ | 111 | */ |
112 | smp_mb(); | 112 | smp_mb(); |
113 | 113 | ||
114 | local_irq_disable(); | 114 | if (!need_resched()) |
115 | if (!need_resched()) { | ||
116 | safe_halt(); /* enables interrupts racelessly */ | 115 | safe_halt(); /* enables interrupts racelessly */ |
117 | local_irq_disable(); | 116 | else |
118 | } | 117 | local_irq_enable(); |
119 | local_irq_enable(); | ||
120 | current_thread_info()->status |= TS_POLLING; | 118 | current_thread_info()->status |= TS_POLLING; |
121 | } else { | 119 | } else { |
122 | local_irq_enable(); | 120 | local_irq_enable(); |
@@ -128,17 +126,6 @@ void default_idle(void) | |||
128 | EXPORT_SYMBOL(default_idle); | 126 | EXPORT_SYMBOL(default_idle); |
129 | #endif | 127 | #endif |
130 | 128 | ||
131 | /* | ||
132 | * On SMP it's slightly faster (but much more power-consuming!) | ||
133 | * to poll the ->work.need_resched flag instead of waiting for the | ||
134 | * cross-CPU IPI to arrive. Use this option with caution. | ||
135 | */ | ||
136 | static void poll_idle(void) | ||
137 | { | ||
138 | local_irq_enable(); | ||
139 | cpu_relax(); | ||
140 | } | ||
141 | |||
142 | #ifdef CONFIG_HOTPLUG_CPU | 129 | #ifdef CONFIG_HOTPLUG_CPU |
143 | #include <asm/nmi.h> | 130 | #include <asm/nmi.h> |
144 | /* We don't actually take CPU down, just spin without interrupts. */ | 131 | /* We don't actually take CPU down, just spin without interrupts. */ |
@@ -196,6 +183,7 @@ void cpu_idle(void) | |||
196 | if (cpu_is_offline(cpu)) | 183 | if (cpu_is_offline(cpu)) |
197 | play_dead(); | 184 | play_dead(); |
198 | 185 | ||
186 | local_irq_disable(); | ||
199 | __get_cpu_var(irq_stat).idle_timestamp = jiffies; | 187 | __get_cpu_var(irq_stat).idle_timestamp = jiffies; |
200 | idle(); | 188 | idle(); |
201 | } | 189 | } |
@@ -206,104 +194,6 @@ void cpu_idle(void) | |||
206 | } | 194 | } |
207 | } | 195 | } |
208 | 196 | ||
209 | static void do_nothing(void *unused) | ||
210 | { | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of | ||
215 | * pm_idle and update to new pm_idle value. Required while changing pm_idle | ||
216 | * handler on SMP systems. | ||
217 | * | ||
218 | * Caller must have changed pm_idle to the new value before the call. Old | ||
219 | * pm_idle value will not be used by any CPU after the return of this function. | ||
220 | */ | ||
221 | void cpu_idle_wait(void) | ||
222 | { | ||
223 | smp_mb(); | ||
224 | /* kick all the CPUs so that they exit out of pm_idle */ | ||
225 | smp_call_function(do_nothing, NULL, 0, 1); | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | ||
228 | |||
229 | /* | ||
230 | * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, | ||
231 | * which can obviate IPI to trigger checking of need_resched. | ||
232 | * We execute MONITOR against need_resched and enter optimized wait state | ||
233 | * through MWAIT. Whenever someone changes need_resched, we would be woken | ||
234 | * up from MWAIT (without an IPI). | ||
235 | * | ||
236 | * New with Core Duo processors, MWAIT can take some hints based on CPU | ||
237 | * capability. | ||
238 | */ | ||
239 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) | ||
240 | { | ||
241 | if (!need_resched()) { | ||
242 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | ||
243 | smp_mb(); | ||
244 | if (!need_resched()) | ||
245 | __sti_mwait(ax, cx); | ||
246 | else | ||
247 | local_irq_enable(); | ||
248 | } else | ||
249 | local_irq_enable(); | ||
250 | } | ||
251 | |||
252 | /* Default MONITOR/MWAIT with no hints, used for default C1 state */ | ||
253 | static void mwait_idle(void) | ||
254 | { | ||
255 | local_irq_enable(); | ||
256 | mwait_idle_with_hints(0, 0); | ||
257 | } | ||
258 | |||
259 | static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) | ||
260 | { | ||
261 | if (force_mwait) | ||
262 | return 1; | ||
263 | /* Any C1 states supported? */ | ||
264 | return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0; | ||
265 | } | ||
266 | |||
267 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) | ||
268 | { | ||
269 | static int selected; | ||
270 | |||
271 | if (selected) | ||
272 | return; | ||
273 | #ifdef CONFIG_X86_SMP | ||
274 | if (pm_idle == poll_idle && smp_num_siblings > 1) { | ||
275 | printk(KERN_WARNING "WARNING: polling idle and HT enabled," | ||
276 | " performance may degrade.\n"); | ||
277 | } | ||
278 | #endif | ||
279 | if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) { | ||
280 | /* | ||
281 | * Skip, if setup has overridden idle. | ||
282 | * One CPU supports mwait => All CPUs supports mwait | ||
283 | */ | ||
284 | if (!pm_idle) { | ||
285 | printk(KERN_INFO "using mwait in idle threads.\n"); | ||
286 | pm_idle = mwait_idle; | ||
287 | } | ||
288 | } | ||
289 | selected = 1; | ||
290 | } | ||
291 | |||
292 | static int __init idle_setup(char *str) | ||
293 | { | ||
294 | if (!strcmp(str, "poll")) { | ||
295 | printk("using polling idle threads.\n"); | ||
296 | pm_idle = poll_idle; | ||
297 | } else if (!strcmp(str, "mwait")) | ||
298 | force_mwait = 1; | ||
299 | else | ||
300 | return -1; | ||
301 | |||
302 | boot_option_idle_override = 1; | ||
303 | return 0; | ||
304 | } | ||
305 | early_param("idle", idle_setup); | ||
306 | |||
307 | void __show_registers(struct pt_regs *regs, int all) | 197 | void __show_registers(struct pt_regs *regs, int all) |
308 | { | 198 | { |
309 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; | 199 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 131c2ee7ac56..e2319f39988b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -106,26 +106,13 @@ void default_idle(void) | |||
106 | * test NEED_RESCHED: | 106 | * test NEED_RESCHED: |
107 | */ | 107 | */ |
108 | smp_mb(); | 108 | smp_mb(); |
109 | local_irq_disable(); | 109 | if (!need_resched()) |
110 | if (!need_resched()) { | ||
111 | safe_halt(); /* enables interrupts racelessly */ | 110 | safe_halt(); /* enables interrupts racelessly */ |
112 | local_irq_disable(); | 111 | else |
113 | } | 112 | local_irq_enable(); |
114 | local_irq_enable(); | ||
115 | current_thread_info()->status |= TS_POLLING; | 113 | current_thread_info()->status |= TS_POLLING; |
116 | } | 114 | } |
117 | 115 | ||
118 | /* | ||
119 | * On SMP it's slightly faster (but much more power-consuming!) | ||
120 | * to poll the ->need_resched flag instead of waiting for the | ||
121 | * cross-CPU IPI to arrive. Use this option with caution. | ||
122 | */ | ||
123 | static void poll_idle(void) | ||
124 | { | ||
125 | local_irq_enable(); | ||
126 | cpu_relax(); | ||
127 | } | ||
128 | |||
129 | #ifdef CONFIG_HOTPLUG_CPU | 116 | #ifdef CONFIG_HOTPLUG_CPU |
130 | DECLARE_PER_CPU(int, cpu_state); | 117 | DECLARE_PER_CPU(int, cpu_state); |
131 | 118 | ||
@@ -192,110 +179,6 @@ void cpu_idle(void) | |||
192 | } | 179 | } |
193 | } | 180 | } |
194 | 181 | ||
195 | static void do_nothing(void *unused) | ||
196 | { | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of | ||
201 | * pm_idle and update to new pm_idle value. Required while changing pm_idle | ||
202 | * handler on SMP systems. | ||
203 | * | ||
204 | * Caller must have changed pm_idle to the new value before the call. Old | ||
205 | * pm_idle value will not be used by any CPU after the return of this function. | ||
206 | */ | ||
207 | void cpu_idle_wait(void) | ||
208 | { | ||
209 | smp_mb(); | ||
210 | /* kick all the CPUs so that they exit out of pm_idle */ | ||
211 | smp_call_function(do_nothing, NULL, 0, 1); | ||
212 | } | ||
213 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | ||
214 | |||
215 | /* | ||
216 | * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, | ||
217 | * which can obviate IPI to trigger checking of need_resched. | ||
218 | * We execute MONITOR against need_resched and enter optimized wait state | ||
219 | * through MWAIT. Whenever someone changes need_resched, we would be woken | ||
220 | * up from MWAIT (without an IPI). | ||
221 | * | ||
222 | * New with Core Duo processors, MWAIT can take some hints based on CPU | ||
223 | * capability. | ||
224 | */ | ||
225 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) | ||
226 | { | ||
227 | if (!need_resched()) { | ||
228 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | ||
229 | smp_mb(); | ||
230 | if (!need_resched()) | ||
231 | __mwait(ax, cx); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* Default MONITOR/MWAIT with no hints, used for default C1 state */ | ||
236 | static void mwait_idle(void) | ||
237 | { | ||
238 | if (!need_resched()) { | ||
239 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | ||
240 | smp_mb(); | ||
241 | if (!need_resched()) | ||
242 | __sti_mwait(0, 0); | ||
243 | else | ||
244 | local_irq_enable(); | ||
245 | } else { | ||
246 | local_irq_enable(); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | |||
251 | static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) | ||
252 | { | ||
253 | if (force_mwait) | ||
254 | return 1; | ||
255 | /* Any C1 states supported? */ | ||
256 | return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0; | ||
257 | } | ||
258 | |||
259 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) | ||
260 | { | ||
261 | static int selected; | ||
262 | |||
263 | if (selected) | ||
264 | return; | ||
265 | #ifdef CONFIG_X86_SMP | ||
266 | if (pm_idle == poll_idle && smp_num_siblings > 1) { | ||
267 | printk(KERN_WARNING "WARNING: polling idle and HT enabled," | ||
268 | " performance may degrade.\n"); | ||
269 | } | ||
270 | #endif | ||
271 | if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) { | ||
272 | /* | ||
273 | * Skip, if setup has overridden idle. | ||
274 | * One CPU supports mwait => All CPUs supports mwait | ||
275 | */ | ||
276 | if (!pm_idle) { | ||
277 | printk(KERN_INFO "using mwait in idle threads.\n"); | ||
278 | pm_idle = mwait_idle; | ||
279 | } | ||
280 | } | ||
281 | selected = 1; | ||
282 | } | ||
283 | |||
284 | static int __init idle_setup(char *str) | ||
285 | { | ||
286 | if (!strcmp(str, "poll")) { | ||
287 | printk("using polling idle threads.\n"); | ||
288 | pm_idle = poll_idle; | ||
289 | } else if (!strcmp(str, "mwait")) | ||
290 | force_mwait = 1; | ||
291 | else | ||
292 | return -1; | ||
293 | |||
294 | boot_option_idle_override = 1; | ||
295 | return 0; | ||
296 | } | ||
297 | early_param("idle", idle_setup); | ||
298 | |||
299 | /* Prints also some state that isn't saved in the pt_regs */ | 182 | /* Prints also some state that isn't saved in the pt_regs */ |
300 | void __show_regs(struct pt_regs * regs) | 183 | void __show_regs(struct pt_regs * regs) |
301 | { | 184 | { |
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 1791a751a772..a4a838306b2c 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -399,7 +399,7 @@ static void native_machine_emergency_restart(void) | |||
399 | } | 399 | } |
400 | } | 400 | } |
401 | 401 | ||
402 | static void native_machine_shutdown(void) | 402 | void native_machine_shutdown(void) |
403 | { | 403 | { |
404 | /* Stop the cpus and apics */ | 404 | /* Stop the cpus and apics */ |
405 | #ifdef CONFIG_SMP | 405 | #ifdef CONFIG_SMP |
@@ -470,7 +470,10 @@ struct machine_ops machine_ops = { | |||
470 | .shutdown = native_machine_shutdown, | 470 | .shutdown = native_machine_shutdown, |
471 | .emergency_restart = native_machine_emergency_restart, | 471 | .emergency_restart = native_machine_emergency_restart, |
472 | .restart = native_machine_restart, | 472 | .restart = native_machine_restart, |
473 | .halt = native_machine_halt | 473 | .halt = native_machine_halt, |
474 | #ifdef CONFIG_KEXEC | ||
475 | .crash_shutdown = native_machine_crash_shutdown, | ||
476 | #endif | ||
474 | }; | 477 | }; |
475 | 478 | ||
476 | void machine_power_off(void) | 479 | void machine_power_off(void) |
@@ -498,3 +501,9 @@ void machine_halt(void) | |||
498 | machine_ops.halt(); | 501 | machine_ops.halt(); |
499 | } | 502 | } |
500 | 503 | ||
504 | #ifdef CONFIG_KEXEC | ||
505 | void machine_crash_shutdown(struct pt_regs *regs) | ||
506 | { | ||
507 | machine_ops.crash_shutdown(regs); | ||
508 | } | ||
509 | #endif | ||
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 44cc9b933932..2283422af794 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/pfn.h> | 47 | #include <linux/pfn.h> |
48 | #include <linux/pci.h> | 48 | #include <linux/pci.h> |
49 | #include <linux/init_ohci1394_dma.h> | 49 | #include <linux/init_ohci1394_dma.h> |
50 | #include <linux/kvm_para.h> | ||
50 | 51 | ||
51 | #include <video/edid.h> | 52 | #include <video/edid.h> |
52 | 53 | ||
@@ -820,6 +821,10 @@ void __init setup_arch(char **cmdline_p) | |||
820 | 821 | ||
821 | max_low_pfn = setup_memory(); | 822 | max_low_pfn = setup_memory(); |
822 | 823 | ||
824 | #ifdef CONFIG_KVM_CLOCK | ||
825 | kvmclock_init(); | ||
826 | #endif | ||
827 | |||
823 | #ifdef CONFIG_VMI | 828 | #ifdef CONFIG_VMI |
824 | /* | 829 | /* |
825 | * Must be after max_low_pfn is determined, and before kernel | 830 | * Must be after max_low_pfn is determined, and before kernel |
@@ -827,6 +832,7 @@ void __init setup_arch(char **cmdline_p) | |||
827 | */ | 832 | */ |
828 | vmi_init(); | 833 | vmi_init(); |
829 | #endif | 834 | #endif |
835 | kvm_guest_init(); | ||
830 | 836 | ||
831 | /* | 837 | /* |
832 | * NOTE: before this point _nobody_ is allowed to allocate | 838 | * NOTE: before this point _nobody_ is allowed to allocate |
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 2f5c488aad0b..22c14e21c97c 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/sort.h> | 44 | #include <linux/sort.h> |
45 | #include <linux/uaccess.h> | 45 | #include <linux/uaccess.h> |
46 | #include <linux/init_ohci1394_dma.h> | 46 | #include <linux/init_ohci1394_dma.h> |
47 | #include <linux/kvm_para.h> | ||
47 | 48 | ||
48 | #include <asm/mtrr.h> | 49 | #include <asm/mtrr.h> |
49 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
@@ -398,6 +399,10 @@ void __init setup_arch(char **cmdline_p) | |||
398 | 399 | ||
399 | io_delay_init(); | 400 | io_delay_init(); |
400 | 401 | ||
402 | #ifdef CONFIG_KVM_CLOCK | ||
403 | kvmclock_init(); | ||
404 | #endif | ||
405 | |||
401 | #ifdef CONFIG_SMP | 406 | #ifdef CONFIG_SMP |
402 | /* setup to use the early static init tables during kernel startup */ | 407 | /* setup to use the early static init tables during kernel startup */ |
403 | x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init; | 408 | x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init; |
@@ -502,6 +507,8 @@ void __init setup_arch(char **cmdline_p) | |||
502 | init_apic_mappings(); | 507 | init_apic_mappings(); |
503 | ioapic_init_mappings(); | 508 | ioapic_init_mappings(); |
504 | 509 | ||
510 | kvm_guest_init(); | ||
511 | |||
505 | /* | 512 | /* |
506 | * We trust e820 completely. No explicit ROM probing in memory. | 513 | * We trust e820 completely. No explicit ROM probing in memory. |
507 | */ | 514 | */ |
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 1a89e93f3f1c..2ff21f398934 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c | |||
@@ -115,7 +115,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
115 | return IRQ_HANDLED; | 115 | return IRQ_HANDLED; |
116 | } | 116 | } |
117 | 117 | ||
118 | extern void (*late_time_init)(void); | ||
119 | /* Duplicate of time_init() below, with hpet_enable part added */ | 118 | /* Duplicate of time_init() below, with hpet_enable part added */ |
120 | void __init hpet_time_init(void) | 119 | void __init hpet_time_init(void) |
121 | { | 120 | { |
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index b7ab3c335fae..fad3674b06a5 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S | |||
@@ -209,12 +209,6 @@ SECTIONS | |||
209 | EXIT_DATA | 209 | EXIT_DATA |
210 | } | 210 | } |
211 | 211 | ||
212 | /* vdso blob that is mapped into user space */ | ||
213 | vdso_start = . ; | ||
214 | .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) } | ||
215 | . = ALIGN(PAGE_SIZE); | ||
216 | vdso_end = .; | ||
217 | |||
218 | #ifdef CONFIG_BLK_DEV_INITRD | 212 | #ifdef CONFIG_BLK_DEV_INITRD |
219 | . = ALIGN(PAGE_SIZE); | 213 | . = ALIGN(PAGE_SIZE); |
220 | __initramfs_start = .; | 214 | __initramfs_start = .; |
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 41962e793c0f..8d45fabc5f3b 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig | |||
@@ -19,7 +19,7 @@ if VIRTUALIZATION | |||
19 | 19 | ||
20 | config KVM | 20 | config KVM |
21 | tristate "Kernel-based Virtual Machine (KVM) support" | 21 | tristate "Kernel-based Virtual Machine (KVM) support" |
22 | depends on HAVE_KVM && EXPERIMENTAL | 22 | depends on HAVE_KVM |
23 | select PREEMPT_NOTIFIERS | 23 | select PREEMPT_NOTIFIERS |
24 | select ANON_INODES | 24 | select ANON_INODES |
25 | ---help--- | 25 | ---help--- |
@@ -50,6 +50,17 @@ config KVM_AMD | |||
50 | Provides support for KVM on AMD processors equipped with the AMD-V | 50 | Provides support for KVM on AMD processors equipped with the AMD-V |
51 | (SVM) extensions. | 51 | (SVM) extensions. |
52 | 52 | ||
53 | config KVM_TRACE | ||
54 | bool "KVM trace support" | ||
55 | depends on KVM && MARKERS && SYSFS | ||
56 | select RELAY | ||
57 | select DEBUG_FS | ||
58 | default n | ||
59 | ---help--- | ||
60 | This option allows reading a trace of kvm-related events through | ||
61 | relayfs. Note the ABI is not considered stable and will be | ||
62 | modified in future updates. | ||
63 | |||
53 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | 64 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under |
54 | # the virtualization menu. | 65 | # the virtualization menu. |
55 | source drivers/lguest/Kconfig | 66 | source drivers/lguest/Kconfig |
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index ffdd0b310784..c97d35c218db 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile | |||
@@ -3,10 +3,14 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) | 5 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) |
6 | ifeq ($(CONFIG_KVM_TRACE),y) | ||
7 | common-objs += $(addprefix ../../../virt/kvm/, kvm_trace.o) | ||
8 | endif | ||
6 | 9 | ||
7 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm | 10 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm |
8 | 11 | ||
9 | kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o | 12 | kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ |
13 | i8254.o | ||
10 | obj-$(CONFIG_KVM) += kvm.o | 14 | obj-$(CONFIG_KVM) += kvm.o |
11 | kvm-intel-objs = vmx.o | 15 | kvm-intel-objs = vmx.o |
12 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | 16 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c new file mode 100644 index 000000000000..361e31611276 --- /dev/null +++ b/arch/x86/kvm/i8254.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * 8253/8254 interval timer emulation | ||
3 | * | ||
4 | * Copyright (c) 2003-2004 Fabrice Bellard | ||
5 | * Copyright (c) 2006 Intel Corporation | ||
6 | * Copyright (c) 2007 Keir Fraser, XenSource Inc | ||
7 | * Copyright (c) 2008 Intel Corporation | ||
8 | * | ||
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | * of this software and associated documentation files (the "Software"), to deal | ||
11 | * in the Software without restriction, including without limitation the rights | ||
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | * copies of the Software, and to permit persons to whom the Software is | ||
14 | * furnished to do so, subject to the following conditions: | ||
15 | * | ||
16 | * The above copyright notice and this permission notice shall be included in | ||
17 | * all copies or substantial portions of the Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
25 | * THE SOFTWARE. | ||
26 | * | ||
27 | * Authors: | ||
28 | * Sheng Yang <sheng.yang@intel.com> | ||
29 | * Based on QEMU and Xen. | ||
30 | */ | ||
31 | |||
32 | #include <linux/kvm_host.h> | ||
33 | |||
34 | #include "irq.h" | ||
35 | #include "i8254.h" | ||
36 | |||
37 | #ifndef CONFIG_X86_64 | ||
38 | #define mod_64(x, y) ((x) - (y) * div64_64(x, y)) | ||
39 | #else | ||
40 | #define mod_64(x, y) ((x) % (y)) | ||
41 | #endif | ||
42 | |||
43 | #define RW_STATE_LSB 1 | ||
44 | #define RW_STATE_MSB 2 | ||
45 | #define RW_STATE_WORD0 3 | ||
46 | #define RW_STATE_WORD1 4 | ||
47 | |||
48 | /* Compute with 96 bit intermediate result: (a*b)/c */ | ||
49 | static u64 muldiv64(u64 a, u32 b, u32 c) | ||
50 | { | ||
51 | union { | ||
52 | u64 ll; | ||
53 | struct { | ||
54 | u32 low, high; | ||
55 | } l; | ||
56 | } u, res; | ||
57 | u64 rl, rh; | ||
58 | |||
59 | u.ll = a; | ||
60 | rl = (u64)u.l.low * (u64)b; | ||
61 | rh = (u64)u.l.high * (u64)b; | ||
62 | rh += (rl >> 32); | ||
63 | res.l.high = div64_64(rh, c); | ||
64 | res.l.low = div64_64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c); | ||
65 | return res.ll; | ||
66 | } | ||
67 | |||
68 | static void pit_set_gate(struct kvm *kvm, int channel, u32 val) | ||
69 | { | ||
70 | struct kvm_kpit_channel_state *c = | ||
71 | &kvm->arch.vpit->pit_state.channels[channel]; | ||
72 | |||
73 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
74 | |||
75 | switch (c->mode) { | ||
76 | default: | ||
77 | case 0: | ||
78 | case 4: | ||
79 | /* XXX: just disable/enable counting */ | ||
80 | break; | ||
81 | case 1: | ||
82 | case 2: | ||
83 | case 3: | ||
84 | case 5: | ||
85 | /* Restart counting on rising edge. */ | ||
86 | if (c->gate < val) | ||
87 | c->count_load_time = ktime_get(); | ||
88 | break; | ||
89 | } | ||
90 | |||
91 | c->gate = val; | ||
92 | } | ||
93 | |||
94 | int pit_get_gate(struct kvm *kvm, int channel) | ||
95 | { | ||
96 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
97 | |||
98 | return kvm->arch.vpit->pit_state.channels[channel].gate; | ||
99 | } | ||
100 | |||
101 | static int pit_get_count(struct kvm *kvm, int channel) | ||
102 | { | ||
103 | struct kvm_kpit_channel_state *c = | ||
104 | &kvm->arch.vpit->pit_state.channels[channel]; | ||
105 | s64 d, t; | ||
106 | int counter; | ||
107 | |||
108 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
109 | |||
110 | t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); | ||
111 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); | ||
112 | |||
113 | switch (c->mode) { | ||
114 | case 0: | ||
115 | case 1: | ||
116 | case 4: | ||
117 | case 5: | ||
118 | counter = (c->count - d) & 0xffff; | ||
119 | break; | ||
120 | case 3: | ||
121 | /* XXX: may be incorrect for odd counts */ | ||
122 | counter = c->count - (mod_64((2 * d), c->count)); | ||
123 | break; | ||
124 | default: | ||
125 | counter = c->count - mod_64(d, c->count); | ||
126 | break; | ||
127 | } | ||
128 | return counter; | ||
129 | } | ||
130 | |||
131 | static int pit_get_out(struct kvm *kvm, int channel) | ||
132 | { | ||
133 | struct kvm_kpit_channel_state *c = | ||
134 | &kvm->arch.vpit->pit_state.channels[channel]; | ||
135 | s64 d, t; | ||
136 | int out; | ||
137 | |||
138 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
139 | |||
140 | t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); | ||
141 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); | ||
142 | |||
143 | switch (c->mode) { | ||
144 | default: | ||
145 | case 0: | ||
146 | out = (d >= c->count); | ||
147 | break; | ||
148 | case 1: | ||
149 | out = (d < c->count); | ||
150 | break; | ||
151 | case 2: | ||
152 | out = ((mod_64(d, c->count) == 0) && (d != 0)); | ||
153 | break; | ||
154 | case 3: | ||
155 | out = (mod_64(d, c->count) < ((c->count + 1) >> 1)); | ||
156 | break; | ||
157 | case 4: | ||
158 | case 5: | ||
159 | out = (d == c->count); | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | return out; | ||
164 | } | ||
165 | |||
166 | static void pit_latch_count(struct kvm *kvm, int channel) | ||
167 | { | ||
168 | struct kvm_kpit_channel_state *c = | ||
169 | &kvm->arch.vpit->pit_state.channels[channel]; | ||
170 | |||
171 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
172 | |||
173 | if (!c->count_latched) { | ||
174 | c->latched_count = pit_get_count(kvm, channel); | ||
175 | c->count_latched = c->rw_mode; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static void pit_latch_status(struct kvm *kvm, int channel) | ||
180 | { | ||
181 | struct kvm_kpit_channel_state *c = | ||
182 | &kvm->arch.vpit->pit_state.channels[channel]; | ||
183 | |||
184 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | ||
185 | |||
186 | if (!c->status_latched) { | ||
187 | /* TODO: Return NULL COUNT (bit 6). */ | ||
188 | c->status = ((pit_get_out(kvm, channel) << 7) | | ||
189 | (c->rw_mode << 4) | | ||
190 | (c->mode << 1) | | ||
191 | c->bcd); | ||
192 | c->status_latched = 1; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | int __pit_timer_fn(struct kvm_kpit_state *ps) | ||
197 | { | ||
198 | struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0]; | ||
199 | struct kvm_kpit_timer *pt = &ps->pit_timer; | ||
200 | |||
201 | atomic_inc(&pt->pending); | ||
202 | smp_mb__after_atomic_inc(); | ||
203 | /* FIXME: handle case where the guest is in guest mode */ | ||
204 | if (vcpu0 && waitqueue_active(&vcpu0->wq)) { | ||
205 | vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
206 | wake_up_interruptible(&vcpu0->wq); | ||
207 | } | ||
208 | |||
209 | pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period); | ||
210 | pt->scheduled = ktime_to_ns(pt->timer.expires); | ||
211 | |||
212 | return (pt->period == 0 ? 0 : 1); | ||
213 | } | ||
214 | |||
215 | int pit_has_pending_timer(struct kvm_vcpu *vcpu) | ||
216 | { | ||
217 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; | ||
218 | |||
219 | if (pit && vcpu->vcpu_id == 0) | ||
220 | return atomic_read(&pit->pit_state.pit_timer.pending); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) | ||
226 | { | ||
227 | struct kvm_kpit_state *ps; | ||
228 | int restart_timer = 0; | ||
229 | |||
230 | ps = container_of(data, struct kvm_kpit_state, pit_timer.timer); | ||
231 | |||
232 | restart_timer = __pit_timer_fn(ps); | ||
233 | |||
234 | if (restart_timer) | ||
235 | return HRTIMER_RESTART; | ||
236 | else | ||
237 | return HRTIMER_NORESTART; | ||
238 | } | ||
239 | |||
240 | static void destroy_pit_timer(struct kvm_kpit_timer *pt) | ||
241 | { | ||
242 | pr_debug("pit: execute del timer!\n"); | ||
243 | hrtimer_cancel(&pt->timer); | ||
244 | } | ||
245 | |||
246 | static void create_pit_timer(struct kvm_kpit_timer *pt, u32 val, int is_period) | ||
247 | { | ||
248 | s64 interval; | ||
249 | |||
250 | interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); | ||
251 | |||
252 | pr_debug("pit: create pit timer, interval is %llu nsec\n", interval); | ||
253 | |||
254 | /* TODO The new value only affected after the retriggered */ | ||
255 | hrtimer_cancel(&pt->timer); | ||
256 | pt->period = (is_period == 0) ? 0 : interval; | ||
257 | pt->timer.function = pit_timer_fn; | ||
258 | atomic_set(&pt->pending, 0); | ||
259 | |||
260 | hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval), | ||
261 | HRTIMER_MODE_ABS); | ||
262 | } | ||
263 | |||
264 | static void pit_load_count(struct kvm *kvm, int channel, u32 val) | ||
265 | { | ||
266 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; | ||
267 | |||
268 | WARN_ON(!mutex_is_locked(&ps->lock)); | ||
269 | |||
270 | pr_debug("pit: load_count val is %d, channel is %d\n", val, channel); | ||
271 | |||
272 | /* | ||
273 | * Though spec said the state of 8254 is undefined after power-up, | ||
274 | * seems some tricky OS like Windows XP depends on IRQ0 interrupt | ||
275 | * when booting up. | ||
276 | * So here setting initialize rate for it, and not a specific number | ||
277 | */ | ||
278 | if (val == 0) | ||
279 | val = 0x10000; | ||
280 | |||
281 | ps->channels[channel].count_load_time = ktime_get(); | ||
282 | ps->channels[channel].count = val; | ||
283 | |||
284 | if (channel != 0) | ||
285 | return; | ||
286 | |||
287 | /* Two types of timer | ||
288 | * mode 1 is one shot, mode 2 is period, otherwise del timer */ | ||
289 | switch (ps->channels[0].mode) { | ||
290 | case 1: | ||
291 | create_pit_timer(&ps->pit_timer, val, 0); | ||
292 | break; | ||
293 | case 2: | ||
294 | create_pit_timer(&ps->pit_timer, val, 1); | ||
295 | break; | ||
296 | default: | ||
297 | destroy_pit_timer(&ps->pit_timer); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val) | ||
302 | { | ||
303 | mutex_lock(&kvm->arch.vpit->pit_state.lock); | ||
304 | pit_load_count(kvm, channel, val); | ||
305 | mutex_unlock(&kvm->arch.vpit->pit_state.lock); | ||
306 | } | ||
307 | |||
308 | static void pit_ioport_write(struct kvm_io_device *this, | ||
309 | gpa_t addr, int len, const void *data) | ||
310 | { | ||
311 | struct kvm_pit *pit = (struct kvm_pit *)this->private; | ||
312 | struct kvm_kpit_state *pit_state = &pit->pit_state; | ||
313 | struct kvm *kvm = pit->kvm; | ||
314 | int channel, access; | ||
315 | struct kvm_kpit_channel_state *s; | ||
316 | u32 val = *(u32 *) data; | ||
317 | |||
318 | val &= 0xff; | ||
319 | addr &= KVM_PIT_CHANNEL_MASK; | ||
320 | |||
321 | mutex_lock(&pit_state->lock); | ||
322 | |||
323 | if (val != 0) | ||
324 | pr_debug("pit: write addr is 0x%x, len is %d, val is 0x%x\n", | ||
325 | (unsigned int)addr, len, val); | ||
326 | |||
327 | if (addr == 3) { | ||
328 | channel = val >> 6; | ||
329 | if (channel == 3) { | ||
330 | /* Read-Back Command. */ | ||
331 | for (channel = 0; channel < 3; channel++) { | ||
332 | s = &pit_state->channels[channel]; | ||
333 | if (val & (2 << channel)) { | ||
334 | if (!(val & 0x20)) | ||
335 | pit_latch_count(kvm, channel); | ||
336 | if (!(val & 0x10)) | ||
337 | pit_latch_status(kvm, channel); | ||
338 | } | ||
339 | } | ||
340 | } else { | ||
341 | /* Select Counter <channel>. */ | ||
342 | s = &pit_state->channels[channel]; | ||
343 | access = (val >> 4) & KVM_PIT_CHANNEL_MASK; | ||
344 | if (access == 0) { | ||
345 | pit_latch_count(kvm, channel); | ||
346 | } else { | ||
347 | s->rw_mode = access; | ||
348 | s->read_state = access; | ||
349 | s->write_state = access; | ||
350 | s->mode = (val >> 1) & 7; | ||
351 | if (s->mode > 5) | ||
352 | s->mode -= 4; | ||
353 | s->bcd = val & 1; | ||
354 | } | ||
355 | } | ||
356 | } else { | ||
357 | /* Write Count. */ | ||
358 | s = &pit_state->channels[addr]; | ||
359 | switch (s->write_state) { | ||
360 | default: | ||
361 | case RW_STATE_LSB: | ||
362 | pit_load_count(kvm, addr, val); | ||
363 | break; | ||
364 | case RW_STATE_MSB: | ||
365 | pit_load_count(kvm, addr, val << 8); | ||
366 | break; | ||
367 | case RW_STATE_WORD0: | ||
368 | s->write_latch = val; | ||
369 | s->write_state = RW_STATE_WORD1; | ||
370 | break; | ||
371 | case RW_STATE_WORD1: | ||
372 | pit_load_count(kvm, addr, s->write_latch | (val << 8)); | ||
373 | s->write_state = RW_STATE_WORD0; | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | mutex_unlock(&pit_state->lock); | ||
379 | } | ||
380 | |||
381 | static void pit_ioport_read(struct kvm_io_device *this, | ||
382 | gpa_t addr, int len, void *data) | ||
383 | { | ||
384 | struct kvm_pit *pit = (struct kvm_pit *)this->private; | ||
385 | struct kvm_kpit_state *pit_state = &pit->pit_state; | ||
386 | struct kvm *kvm = pit->kvm; | ||
387 | int ret, count; | ||
388 | struct kvm_kpit_channel_state *s; | ||
389 | |||
390 | addr &= KVM_PIT_CHANNEL_MASK; | ||
391 | s = &pit_state->channels[addr]; | ||
392 | |||
393 | mutex_lock(&pit_state->lock); | ||
394 | |||
395 | if (s->status_latched) { | ||
396 | s->status_latched = 0; | ||
397 | ret = s->status; | ||
398 | } else if (s->count_latched) { | ||
399 | switch (s->count_latched) { | ||
400 | default: | ||
401 | case RW_STATE_LSB: | ||
402 | ret = s->latched_count & 0xff; | ||
403 | s->count_latched = 0; | ||
404 | break; | ||
405 | case RW_STATE_MSB: | ||
406 | ret = s->latched_count >> 8; | ||
407 | s->count_latched = 0; | ||
408 | break; | ||
409 | case RW_STATE_WORD0: | ||
410 | ret = s->latched_count & 0xff; | ||
411 | s->count_latched = RW_STATE_MSB; | ||
412 | break; | ||
413 | } | ||
414 | } else { | ||
415 | switch (s->read_state) { | ||
416 | default: | ||
417 | case RW_STATE_LSB: | ||
418 | count = pit_get_count(kvm, addr); | ||
419 | ret = count & 0xff; | ||
420 | break; | ||
421 | case RW_STATE_MSB: | ||
422 | count = pit_get_count(kvm, addr); | ||
423 | ret = (count >> 8) & 0xff; | ||
424 | break; | ||
425 | case RW_STATE_WORD0: | ||
426 | count = pit_get_count(kvm, addr); | ||
427 | ret = count & 0xff; | ||
428 | s->read_state = RW_STATE_WORD1; | ||
429 | break; | ||
430 | case RW_STATE_WORD1: | ||
431 | count = pit_get_count(kvm, addr); | ||
432 | ret = (count >> 8) & 0xff; | ||
433 | s->read_state = RW_STATE_WORD0; | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | if (len > sizeof(ret)) | ||
439 | len = sizeof(ret); | ||
440 | memcpy(data, (char *)&ret, len); | ||
441 | |||
442 | mutex_unlock(&pit_state->lock); | ||
443 | } | ||
444 | |||
445 | static int pit_in_range(struct kvm_io_device *this, gpa_t addr) | ||
446 | { | ||
447 | return ((addr >= KVM_PIT_BASE_ADDRESS) && | ||
448 | (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH)); | ||
449 | } | ||
450 | |||
451 | static void speaker_ioport_write(struct kvm_io_device *this, | ||
452 | gpa_t addr, int len, const void *data) | ||
453 | { | ||
454 | struct kvm_pit *pit = (struct kvm_pit *)this->private; | ||
455 | struct kvm_kpit_state *pit_state = &pit->pit_state; | ||
456 | struct kvm *kvm = pit->kvm; | ||
457 | u32 val = *(u32 *) data; | ||
458 | |||
459 | mutex_lock(&pit_state->lock); | ||
460 | pit_state->speaker_data_on = (val >> 1) & 1; | ||
461 | pit_set_gate(kvm, 2, val & 1); | ||
462 | mutex_unlock(&pit_state->lock); | ||
463 | } | ||
464 | |||
465 | static void speaker_ioport_read(struct kvm_io_device *this, | ||
466 | gpa_t addr, int len, void *data) | ||
467 | { | ||
468 | struct kvm_pit *pit = (struct kvm_pit *)this->private; | ||
469 | struct kvm_kpit_state *pit_state = &pit->pit_state; | ||
470 | struct kvm *kvm = pit->kvm; | ||
471 | unsigned int refresh_clock; | ||
472 | int ret; | ||
473 | |||
474 | /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */ | ||
475 | refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1; | ||
476 | |||
477 | mutex_lock(&pit_state->lock); | ||
478 | ret = ((pit_state->speaker_data_on << 1) | pit_get_gate(kvm, 2) | | ||
479 | (pit_get_out(kvm, 2) << 5) | (refresh_clock << 4)); | ||
480 | if (len > sizeof(ret)) | ||
481 | len = sizeof(ret); | ||
482 | memcpy(data, (char *)&ret, len); | ||
483 | mutex_unlock(&pit_state->lock); | ||
484 | } | ||
485 | |||
486 | static int speaker_in_range(struct kvm_io_device *this, gpa_t addr) | ||
487 | { | ||
488 | return (addr == KVM_SPEAKER_BASE_ADDRESS); | ||
489 | } | ||
490 | |||
491 | void kvm_pit_reset(struct kvm_pit *pit) | ||
492 | { | ||
493 | int i; | ||
494 | struct kvm_kpit_channel_state *c; | ||
495 | |||
496 | mutex_lock(&pit->pit_state.lock); | ||
497 | for (i = 0; i < 3; i++) { | ||
498 | c = &pit->pit_state.channels[i]; | ||
499 | c->mode = 0xff; | ||
500 | c->gate = (i != 2); | ||
501 | pit_load_count(pit->kvm, i, 0); | ||
502 | } | ||
503 | mutex_unlock(&pit->pit_state.lock); | ||
504 | |||
505 | atomic_set(&pit->pit_state.pit_timer.pending, 0); | ||
506 | pit->pit_state.inject_pending = 1; | ||
507 | } | ||
508 | |||
509 | struct kvm_pit *kvm_create_pit(struct kvm *kvm) | ||
510 | { | ||
511 | struct kvm_pit *pit; | ||
512 | struct kvm_kpit_state *pit_state; | ||
513 | |||
514 | pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL); | ||
515 | if (!pit) | ||
516 | return NULL; | ||
517 | |||
518 | mutex_init(&pit->pit_state.lock); | ||
519 | mutex_lock(&pit->pit_state.lock); | ||
520 | |||
521 | /* Initialize PIO device */ | ||
522 | pit->dev.read = pit_ioport_read; | ||
523 | pit->dev.write = pit_ioport_write; | ||
524 | pit->dev.in_range = pit_in_range; | ||
525 | pit->dev.private = pit; | ||
526 | kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev); | ||
527 | |||
528 | pit->speaker_dev.read = speaker_ioport_read; | ||
529 | pit->speaker_dev.write = speaker_ioport_write; | ||
530 | pit->speaker_dev.in_range = speaker_in_range; | ||
531 | pit->speaker_dev.private = pit; | ||
532 | kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev); | ||
533 | |||
534 | kvm->arch.vpit = pit; | ||
535 | pit->kvm = kvm; | ||
536 | |||
537 | pit_state = &pit->pit_state; | ||
538 | pit_state->pit = pit; | ||
539 | hrtimer_init(&pit_state->pit_timer.timer, | ||
540 | CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
541 | mutex_unlock(&pit->pit_state.lock); | ||
542 | |||
543 | kvm_pit_reset(pit); | ||
544 | |||
545 | return pit; | ||
546 | } | ||
547 | |||
548 | void kvm_free_pit(struct kvm *kvm) | ||
549 | { | ||
550 | struct hrtimer *timer; | ||
551 | |||
552 | if (kvm->arch.vpit) { | ||
553 | mutex_lock(&kvm->arch.vpit->pit_state.lock); | ||
554 | timer = &kvm->arch.vpit->pit_state.pit_timer.timer; | ||
555 | hrtimer_cancel(timer); | ||
556 | mutex_unlock(&kvm->arch.vpit->pit_state.lock); | ||
557 | kfree(kvm->arch.vpit); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | void __inject_pit_timer_intr(struct kvm *kvm) | ||
562 | { | ||
563 | mutex_lock(&kvm->lock); | ||
564 | kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1); | ||
565 | kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0); | ||
566 | kvm_pic_set_irq(pic_irqchip(kvm), 0, 1); | ||
567 | kvm_pic_set_irq(pic_irqchip(kvm), 0, 0); | ||
568 | mutex_unlock(&kvm->lock); | ||
569 | } | ||
570 | |||
571 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) | ||
572 | { | ||
573 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; | ||
574 | struct kvm *kvm = vcpu->kvm; | ||
575 | struct kvm_kpit_state *ps; | ||
576 | |||
577 | if (vcpu && pit) { | ||
578 | ps = &pit->pit_state; | ||
579 | |||
580 | /* Try to inject pending interrupts when: | ||
581 | * 1. Pending exists | ||
582 | * 2. Last interrupt was accepted or waited for too long time*/ | ||
583 | if (atomic_read(&ps->pit_timer.pending) && | ||
584 | (ps->inject_pending || | ||
585 | (jiffies - ps->last_injected_time | ||
586 | >= KVM_MAX_PIT_INTR_INTERVAL))) { | ||
587 | ps->inject_pending = 0; | ||
588 | __inject_pit_timer_intr(kvm); | ||
589 | ps->last_injected_time = jiffies; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | void kvm_pit_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | ||
595 | { | ||
596 | struct kvm_arch *arch = &vcpu->kvm->arch; | ||
597 | struct kvm_kpit_state *ps; | ||
598 | |||
599 | if (vcpu && arch->vpit) { | ||
600 | ps = &arch->vpit->pit_state; | ||
601 | if (atomic_read(&ps->pit_timer.pending) && | ||
602 | (((arch->vpic->pics[0].imr & 1) == 0 && | ||
603 | arch->vpic->pics[0].irq_base == vec) || | ||
604 | (arch->vioapic->redirtbl[0].fields.vector == vec && | ||
605 | arch->vioapic->redirtbl[0].fields.mask != 1))) { | ||
606 | ps->inject_pending = 1; | ||
607 | atomic_dec(&ps->pit_timer.pending); | ||
608 | ps->channels[0].count_load_time = ktime_get(); | ||
609 | } | ||
610 | } | ||
611 | } | ||
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h new file mode 100644 index 000000000000..db25c2a6c8c4 --- /dev/null +++ b/arch/x86/kvm/i8254.h | |||
@@ -0,0 +1,63 @@ | |||
1 | #ifndef __I8254_H | ||
2 | #define __I8254_H | ||
3 | |||
4 | #include "iodev.h" | ||
5 | |||
6 | struct kvm_kpit_timer { | ||
7 | struct hrtimer timer; | ||
8 | int irq; | ||
9 | s64 period; /* unit: ns */ | ||
10 | s64 scheduled; | ||
11 | ktime_t last_update; | ||
12 | atomic_t pending; | ||
13 | }; | ||
14 | |||
15 | struct kvm_kpit_channel_state { | ||
16 | u32 count; /* can be 65536 */ | ||
17 | u16 latched_count; | ||
18 | u8 count_latched; | ||
19 | u8 status_latched; | ||
20 | u8 status; | ||
21 | u8 read_state; | ||
22 | u8 write_state; | ||
23 | u8 write_latch; | ||
24 | u8 rw_mode; | ||
25 | u8 mode; | ||
26 | u8 bcd; /* not supported */ | ||
27 | u8 gate; /* timer start */ | ||
28 | ktime_t count_load_time; | ||
29 | }; | ||
30 | |||
31 | struct kvm_kpit_state { | ||
32 | struct kvm_kpit_channel_state channels[3]; | ||
33 | struct kvm_kpit_timer pit_timer; | ||
34 | u32 speaker_data_on; | ||
35 | struct mutex lock; | ||
36 | struct kvm_pit *pit; | ||
37 | bool inject_pending; /* if inject pending interrupts */ | ||
38 | unsigned long last_injected_time; | ||
39 | }; | ||
40 | |||
41 | struct kvm_pit { | ||
42 | unsigned long base_addresss; | ||
43 | struct kvm_io_device dev; | ||
44 | struct kvm_io_device speaker_dev; | ||
45 | struct kvm *kvm; | ||
46 | struct kvm_kpit_state pit_state; | ||
47 | }; | ||
48 | |||
49 | #define KVM_PIT_BASE_ADDRESS 0x40 | ||
50 | #define KVM_SPEAKER_BASE_ADDRESS 0x61 | ||
51 | #define KVM_PIT_MEM_LENGTH 4 | ||
52 | #define KVM_PIT_FREQ 1193181 | ||
53 | #define KVM_MAX_PIT_INTR_INTERVAL HZ / 100 | ||
54 | #define KVM_PIT_CHANNEL_MASK 0x3 | ||
55 | |||
56 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu); | ||
57 | void kvm_pit_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | ||
58 | void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val); | ||
59 | struct kvm_pit *kvm_create_pit(struct kvm *kvm); | ||
60 | void kvm_free_pit(struct kvm *kvm); | ||
61 | void kvm_pit_reset(struct kvm_pit *pit); | ||
62 | |||
63 | #endif | ||
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index e5714759e97f..ce1f583459b1 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c | |||
@@ -23,6 +23,22 @@ | |||
23 | #include <linux/kvm_host.h> | 23 | #include <linux/kvm_host.h> |
24 | 24 | ||
25 | #include "irq.h" | 25 | #include "irq.h" |
26 | #include "i8254.h" | ||
27 | |||
28 | /* | ||
29 | * check if there are pending timer events | ||
30 | * to be processed. | ||
31 | */ | ||
32 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | ret = pit_has_pending_timer(vcpu); | ||
37 | ret |= apic_has_pending_timer(vcpu); | ||
38 | |||
39 | return ret; | ||
40 | } | ||
41 | EXPORT_SYMBOL(kvm_cpu_has_pending_timer); | ||
26 | 42 | ||
27 | /* | 43 | /* |
28 | * check if there is pending interrupt without | 44 | * check if there is pending interrupt without |
@@ -66,6 +82,7 @@ EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); | |||
66 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) | 82 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) |
67 | { | 83 | { |
68 | kvm_inject_apic_timer_irqs(vcpu); | 84 | kvm_inject_apic_timer_irqs(vcpu); |
85 | kvm_inject_pit_timer_irqs(vcpu); | ||
69 | /* TODO: PIT, RTC etc. */ | 86 | /* TODO: PIT, RTC etc. */ |
70 | } | 87 | } |
71 | EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); | 88 | EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); |
@@ -73,6 +90,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); | |||
73 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | 90 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) |
74 | { | 91 | { |
75 | kvm_apic_timer_intr_post(vcpu, vec); | 92 | kvm_apic_timer_intr_post(vcpu, vec); |
93 | kvm_pit_timer_intr_post(vcpu, vec); | ||
76 | /* TODO: PIT, RTC etc. */ | 94 | /* TODO: PIT, RTC etc. */ |
77 | } | 95 | } |
78 | EXPORT_SYMBOL_GPL(kvm_timer_intr_post); | 96 | EXPORT_SYMBOL_GPL(kvm_timer_intr_post); |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index fa5ed5d59b5d..1802134b836f 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
@@ -85,4 +85,7 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); | |||
85 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); | 85 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); |
86 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); | 86 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); |
87 | 87 | ||
88 | int pit_has_pending_timer(struct kvm_vcpu *vcpu); | ||
89 | int apic_has_pending_timer(struct kvm_vcpu *vcpu); | ||
90 | |||
88 | #endif | 91 | #endif |
diff --git a/arch/x86/kvm/kvm_svm.h b/arch/x86/kvm/kvm_svm.h index ecdfe97e4635..65ef0fc2c036 100644 --- a/arch/x86/kvm/kvm_svm.h +++ b/arch/x86/kvm/kvm_svm.h | |||
@@ -39,6 +39,8 @@ struct vcpu_svm { | |||
39 | unsigned long host_db_regs[NUM_DB_REGS]; | 39 | unsigned long host_db_regs[NUM_DB_REGS]; |
40 | unsigned long host_dr6; | 40 | unsigned long host_dr6; |
41 | unsigned long host_dr7; | 41 | unsigned long host_dr7; |
42 | |||
43 | u32 *msrpm; | ||
42 | }; | 44 | }; |
43 | 45 | ||
44 | #endif | 46 | #endif |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 68a6b1511934..57ac4e4c556a 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -338,10 +338,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
338 | } else | 338 | } else |
339 | apic_clear_vector(vector, apic->regs + APIC_TMR); | 339 | apic_clear_vector(vector, apic->regs + APIC_TMR); |
340 | 340 | ||
341 | if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE) | 341 | if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) |
342 | kvm_vcpu_kick(vcpu); | 342 | kvm_vcpu_kick(vcpu); |
343 | else if (vcpu->arch.mp_state == VCPU_MP_STATE_HALTED) { | 343 | else if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED) { |
344 | vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; | 344 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; |
345 | if (waitqueue_active(&vcpu->wq)) | 345 | if (waitqueue_active(&vcpu->wq)) |
346 | wake_up_interruptible(&vcpu->wq); | 346 | wake_up_interruptible(&vcpu->wq); |
347 | } | 347 | } |
@@ -362,11 +362,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
362 | 362 | ||
363 | case APIC_DM_INIT: | 363 | case APIC_DM_INIT: |
364 | if (level) { | 364 | if (level) { |
365 | if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE) | 365 | if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) |
366 | printk(KERN_DEBUG | 366 | printk(KERN_DEBUG |
367 | "INIT on a runnable vcpu %d\n", | 367 | "INIT on a runnable vcpu %d\n", |
368 | vcpu->vcpu_id); | 368 | vcpu->vcpu_id); |
369 | vcpu->arch.mp_state = VCPU_MP_STATE_INIT_RECEIVED; | 369 | vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; |
370 | kvm_vcpu_kick(vcpu); | 370 | kvm_vcpu_kick(vcpu); |
371 | } else { | 371 | } else { |
372 | printk(KERN_DEBUG | 372 | printk(KERN_DEBUG |
@@ -379,9 +379,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
379 | case APIC_DM_STARTUP: | 379 | case APIC_DM_STARTUP: |
380 | printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", | 380 | printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", |
381 | vcpu->vcpu_id, vector); | 381 | vcpu->vcpu_id, vector); |
382 | if (vcpu->arch.mp_state == VCPU_MP_STATE_INIT_RECEIVED) { | 382 | if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { |
383 | vcpu->arch.sipi_vector = vector; | 383 | vcpu->arch.sipi_vector = vector; |
384 | vcpu->arch.mp_state = VCPU_MP_STATE_SIPI_RECEIVED; | 384 | vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; |
385 | if (waitqueue_active(&vcpu->wq)) | 385 | if (waitqueue_active(&vcpu->wq)) |
386 | wake_up_interruptible(&vcpu->wq); | 386 | wake_up_interruptible(&vcpu->wq); |
387 | } | 387 | } |
@@ -658,7 +658,7 @@ static void start_apic_timer(struct kvm_lapic *apic) | |||
658 | apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" | 658 | apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" |
659 | PRIx64 ", " | 659 | PRIx64 ", " |
660 | "timer initial count 0x%x, period %lldns, " | 660 | "timer initial count 0x%x, period %lldns, " |
661 | "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, | 661 | "expire @ 0x%016" PRIx64 ".\n", __func__, |
662 | APIC_BUS_CYCLE_NS, ktime_to_ns(now), | 662 | APIC_BUS_CYCLE_NS, ktime_to_ns(now), |
663 | apic_get_reg(apic, APIC_TMICT), | 663 | apic_get_reg(apic, APIC_TMICT), |
664 | apic->timer.period, | 664 | apic->timer.period, |
@@ -691,7 +691,7 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
691 | /* too common printing */ | 691 | /* too common printing */ |
692 | if (offset != APIC_EOI) | 692 | if (offset != APIC_EOI) |
693 | apic_debug("%s: offset 0x%x with length 0x%x, and value is " | 693 | apic_debug("%s: offset 0x%x with length 0x%x, and value is " |
694 | "0x%x\n", __FUNCTION__, offset, len, val); | 694 | "0x%x\n", __func__, offset, len, val); |
695 | 695 | ||
696 | offset &= 0xff0; | 696 | offset &= 0xff0; |
697 | 697 | ||
@@ -822,6 +822,7 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
822 | apic_set_tpr(apic, ((cr8 & 0x0f) << 4) | 822 | apic_set_tpr(apic, ((cr8 & 0x0f) << 4) |
823 | | (apic_get_reg(apic, APIC_TASKPRI) & 4)); | 823 | | (apic_get_reg(apic, APIC_TASKPRI) & 4)); |
824 | } | 824 | } |
825 | EXPORT_SYMBOL_GPL(kvm_lapic_set_tpr); | ||
825 | 826 | ||
826 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) | 827 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) |
827 | { | 828 | { |
@@ -869,7 +870,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
869 | struct kvm_lapic *apic; | 870 | struct kvm_lapic *apic; |
870 | int i; | 871 | int i; |
871 | 872 | ||
872 | apic_debug("%s\n", __FUNCTION__); | 873 | apic_debug("%s\n", __func__); |
873 | 874 | ||
874 | ASSERT(vcpu); | 875 | ASSERT(vcpu); |
875 | apic = vcpu->arch.apic; | 876 | apic = vcpu->arch.apic; |
@@ -907,7 +908,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
907 | apic_update_ppr(apic); | 908 | apic_update_ppr(apic); |
908 | 909 | ||
909 | apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" | 910 | apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" |
910 | "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, | 911 | "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__, |
911 | vcpu, kvm_apic_id(apic), | 912 | vcpu, kvm_apic_id(apic), |
912 | vcpu->arch.apic_base, apic->base_address); | 913 | vcpu->arch.apic_base, apic->base_address); |
913 | } | 914 | } |
@@ -940,7 +941,7 @@ static int __apic_timer_fn(struct kvm_lapic *apic) | |||
940 | 941 | ||
941 | atomic_inc(&apic->timer.pending); | 942 | atomic_inc(&apic->timer.pending); |
942 | if (waitqueue_active(q)) { | 943 | if (waitqueue_active(q)) { |
943 | apic->vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; | 944 | apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; |
944 | wake_up_interruptible(q); | 945 | wake_up_interruptible(q); |
945 | } | 946 | } |
946 | if (apic_lvtt_period(apic)) { | 947 | if (apic_lvtt_period(apic)) { |
@@ -952,6 +953,16 @@ static int __apic_timer_fn(struct kvm_lapic *apic) | |||
952 | return result; | 953 | return result; |
953 | } | 954 | } |
954 | 955 | ||
956 | int apic_has_pending_timer(struct kvm_vcpu *vcpu) | ||
957 | { | ||
958 | struct kvm_lapic *lapic = vcpu->arch.apic; | ||
959 | |||
960 | if (lapic) | ||
961 | return atomic_read(&lapic->timer.pending); | ||
962 | |||
963 | return 0; | ||
964 | } | ||
965 | |||
955 | static int __inject_apic_timer_irq(struct kvm_lapic *apic) | 966 | static int __inject_apic_timer_irq(struct kvm_lapic *apic) |
956 | { | 967 | { |
957 | int vector; | 968 | int vector; |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index e55af12e11b7..2ad6f5481671 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -27,11 +27,22 @@ | |||
27 | #include <linux/highmem.h> | 27 | #include <linux/highmem.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/swap.h> | 29 | #include <linux/swap.h> |
30 | #include <linux/hugetlb.h> | ||
31 | #include <linux/compiler.h> | ||
30 | 32 | ||
31 | #include <asm/page.h> | 33 | #include <asm/page.h> |
32 | #include <asm/cmpxchg.h> | 34 | #include <asm/cmpxchg.h> |
33 | #include <asm/io.h> | 35 | #include <asm/io.h> |
34 | 36 | ||
37 | /* | ||
38 | * When setting this variable to true it enables Two-Dimensional-Paging | ||
39 | * where the hardware walks 2 page tables: | ||
40 | * 1. the guest-virtual to guest-physical | ||
41 | * 2. while doing 1. it walks guest-physical to host-physical | ||
42 | * If the hardware supports that we don't need to do shadow paging. | ||
43 | */ | ||
44 | bool tdp_enabled = false; | ||
45 | |||
35 | #undef MMU_DEBUG | 46 | #undef MMU_DEBUG |
36 | 47 | ||
37 | #undef AUDIT | 48 | #undef AUDIT |
@@ -101,8 +112,6 @@ static int dbg = 1; | |||
101 | #define PT_FIRST_AVAIL_BITS_SHIFT 9 | 112 | #define PT_FIRST_AVAIL_BITS_SHIFT 9 |
102 | #define PT64_SECOND_AVAIL_BITS_SHIFT 52 | 113 | #define PT64_SECOND_AVAIL_BITS_SHIFT 52 |
103 | 114 | ||
104 | #define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) | ||
105 | |||
106 | #define VALID_PAGE(x) ((x) != INVALID_PAGE) | 115 | #define VALID_PAGE(x) ((x) != INVALID_PAGE) |
107 | 116 | ||
108 | #define PT64_LEVEL_BITS 9 | 117 | #define PT64_LEVEL_BITS 9 |
@@ -159,6 +168,13 @@ static int dbg = 1; | |||
159 | #define ACC_USER_MASK PT_USER_MASK | 168 | #define ACC_USER_MASK PT_USER_MASK |
160 | #define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) | 169 | #define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) |
161 | 170 | ||
171 | struct kvm_pv_mmu_op_buffer { | ||
172 | void *ptr; | ||
173 | unsigned len; | ||
174 | unsigned processed; | ||
175 | char buf[512] __aligned(sizeof(long)); | ||
176 | }; | ||
177 | |||
162 | struct kvm_rmap_desc { | 178 | struct kvm_rmap_desc { |
163 | u64 *shadow_ptes[RMAP_EXT]; | 179 | u64 *shadow_ptes[RMAP_EXT]; |
164 | struct kvm_rmap_desc *more; | 180 | struct kvm_rmap_desc *more; |
@@ -200,11 +216,15 @@ static int is_present_pte(unsigned long pte) | |||
200 | 216 | ||
201 | static int is_shadow_present_pte(u64 pte) | 217 | static int is_shadow_present_pte(u64 pte) |
202 | { | 218 | { |
203 | pte &= ~PT_SHADOW_IO_MARK; | ||
204 | return pte != shadow_trap_nonpresent_pte | 219 | return pte != shadow_trap_nonpresent_pte |
205 | && pte != shadow_notrap_nonpresent_pte; | 220 | && pte != shadow_notrap_nonpresent_pte; |
206 | } | 221 | } |
207 | 222 | ||
223 | static int is_large_pte(u64 pte) | ||
224 | { | ||
225 | return pte & PT_PAGE_SIZE_MASK; | ||
226 | } | ||
227 | |||
208 | static int is_writeble_pte(unsigned long pte) | 228 | static int is_writeble_pte(unsigned long pte) |
209 | { | 229 | { |
210 | return pte & PT_WRITABLE_MASK; | 230 | return pte & PT_WRITABLE_MASK; |
@@ -215,14 +235,14 @@ static int is_dirty_pte(unsigned long pte) | |||
215 | return pte & PT_DIRTY_MASK; | 235 | return pte & PT_DIRTY_MASK; |
216 | } | 236 | } |
217 | 237 | ||
218 | static int is_io_pte(unsigned long pte) | 238 | static int is_rmap_pte(u64 pte) |
219 | { | 239 | { |
220 | return pte & PT_SHADOW_IO_MARK; | 240 | return is_shadow_present_pte(pte); |
221 | } | 241 | } |
222 | 242 | ||
223 | static int is_rmap_pte(u64 pte) | 243 | static pfn_t spte_to_pfn(u64 pte) |
224 | { | 244 | { |
225 | return is_shadow_present_pte(pte); | 245 | return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; |
226 | } | 246 | } |
227 | 247 | ||
228 | static gfn_t pse36_gfn_delta(u32 gpte) | 248 | static gfn_t pse36_gfn_delta(u32 gpte) |
@@ -349,16 +369,100 @@ static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd) | |||
349 | } | 369 | } |
350 | 370 | ||
351 | /* | 371 | /* |
372 | * Return the pointer to the largepage write count for a given | ||
373 | * gfn, handling slots that are not large page aligned. | ||
374 | */ | ||
375 | static int *slot_largepage_idx(gfn_t gfn, struct kvm_memory_slot *slot) | ||
376 | { | ||
377 | unsigned long idx; | ||
378 | |||
379 | idx = (gfn / KVM_PAGES_PER_HPAGE) - | ||
380 | (slot->base_gfn / KVM_PAGES_PER_HPAGE); | ||
381 | return &slot->lpage_info[idx].write_count; | ||
382 | } | ||
383 | |||
384 | static void account_shadowed(struct kvm *kvm, gfn_t gfn) | ||
385 | { | ||
386 | int *write_count; | ||
387 | |||
388 | write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn)); | ||
389 | *write_count += 1; | ||
390 | WARN_ON(*write_count > KVM_PAGES_PER_HPAGE); | ||
391 | } | ||
392 | |||
393 | static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) | ||
394 | { | ||
395 | int *write_count; | ||
396 | |||
397 | write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn)); | ||
398 | *write_count -= 1; | ||
399 | WARN_ON(*write_count < 0); | ||
400 | } | ||
401 | |||
402 | static int has_wrprotected_page(struct kvm *kvm, gfn_t gfn) | ||
403 | { | ||
404 | struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); | ||
405 | int *largepage_idx; | ||
406 | |||
407 | if (slot) { | ||
408 | largepage_idx = slot_largepage_idx(gfn, slot); | ||
409 | return *largepage_idx; | ||
410 | } | ||
411 | |||
412 | return 1; | ||
413 | } | ||
414 | |||
415 | static int host_largepage_backed(struct kvm *kvm, gfn_t gfn) | ||
416 | { | ||
417 | struct vm_area_struct *vma; | ||
418 | unsigned long addr; | ||
419 | |||
420 | addr = gfn_to_hva(kvm, gfn); | ||
421 | if (kvm_is_error_hva(addr)) | ||
422 | return 0; | ||
423 | |||
424 | vma = find_vma(current->mm, addr); | ||
425 | if (vma && is_vm_hugetlb_page(vma)) | ||
426 | return 1; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn) | ||
432 | { | ||
433 | struct kvm_memory_slot *slot; | ||
434 | |||
435 | if (has_wrprotected_page(vcpu->kvm, large_gfn)) | ||
436 | return 0; | ||
437 | |||
438 | if (!host_largepage_backed(vcpu->kvm, large_gfn)) | ||
439 | return 0; | ||
440 | |||
441 | slot = gfn_to_memslot(vcpu->kvm, large_gfn); | ||
442 | if (slot && slot->dirty_bitmap) | ||
443 | return 0; | ||
444 | |||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | /* | ||
352 | * Take gfn and return the reverse mapping to it. | 449 | * Take gfn and return the reverse mapping to it. |
353 | * Note: gfn must be unaliased before this function get called | 450 | * Note: gfn must be unaliased before this function get called |
354 | */ | 451 | */ |
355 | 452 | ||
356 | static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn) | 453 | static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage) |
357 | { | 454 | { |
358 | struct kvm_memory_slot *slot; | 455 | struct kvm_memory_slot *slot; |
456 | unsigned long idx; | ||
359 | 457 | ||
360 | slot = gfn_to_memslot(kvm, gfn); | 458 | slot = gfn_to_memslot(kvm, gfn); |
361 | return &slot->rmap[gfn - slot->base_gfn]; | 459 | if (!lpage) |
460 | return &slot->rmap[gfn - slot->base_gfn]; | ||
461 | |||
462 | idx = (gfn / KVM_PAGES_PER_HPAGE) - | ||
463 | (slot->base_gfn / KVM_PAGES_PER_HPAGE); | ||
464 | |||
465 | return &slot->lpage_info[idx].rmap_pde; | ||
362 | } | 466 | } |
363 | 467 | ||
364 | /* | 468 | /* |
@@ -370,7 +474,7 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn) | |||
370 | * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc | 474 | * If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc |
371 | * containing more mappings. | 475 | * containing more mappings. |
372 | */ | 476 | */ |
373 | static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | 477 | static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage) |
374 | { | 478 | { |
375 | struct kvm_mmu_page *sp; | 479 | struct kvm_mmu_page *sp; |
376 | struct kvm_rmap_desc *desc; | 480 | struct kvm_rmap_desc *desc; |
@@ -382,7 +486,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | |||
382 | gfn = unalias_gfn(vcpu->kvm, gfn); | 486 | gfn = unalias_gfn(vcpu->kvm, gfn); |
383 | sp = page_header(__pa(spte)); | 487 | sp = page_header(__pa(spte)); |
384 | sp->gfns[spte - sp->spt] = gfn; | 488 | sp->gfns[spte - sp->spt] = gfn; |
385 | rmapp = gfn_to_rmap(vcpu->kvm, gfn); | 489 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, lpage); |
386 | if (!*rmapp) { | 490 | if (!*rmapp) { |
387 | rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); | 491 | rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); |
388 | *rmapp = (unsigned long)spte; | 492 | *rmapp = (unsigned long)spte; |
@@ -435,20 +539,21 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | |||
435 | struct kvm_rmap_desc *desc; | 539 | struct kvm_rmap_desc *desc; |
436 | struct kvm_rmap_desc *prev_desc; | 540 | struct kvm_rmap_desc *prev_desc; |
437 | struct kvm_mmu_page *sp; | 541 | struct kvm_mmu_page *sp; |
438 | struct page *page; | 542 | pfn_t pfn; |
439 | unsigned long *rmapp; | 543 | unsigned long *rmapp; |
440 | int i; | 544 | int i; |
441 | 545 | ||
442 | if (!is_rmap_pte(*spte)) | 546 | if (!is_rmap_pte(*spte)) |
443 | return; | 547 | return; |
444 | sp = page_header(__pa(spte)); | 548 | sp = page_header(__pa(spte)); |
445 | page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); | 549 | pfn = spte_to_pfn(*spte); |
446 | mark_page_accessed(page); | 550 | if (*spte & PT_ACCESSED_MASK) |
551 | kvm_set_pfn_accessed(pfn); | ||
447 | if (is_writeble_pte(*spte)) | 552 | if (is_writeble_pte(*spte)) |
448 | kvm_release_page_dirty(page); | 553 | kvm_release_pfn_dirty(pfn); |
449 | else | 554 | else |
450 | kvm_release_page_clean(page); | 555 | kvm_release_pfn_clean(pfn); |
451 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt]); | 556 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], is_large_pte(*spte)); |
452 | if (!*rmapp) { | 557 | if (!*rmapp) { |
453 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); | 558 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); |
454 | BUG(); | 559 | BUG(); |
@@ -514,7 +619,7 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
514 | int write_protected = 0; | 619 | int write_protected = 0; |
515 | 620 | ||
516 | gfn = unalias_gfn(kvm, gfn); | 621 | gfn = unalias_gfn(kvm, gfn); |
517 | rmapp = gfn_to_rmap(kvm, gfn); | 622 | rmapp = gfn_to_rmap(kvm, gfn, 0); |
518 | 623 | ||
519 | spte = rmap_next(kvm, rmapp, NULL); | 624 | spte = rmap_next(kvm, rmapp, NULL); |
520 | while (spte) { | 625 | while (spte) { |
@@ -527,8 +632,35 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
527 | } | 632 | } |
528 | spte = rmap_next(kvm, rmapp, spte); | 633 | spte = rmap_next(kvm, rmapp, spte); |
529 | } | 634 | } |
635 | if (write_protected) { | ||
636 | pfn_t pfn; | ||
637 | |||
638 | spte = rmap_next(kvm, rmapp, NULL); | ||
639 | pfn = spte_to_pfn(*spte); | ||
640 | kvm_set_pfn_dirty(pfn); | ||
641 | } | ||
642 | |||
643 | /* check for huge page mappings */ | ||
644 | rmapp = gfn_to_rmap(kvm, gfn, 1); | ||
645 | spte = rmap_next(kvm, rmapp, NULL); | ||
646 | while (spte) { | ||
647 | BUG_ON(!spte); | ||
648 | BUG_ON(!(*spte & PT_PRESENT_MASK)); | ||
649 | BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)); | ||
650 | pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn); | ||
651 | if (is_writeble_pte(*spte)) { | ||
652 | rmap_remove(kvm, spte); | ||
653 | --kvm->stat.lpages; | ||
654 | set_shadow_pte(spte, shadow_trap_nonpresent_pte); | ||
655 | write_protected = 1; | ||
656 | } | ||
657 | spte = rmap_next(kvm, rmapp, spte); | ||
658 | } | ||
659 | |||
530 | if (write_protected) | 660 | if (write_protected) |
531 | kvm_flush_remote_tlbs(kvm); | 661 | kvm_flush_remote_tlbs(kvm); |
662 | |||
663 | account_shadowed(kvm, gfn); | ||
532 | } | 664 | } |
533 | 665 | ||
534 | #ifdef MMU_DEBUG | 666 | #ifdef MMU_DEBUG |
@@ -538,8 +670,8 @@ static int is_empty_shadow_page(u64 *spt) | |||
538 | u64 *end; | 670 | u64 *end; |
539 | 671 | ||
540 | for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++) | 672 | for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++) |
541 | if ((*pos & ~PT_SHADOW_IO_MARK) != shadow_trap_nonpresent_pte) { | 673 | if (*pos != shadow_trap_nonpresent_pte) { |
542 | printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__, | 674 | printk(KERN_ERR "%s: %p %llx\n", __func__, |
543 | pos, *pos); | 675 | pos, *pos); |
544 | return 0; | 676 | return 0; |
545 | } | 677 | } |
@@ -559,7 +691,7 @@ static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp) | |||
559 | 691 | ||
560 | static unsigned kvm_page_table_hashfn(gfn_t gfn) | 692 | static unsigned kvm_page_table_hashfn(gfn_t gfn) |
561 | { | 693 | { |
562 | return gfn; | 694 | return gfn & ((1 << KVM_MMU_HASH_SHIFT) - 1); |
563 | } | 695 | } |
564 | 696 | ||
565 | static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, | 697 | static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, |
@@ -662,13 +794,14 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) | |||
662 | struct kvm_mmu_page *sp; | 794 | struct kvm_mmu_page *sp; |
663 | struct hlist_node *node; | 795 | struct hlist_node *node; |
664 | 796 | ||
665 | pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); | 797 | pgprintk("%s: looking for gfn %lx\n", __func__, gfn); |
666 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 798 | index = kvm_page_table_hashfn(gfn); |
667 | bucket = &kvm->arch.mmu_page_hash[index]; | 799 | bucket = &kvm->arch.mmu_page_hash[index]; |
668 | hlist_for_each_entry(sp, node, bucket, hash_link) | 800 | hlist_for_each_entry(sp, node, bucket, hash_link) |
669 | if (sp->gfn == gfn && !sp->role.metaphysical) { | 801 | if (sp->gfn == gfn && !sp->role.metaphysical |
802 | && !sp->role.invalid) { | ||
670 | pgprintk("%s: found role %x\n", | 803 | pgprintk("%s: found role %x\n", |
671 | __FUNCTION__, sp->role.word); | 804 | __func__, sp->role.word); |
672 | return sp; | 805 | return sp; |
673 | } | 806 | } |
674 | return NULL; | 807 | return NULL; |
@@ -699,27 +832,27 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | |||
699 | quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; | 832 | quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; |
700 | role.quadrant = quadrant; | 833 | role.quadrant = quadrant; |
701 | } | 834 | } |
702 | pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__, | 835 | pgprintk("%s: looking gfn %lx role %x\n", __func__, |
703 | gfn, role.word); | 836 | gfn, role.word); |
704 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 837 | index = kvm_page_table_hashfn(gfn); |
705 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; | 838 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; |
706 | hlist_for_each_entry(sp, node, bucket, hash_link) | 839 | hlist_for_each_entry(sp, node, bucket, hash_link) |
707 | if (sp->gfn == gfn && sp->role.word == role.word) { | 840 | if (sp->gfn == gfn && sp->role.word == role.word) { |
708 | mmu_page_add_parent_pte(vcpu, sp, parent_pte); | 841 | mmu_page_add_parent_pte(vcpu, sp, parent_pte); |
709 | pgprintk("%s: found\n", __FUNCTION__); | 842 | pgprintk("%s: found\n", __func__); |
710 | return sp; | 843 | return sp; |
711 | } | 844 | } |
712 | ++vcpu->kvm->stat.mmu_cache_miss; | 845 | ++vcpu->kvm->stat.mmu_cache_miss; |
713 | sp = kvm_mmu_alloc_page(vcpu, parent_pte); | 846 | sp = kvm_mmu_alloc_page(vcpu, parent_pte); |
714 | if (!sp) | 847 | if (!sp) |
715 | return sp; | 848 | return sp; |
716 | pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word); | 849 | pgprintk("%s: adding gfn %lx role %x\n", __func__, gfn, role.word); |
717 | sp->gfn = gfn; | 850 | sp->gfn = gfn; |
718 | sp->role = role; | 851 | sp->role = role; |
719 | hlist_add_head(&sp->hash_link, bucket); | 852 | hlist_add_head(&sp->hash_link, bucket); |
720 | vcpu->arch.mmu.prefetch_page(vcpu, sp); | ||
721 | if (!metaphysical) | 853 | if (!metaphysical) |
722 | rmap_write_protect(vcpu->kvm, gfn); | 854 | rmap_write_protect(vcpu->kvm, gfn); |
855 | vcpu->arch.mmu.prefetch_page(vcpu, sp); | ||
723 | return sp; | 856 | return sp; |
724 | } | 857 | } |
725 | 858 | ||
@@ -745,11 +878,17 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm, | |||
745 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { | 878 | for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { |
746 | ent = pt[i]; | 879 | ent = pt[i]; |
747 | 880 | ||
881 | if (is_shadow_present_pte(ent)) { | ||
882 | if (!is_large_pte(ent)) { | ||
883 | ent &= PT64_BASE_ADDR_MASK; | ||
884 | mmu_page_remove_parent_pte(page_header(ent), | ||
885 | &pt[i]); | ||
886 | } else { | ||
887 | --kvm->stat.lpages; | ||
888 | rmap_remove(kvm, &pt[i]); | ||
889 | } | ||
890 | } | ||
748 | pt[i] = shadow_trap_nonpresent_pte; | 891 | pt[i] = shadow_trap_nonpresent_pte; |
749 | if (!is_shadow_present_pte(ent)) | ||
750 | continue; | ||
751 | ent &= PT64_BASE_ADDR_MASK; | ||
752 | mmu_page_remove_parent_pte(page_header(ent), &pt[i]); | ||
753 | } | 892 | } |
754 | kvm_flush_remote_tlbs(kvm); | 893 | kvm_flush_remote_tlbs(kvm); |
755 | } | 894 | } |
@@ -789,10 +928,15 @@ static void kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) | |||
789 | } | 928 | } |
790 | kvm_mmu_page_unlink_children(kvm, sp); | 929 | kvm_mmu_page_unlink_children(kvm, sp); |
791 | if (!sp->root_count) { | 930 | if (!sp->root_count) { |
931 | if (!sp->role.metaphysical) | ||
932 | unaccount_shadowed(kvm, sp->gfn); | ||
792 | hlist_del(&sp->hash_link); | 933 | hlist_del(&sp->hash_link); |
793 | kvm_mmu_free_page(kvm, sp); | 934 | kvm_mmu_free_page(kvm, sp); |
794 | } else | 935 | } else { |
795 | list_move(&sp->link, &kvm->arch.active_mmu_pages); | 936 | list_move(&sp->link, &kvm->arch.active_mmu_pages); |
937 | sp->role.invalid = 1; | ||
938 | kvm_reload_remote_mmus(kvm); | ||
939 | } | ||
796 | kvm_mmu_reset_last_pte_updated(kvm); | 940 | kvm_mmu_reset_last_pte_updated(kvm); |
797 | } | 941 | } |
798 | 942 | ||
@@ -838,13 +982,13 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn) | |||
838 | struct hlist_node *node, *n; | 982 | struct hlist_node *node, *n; |
839 | int r; | 983 | int r; |
840 | 984 | ||
841 | pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); | 985 | pgprintk("%s: looking for gfn %lx\n", __func__, gfn); |
842 | r = 0; | 986 | r = 0; |
843 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 987 | index = kvm_page_table_hashfn(gfn); |
844 | bucket = &kvm->arch.mmu_page_hash[index]; | 988 | bucket = &kvm->arch.mmu_page_hash[index]; |
845 | hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) | 989 | hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) |
846 | if (sp->gfn == gfn && !sp->role.metaphysical) { | 990 | if (sp->gfn == gfn && !sp->role.metaphysical) { |
847 | pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn, | 991 | pgprintk("%s: gfn %lx role %x\n", __func__, gfn, |
848 | sp->role.word); | 992 | sp->role.word); |
849 | kvm_mmu_zap_page(kvm, sp); | 993 | kvm_mmu_zap_page(kvm, sp); |
850 | r = 1; | 994 | r = 1; |
@@ -857,7 +1001,7 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) | |||
857 | struct kvm_mmu_page *sp; | 1001 | struct kvm_mmu_page *sp; |
858 | 1002 | ||
859 | while ((sp = kvm_mmu_lookup_page(kvm, gfn)) != NULL) { | 1003 | while ((sp = kvm_mmu_lookup_page(kvm, gfn)) != NULL) { |
860 | pgprintk("%s: zap %lx %x\n", __FUNCTION__, gfn, sp->role.word); | 1004 | pgprintk("%s: zap %lx %x\n", __func__, gfn, sp->role.word); |
861 | kvm_mmu_zap_page(kvm, sp); | 1005 | kvm_mmu_zap_page(kvm, sp); |
862 | } | 1006 | } |
863 | } | 1007 | } |
@@ -889,26 +1033,39 @@ struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) | |||
889 | static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, | 1033 | static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, |
890 | unsigned pt_access, unsigned pte_access, | 1034 | unsigned pt_access, unsigned pte_access, |
891 | int user_fault, int write_fault, int dirty, | 1035 | int user_fault, int write_fault, int dirty, |
892 | int *ptwrite, gfn_t gfn, struct page *page) | 1036 | int *ptwrite, int largepage, gfn_t gfn, |
1037 | pfn_t pfn, bool speculative) | ||
893 | { | 1038 | { |
894 | u64 spte; | 1039 | u64 spte; |
895 | int was_rmapped = 0; | 1040 | int was_rmapped = 0; |
896 | int was_writeble = is_writeble_pte(*shadow_pte); | 1041 | int was_writeble = is_writeble_pte(*shadow_pte); |
897 | hfn_t host_pfn = (*shadow_pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; | ||
898 | 1042 | ||
899 | pgprintk("%s: spte %llx access %x write_fault %d" | 1043 | pgprintk("%s: spte %llx access %x write_fault %d" |
900 | " user_fault %d gfn %lx\n", | 1044 | " user_fault %d gfn %lx\n", |
901 | __FUNCTION__, *shadow_pte, pt_access, | 1045 | __func__, *shadow_pte, pt_access, |
902 | write_fault, user_fault, gfn); | 1046 | write_fault, user_fault, gfn); |
903 | 1047 | ||
904 | if (is_rmap_pte(*shadow_pte)) { | 1048 | if (is_rmap_pte(*shadow_pte)) { |
905 | if (host_pfn != page_to_pfn(page)) { | 1049 | /* |
1050 | * If we overwrite a PTE page pointer with a 2MB PMD, unlink | ||
1051 | * the parent of the now unreachable PTE. | ||
1052 | */ | ||
1053 | if (largepage && !is_large_pte(*shadow_pte)) { | ||
1054 | struct kvm_mmu_page *child; | ||
1055 | u64 pte = *shadow_pte; | ||
1056 | |||
1057 | child = page_header(pte & PT64_BASE_ADDR_MASK); | ||
1058 | mmu_page_remove_parent_pte(child, shadow_pte); | ||
1059 | } else if (pfn != spte_to_pfn(*shadow_pte)) { | ||
906 | pgprintk("hfn old %lx new %lx\n", | 1060 | pgprintk("hfn old %lx new %lx\n", |
907 | host_pfn, page_to_pfn(page)); | 1061 | spte_to_pfn(*shadow_pte), pfn); |
908 | rmap_remove(vcpu->kvm, shadow_pte); | 1062 | rmap_remove(vcpu->kvm, shadow_pte); |
1063 | } else { | ||
1064 | if (largepage) | ||
1065 | was_rmapped = is_large_pte(*shadow_pte); | ||
1066 | else | ||
1067 | was_rmapped = 1; | ||
909 | } | 1068 | } |
910 | else | ||
911 | was_rmapped = 1; | ||
912 | } | 1069 | } |
913 | 1070 | ||
914 | /* | 1071 | /* |
@@ -917,6 +1074,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, | |||
917 | * demand paging). | 1074 | * demand paging). |
918 | */ | 1075 | */ |
919 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; | 1076 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; |
1077 | if (!speculative) | ||
1078 | pte_access |= PT_ACCESSED_MASK; | ||
920 | if (!dirty) | 1079 | if (!dirty) |
921 | pte_access &= ~ACC_WRITE_MASK; | 1080 | pte_access &= ~ACC_WRITE_MASK; |
922 | if (!(pte_access & ACC_EXEC_MASK)) | 1081 | if (!(pte_access & ACC_EXEC_MASK)) |
@@ -925,15 +1084,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, | |||
925 | spte |= PT_PRESENT_MASK; | 1084 | spte |= PT_PRESENT_MASK; |
926 | if (pte_access & ACC_USER_MASK) | 1085 | if (pte_access & ACC_USER_MASK) |
927 | spte |= PT_USER_MASK; | 1086 | spte |= PT_USER_MASK; |
1087 | if (largepage) | ||
1088 | spte |= PT_PAGE_SIZE_MASK; | ||
928 | 1089 | ||
929 | if (is_error_page(page)) { | 1090 | spte |= (u64)pfn << PAGE_SHIFT; |
930 | set_shadow_pte(shadow_pte, | ||
931 | shadow_trap_nonpresent_pte | PT_SHADOW_IO_MARK); | ||
932 | kvm_release_page_clean(page); | ||
933 | return; | ||
934 | } | ||
935 | |||
936 | spte |= page_to_phys(page); | ||
937 | 1091 | ||
938 | if ((pte_access & ACC_WRITE_MASK) | 1092 | if ((pte_access & ACC_WRITE_MASK) |
939 | || (write_fault && !is_write_protection(vcpu) && !user_fault)) { | 1093 | || (write_fault && !is_write_protection(vcpu) && !user_fault)) { |
@@ -946,9 +1100,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, | |||
946 | } | 1100 | } |
947 | 1101 | ||
948 | shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn); | 1102 | shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn); |
949 | if (shadow) { | 1103 | if (shadow || |
1104 | (largepage && has_wrprotected_page(vcpu->kvm, gfn))) { | ||
950 | pgprintk("%s: found shadow page for %lx, marking ro\n", | 1105 | pgprintk("%s: found shadow page for %lx, marking ro\n", |
951 | __FUNCTION__, gfn); | 1106 | __func__, gfn); |
952 | pte_access &= ~ACC_WRITE_MASK; | 1107 | pte_access &= ~ACC_WRITE_MASK; |
953 | if (is_writeble_pte(spte)) { | 1108 | if (is_writeble_pte(spte)) { |
954 | spte &= ~PT_WRITABLE_MASK; | 1109 | spte &= ~PT_WRITABLE_MASK; |
@@ -964,18 +1119,25 @@ unshadowed: | |||
964 | if (pte_access & ACC_WRITE_MASK) | 1119 | if (pte_access & ACC_WRITE_MASK) |
965 | mark_page_dirty(vcpu->kvm, gfn); | 1120 | mark_page_dirty(vcpu->kvm, gfn); |
966 | 1121 | ||
967 | pgprintk("%s: setting spte %llx\n", __FUNCTION__, spte); | 1122 | pgprintk("%s: setting spte %llx\n", __func__, spte); |
1123 | pgprintk("instantiating %s PTE (%s) at %d (%llx) addr %llx\n", | ||
1124 | (spte&PT_PAGE_SIZE_MASK)? "2MB" : "4kB", | ||
1125 | (spte&PT_WRITABLE_MASK)?"RW":"R", gfn, spte, shadow_pte); | ||
968 | set_shadow_pte(shadow_pte, spte); | 1126 | set_shadow_pte(shadow_pte, spte); |
1127 | if (!was_rmapped && (spte & PT_PAGE_SIZE_MASK) | ||
1128 | && (spte & PT_PRESENT_MASK)) | ||
1129 | ++vcpu->kvm->stat.lpages; | ||
1130 | |||
969 | page_header_update_slot(vcpu->kvm, shadow_pte, gfn); | 1131 | page_header_update_slot(vcpu->kvm, shadow_pte, gfn); |
970 | if (!was_rmapped) { | 1132 | if (!was_rmapped) { |
971 | rmap_add(vcpu, shadow_pte, gfn); | 1133 | rmap_add(vcpu, shadow_pte, gfn, largepage); |
972 | if (!is_rmap_pte(*shadow_pte)) | 1134 | if (!is_rmap_pte(*shadow_pte)) |
973 | kvm_release_page_clean(page); | 1135 | kvm_release_pfn_clean(pfn); |
974 | } else { | 1136 | } else { |
975 | if (was_writeble) | 1137 | if (was_writeble) |
976 | kvm_release_page_dirty(page); | 1138 | kvm_release_pfn_dirty(pfn); |
977 | else | 1139 | else |
978 | kvm_release_page_clean(page); | 1140 | kvm_release_pfn_clean(pfn); |
979 | } | 1141 | } |
980 | if (!ptwrite || !*ptwrite) | 1142 | if (!ptwrite || !*ptwrite) |
981 | vcpu->arch.last_pte_updated = shadow_pte; | 1143 | vcpu->arch.last_pte_updated = shadow_pte; |
@@ -985,10 +1147,10 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) | |||
985 | { | 1147 | { |
986 | } | 1148 | } |
987 | 1149 | ||
988 | static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, | 1150 | static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, |
989 | gfn_t gfn, struct page *page) | 1151 | int largepage, gfn_t gfn, pfn_t pfn, |
1152 | int level) | ||
990 | { | 1153 | { |
991 | int level = PT32E_ROOT_LEVEL; | ||
992 | hpa_t table_addr = vcpu->arch.mmu.root_hpa; | 1154 | hpa_t table_addr = vcpu->arch.mmu.root_hpa; |
993 | int pt_write = 0; | 1155 | int pt_write = 0; |
994 | 1156 | ||
@@ -1001,8 +1163,14 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, | |||
1001 | 1163 | ||
1002 | if (level == 1) { | 1164 | if (level == 1) { |
1003 | mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, | 1165 | mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, |
1004 | 0, write, 1, &pt_write, gfn, page); | 1166 | 0, write, 1, &pt_write, 0, gfn, pfn, false); |
1005 | return pt_write || is_io_pte(table[index]); | 1167 | return pt_write; |
1168 | } | ||
1169 | |||
1170 | if (largepage && level == 2) { | ||
1171 | mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, | ||
1172 | 0, write, 1, &pt_write, 1, gfn, pfn, false); | ||
1173 | return pt_write; | ||
1006 | } | 1174 | } |
1007 | 1175 | ||
1008 | if (table[index] == shadow_trap_nonpresent_pte) { | 1176 | if (table[index] == shadow_trap_nonpresent_pte) { |
@@ -1016,7 +1184,7 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, | |||
1016 | 1, ACC_ALL, &table[index]); | 1184 | 1, ACC_ALL, &table[index]); |
1017 | if (!new_table) { | 1185 | if (!new_table) { |
1018 | pgprintk("nonpaging_map: ENOMEM\n"); | 1186 | pgprintk("nonpaging_map: ENOMEM\n"); |
1019 | kvm_release_page_clean(page); | 1187 | kvm_release_pfn_clean(pfn); |
1020 | return -ENOMEM; | 1188 | return -ENOMEM; |
1021 | } | 1189 | } |
1022 | 1190 | ||
@@ -1030,21 +1198,30 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, | |||
1030 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) | 1198 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) |
1031 | { | 1199 | { |
1032 | int r; | 1200 | int r; |
1033 | 1201 | int largepage = 0; | |
1034 | struct page *page; | 1202 | pfn_t pfn; |
1035 | |||
1036 | down_read(&vcpu->kvm->slots_lock); | ||
1037 | 1203 | ||
1038 | down_read(¤t->mm->mmap_sem); | 1204 | down_read(¤t->mm->mmap_sem); |
1039 | page = gfn_to_page(vcpu->kvm, gfn); | 1205 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { |
1206 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | ||
1207 | largepage = 1; | ||
1208 | } | ||
1209 | |||
1210 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | ||
1040 | up_read(¤t->mm->mmap_sem); | 1211 | up_read(¤t->mm->mmap_sem); |
1041 | 1212 | ||
1213 | /* mmio */ | ||
1214 | if (is_error_pfn(pfn)) { | ||
1215 | kvm_release_pfn_clean(pfn); | ||
1216 | return 1; | ||
1217 | } | ||
1218 | |||
1042 | spin_lock(&vcpu->kvm->mmu_lock); | 1219 | spin_lock(&vcpu->kvm->mmu_lock); |
1043 | kvm_mmu_free_some_pages(vcpu); | 1220 | kvm_mmu_free_some_pages(vcpu); |
1044 | r = __nonpaging_map(vcpu, v, write, gfn, page); | 1221 | r = __direct_map(vcpu, v, write, largepage, gfn, pfn, |
1222 | PT32E_ROOT_LEVEL); | ||
1045 | spin_unlock(&vcpu->kvm->mmu_lock); | 1223 | spin_unlock(&vcpu->kvm->mmu_lock); |
1046 | 1224 | ||
1047 | up_read(&vcpu->kvm->slots_lock); | ||
1048 | 1225 | ||
1049 | return r; | 1226 | return r; |
1050 | } | 1227 | } |
@@ -1073,6 +1250,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) | |||
1073 | 1250 | ||
1074 | sp = page_header(root); | 1251 | sp = page_header(root); |
1075 | --sp->root_count; | 1252 | --sp->root_count; |
1253 | if (!sp->root_count && sp->role.invalid) | ||
1254 | kvm_mmu_zap_page(vcpu->kvm, sp); | ||
1076 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; | 1255 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; |
1077 | spin_unlock(&vcpu->kvm->mmu_lock); | 1256 | spin_unlock(&vcpu->kvm->mmu_lock); |
1078 | return; | 1257 | return; |
@@ -1085,6 +1264,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) | |||
1085 | root &= PT64_BASE_ADDR_MASK; | 1264 | root &= PT64_BASE_ADDR_MASK; |
1086 | sp = page_header(root); | 1265 | sp = page_header(root); |
1087 | --sp->root_count; | 1266 | --sp->root_count; |
1267 | if (!sp->root_count && sp->role.invalid) | ||
1268 | kvm_mmu_zap_page(vcpu->kvm, sp); | ||
1088 | } | 1269 | } |
1089 | vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; | 1270 | vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; |
1090 | } | 1271 | } |
@@ -1097,6 +1278,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
1097 | int i; | 1278 | int i; |
1098 | gfn_t root_gfn; | 1279 | gfn_t root_gfn; |
1099 | struct kvm_mmu_page *sp; | 1280 | struct kvm_mmu_page *sp; |
1281 | int metaphysical = 0; | ||
1100 | 1282 | ||
1101 | root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT; | 1283 | root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT; |
1102 | 1284 | ||
@@ -1105,14 +1287,20 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
1105 | hpa_t root = vcpu->arch.mmu.root_hpa; | 1287 | hpa_t root = vcpu->arch.mmu.root_hpa; |
1106 | 1288 | ||
1107 | ASSERT(!VALID_PAGE(root)); | 1289 | ASSERT(!VALID_PAGE(root)); |
1290 | if (tdp_enabled) | ||
1291 | metaphysical = 1; | ||
1108 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, | 1292 | sp = kvm_mmu_get_page(vcpu, root_gfn, 0, |
1109 | PT64_ROOT_LEVEL, 0, ACC_ALL, NULL); | 1293 | PT64_ROOT_LEVEL, metaphysical, |
1294 | ACC_ALL, NULL); | ||
1110 | root = __pa(sp->spt); | 1295 | root = __pa(sp->spt); |
1111 | ++sp->root_count; | 1296 | ++sp->root_count; |
1112 | vcpu->arch.mmu.root_hpa = root; | 1297 | vcpu->arch.mmu.root_hpa = root; |
1113 | return; | 1298 | return; |
1114 | } | 1299 | } |
1115 | #endif | 1300 | #endif |
1301 | metaphysical = !is_paging(vcpu); | ||
1302 | if (tdp_enabled) | ||
1303 | metaphysical = 1; | ||
1116 | for (i = 0; i < 4; ++i) { | 1304 | for (i = 0; i < 4; ++i) { |
1117 | hpa_t root = vcpu->arch.mmu.pae_root[i]; | 1305 | hpa_t root = vcpu->arch.mmu.pae_root[i]; |
1118 | 1306 | ||
@@ -1126,7 +1314,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) | |||
1126 | } else if (vcpu->arch.mmu.root_level == 0) | 1314 | } else if (vcpu->arch.mmu.root_level == 0) |
1127 | root_gfn = 0; | 1315 | root_gfn = 0; |
1128 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, | 1316 | sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, |
1129 | PT32_ROOT_LEVEL, !is_paging(vcpu), | 1317 | PT32_ROOT_LEVEL, metaphysical, |
1130 | ACC_ALL, NULL); | 1318 | ACC_ALL, NULL); |
1131 | root = __pa(sp->spt); | 1319 | root = __pa(sp->spt); |
1132 | ++sp->root_count; | 1320 | ++sp->root_count; |
@@ -1146,7 +1334,7 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, | |||
1146 | gfn_t gfn; | 1334 | gfn_t gfn; |
1147 | int r; | 1335 | int r; |
1148 | 1336 | ||
1149 | pgprintk("%s: gva %lx error %x\n", __FUNCTION__, gva, error_code); | 1337 | pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code); |
1150 | r = mmu_topup_memory_caches(vcpu); | 1338 | r = mmu_topup_memory_caches(vcpu); |
1151 | if (r) | 1339 | if (r) |
1152 | return r; | 1340 | return r; |
@@ -1160,6 +1348,41 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, | |||
1160 | error_code & PFERR_WRITE_MASK, gfn); | 1348 | error_code & PFERR_WRITE_MASK, gfn); |
1161 | } | 1349 | } |
1162 | 1350 | ||
1351 | static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, | ||
1352 | u32 error_code) | ||
1353 | { | ||
1354 | pfn_t pfn; | ||
1355 | int r; | ||
1356 | int largepage = 0; | ||
1357 | gfn_t gfn = gpa >> PAGE_SHIFT; | ||
1358 | |||
1359 | ASSERT(vcpu); | ||
1360 | ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa)); | ||
1361 | |||
1362 | r = mmu_topup_memory_caches(vcpu); | ||
1363 | if (r) | ||
1364 | return r; | ||
1365 | |||
1366 | down_read(¤t->mm->mmap_sem); | ||
1367 | if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) { | ||
1368 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | ||
1369 | largepage = 1; | ||
1370 | } | ||
1371 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | ||
1372 | up_read(¤t->mm->mmap_sem); | ||
1373 | if (is_error_pfn(pfn)) { | ||
1374 | kvm_release_pfn_clean(pfn); | ||
1375 | return 1; | ||
1376 | } | ||
1377 | spin_lock(&vcpu->kvm->mmu_lock); | ||
1378 | kvm_mmu_free_some_pages(vcpu); | ||
1379 | r = __direct_map(vcpu, gpa, error_code & PFERR_WRITE_MASK, | ||
1380 | largepage, gfn, pfn, TDP_ROOT_LEVEL); | ||
1381 | spin_unlock(&vcpu->kvm->mmu_lock); | ||
1382 | |||
1383 | return r; | ||
1384 | } | ||
1385 | |||
1163 | static void nonpaging_free(struct kvm_vcpu *vcpu) | 1386 | static void nonpaging_free(struct kvm_vcpu *vcpu) |
1164 | { | 1387 | { |
1165 | mmu_free_roots(vcpu); | 1388 | mmu_free_roots(vcpu); |
@@ -1188,7 +1411,7 @@ void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) | |||
1188 | 1411 | ||
1189 | static void paging_new_cr3(struct kvm_vcpu *vcpu) | 1412 | static void paging_new_cr3(struct kvm_vcpu *vcpu) |
1190 | { | 1413 | { |
1191 | pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->arch.cr3); | 1414 | pgprintk("%s: cr3 %lx\n", __func__, vcpu->arch.cr3); |
1192 | mmu_free_roots(vcpu); | 1415 | mmu_free_roots(vcpu); |
1193 | } | 1416 | } |
1194 | 1417 | ||
@@ -1253,7 +1476,35 @@ static int paging32E_init_context(struct kvm_vcpu *vcpu) | |||
1253 | return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); | 1476 | return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); |
1254 | } | 1477 | } |
1255 | 1478 | ||
1256 | static int init_kvm_mmu(struct kvm_vcpu *vcpu) | 1479 | static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) |
1480 | { | ||
1481 | struct kvm_mmu *context = &vcpu->arch.mmu; | ||
1482 | |||
1483 | context->new_cr3 = nonpaging_new_cr3; | ||
1484 | context->page_fault = tdp_page_fault; | ||
1485 | context->free = nonpaging_free; | ||
1486 | context->prefetch_page = nonpaging_prefetch_page; | ||
1487 | context->shadow_root_level = TDP_ROOT_LEVEL; | ||
1488 | context->root_hpa = INVALID_PAGE; | ||
1489 | |||
1490 | if (!is_paging(vcpu)) { | ||
1491 | context->gva_to_gpa = nonpaging_gva_to_gpa; | ||
1492 | context->root_level = 0; | ||
1493 | } else if (is_long_mode(vcpu)) { | ||
1494 | context->gva_to_gpa = paging64_gva_to_gpa; | ||
1495 | context->root_level = PT64_ROOT_LEVEL; | ||
1496 | } else if (is_pae(vcpu)) { | ||
1497 | context->gva_to_gpa = paging64_gva_to_gpa; | ||
1498 | context->root_level = PT32E_ROOT_LEVEL; | ||
1499 | } else { | ||
1500 | context->gva_to_gpa = paging32_gva_to_gpa; | ||
1501 | context->root_level = PT32_ROOT_LEVEL; | ||
1502 | } | ||
1503 | |||
1504 | return 0; | ||
1505 | } | ||
1506 | |||
1507 | static int init_kvm_softmmu(struct kvm_vcpu *vcpu) | ||
1257 | { | 1508 | { |
1258 | ASSERT(vcpu); | 1509 | ASSERT(vcpu); |
1259 | ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); | 1510 | ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); |
@@ -1268,6 +1519,16 @@ static int init_kvm_mmu(struct kvm_vcpu *vcpu) | |||
1268 | return paging32_init_context(vcpu); | 1519 | return paging32_init_context(vcpu); |
1269 | } | 1520 | } |
1270 | 1521 | ||
1522 | static int init_kvm_mmu(struct kvm_vcpu *vcpu) | ||
1523 | { | ||
1524 | vcpu->arch.update_pte.pfn = bad_pfn; | ||
1525 | |||
1526 | if (tdp_enabled) | ||
1527 | return init_kvm_tdp_mmu(vcpu); | ||
1528 | else | ||
1529 | return init_kvm_softmmu(vcpu); | ||
1530 | } | ||
1531 | |||
1271 | static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) | 1532 | static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) |
1272 | { | 1533 | { |
1273 | ASSERT(vcpu); | 1534 | ASSERT(vcpu); |
@@ -1316,7 +1577,8 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, | |||
1316 | 1577 | ||
1317 | pte = *spte; | 1578 | pte = *spte; |
1318 | if (is_shadow_present_pte(pte)) { | 1579 | if (is_shadow_present_pte(pte)) { |
1319 | if (sp->role.level == PT_PAGE_TABLE_LEVEL) | 1580 | if (sp->role.level == PT_PAGE_TABLE_LEVEL || |
1581 | is_large_pte(pte)) | ||
1320 | rmap_remove(vcpu->kvm, spte); | 1582 | rmap_remove(vcpu->kvm, spte); |
1321 | else { | 1583 | else { |
1322 | child = page_header(pte & PT64_BASE_ADDR_MASK); | 1584 | child = page_header(pte & PT64_BASE_ADDR_MASK); |
@@ -1324,24 +1586,26 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, | |||
1324 | } | 1586 | } |
1325 | } | 1587 | } |
1326 | set_shadow_pte(spte, shadow_trap_nonpresent_pte); | 1588 | set_shadow_pte(spte, shadow_trap_nonpresent_pte); |
1589 | if (is_large_pte(pte)) | ||
1590 | --vcpu->kvm->stat.lpages; | ||
1327 | } | 1591 | } |
1328 | 1592 | ||
1329 | static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, | 1593 | static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, |
1330 | struct kvm_mmu_page *sp, | 1594 | struct kvm_mmu_page *sp, |
1331 | u64 *spte, | 1595 | u64 *spte, |
1332 | const void *new, int bytes, | 1596 | const void *new) |
1333 | int offset_in_pte) | ||
1334 | { | 1597 | { |
1335 | if (sp->role.level != PT_PAGE_TABLE_LEVEL) { | 1598 | if ((sp->role.level != PT_PAGE_TABLE_LEVEL) |
1599 | && !vcpu->arch.update_pte.largepage) { | ||
1336 | ++vcpu->kvm->stat.mmu_pde_zapped; | 1600 | ++vcpu->kvm->stat.mmu_pde_zapped; |
1337 | return; | 1601 | return; |
1338 | } | 1602 | } |
1339 | 1603 | ||
1340 | ++vcpu->kvm->stat.mmu_pte_updated; | 1604 | ++vcpu->kvm->stat.mmu_pte_updated; |
1341 | if (sp->role.glevels == PT32_ROOT_LEVEL) | 1605 | if (sp->role.glevels == PT32_ROOT_LEVEL) |
1342 | paging32_update_pte(vcpu, sp, spte, new, bytes, offset_in_pte); | 1606 | paging32_update_pte(vcpu, sp, spte, new); |
1343 | else | 1607 | else |
1344 | paging64_update_pte(vcpu, sp, spte, new, bytes, offset_in_pte); | 1608 | paging64_update_pte(vcpu, sp, spte, new); |
1345 | } | 1609 | } |
1346 | 1610 | ||
1347 | static bool need_remote_flush(u64 old, u64 new) | 1611 | static bool need_remote_flush(u64 old, u64 new) |
@@ -1378,7 +1642,9 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1378 | gfn_t gfn; | 1642 | gfn_t gfn; |
1379 | int r; | 1643 | int r; |
1380 | u64 gpte = 0; | 1644 | u64 gpte = 0; |
1381 | struct page *page; | 1645 | pfn_t pfn; |
1646 | |||
1647 | vcpu->arch.update_pte.largepage = 0; | ||
1382 | 1648 | ||
1383 | if (bytes != 4 && bytes != 8) | 1649 | if (bytes != 4 && bytes != 8) |
1384 | return; | 1650 | return; |
@@ -1408,11 +1674,19 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1408 | gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; | 1674 | gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; |
1409 | 1675 | ||
1410 | down_read(¤t->mm->mmap_sem); | 1676 | down_read(¤t->mm->mmap_sem); |
1411 | page = gfn_to_page(vcpu->kvm, gfn); | 1677 | if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) { |
1678 | gfn &= ~(KVM_PAGES_PER_HPAGE-1); | ||
1679 | vcpu->arch.update_pte.largepage = 1; | ||
1680 | } | ||
1681 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | ||
1412 | up_read(¤t->mm->mmap_sem); | 1682 | up_read(¤t->mm->mmap_sem); |
1413 | 1683 | ||
1684 | if (is_error_pfn(pfn)) { | ||
1685 | kvm_release_pfn_clean(pfn); | ||
1686 | return; | ||
1687 | } | ||
1414 | vcpu->arch.update_pte.gfn = gfn; | 1688 | vcpu->arch.update_pte.gfn = gfn; |
1415 | vcpu->arch.update_pte.page = page; | 1689 | vcpu->arch.update_pte.pfn = pfn; |
1416 | } | 1690 | } |
1417 | 1691 | ||
1418 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | 1692 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, |
@@ -1423,7 +1697,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1423 | struct hlist_node *node, *n; | 1697 | struct hlist_node *node, *n; |
1424 | struct hlist_head *bucket; | 1698 | struct hlist_head *bucket; |
1425 | unsigned index; | 1699 | unsigned index; |
1426 | u64 entry; | 1700 | u64 entry, gentry; |
1427 | u64 *spte; | 1701 | u64 *spte; |
1428 | unsigned offset = offset_in_page(gpa); | 1702 | unsigned offset = offset_in_page(gpa); |
1429 | unsigned pte_size; | 1703 | unsigned pte_size; |
@@ -1433,8 +1707,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1433 | int level; | 1707 | int level; |
1434 | int flooded = 0; | 1708 | int flooded = 0; |
1435 | int npte; | 1709 | int npte; |
1710 | int r; | ||
1436 | 1711 | ||
1437 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); | 1712 | pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes); |
1438 | mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes); | 1713 | mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes); |
1439 | spin_lock(&vcpu->kvm->mmu_lock); | 1714 | spin_lock(&vcpu->kvm->mmu_lock); |
1440 | kvm_mmu_free_some_pages(vcpu); | 1715 | kvm_mmu_free_some_pages(vcpu); |
@@ -1450,7 +1725,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1450 | vcpu->arch.last_pt_write_count = 1; | 1725 | vcpu->arch.last_pt_write_count = 1; |
1451 | vcpu->arch.last_pte_updated = NULL; | 1726 | vcpu->arch.last_pte_updated = NULL; |
1452 | } | 1727 | } |
1453 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 1728 | index = kvm_page_table_hashfn(gfn); |
1454 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; | 1729 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; |
1455 | hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) { | 1730 | hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) { |
1456 | if (sp->gfn != gfn || sp->role.metaphysical) | 1731 | if (sp->gfn != gfn || sp->role.metaphysical) |
@@ -1496,20 +1771,29 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1496 | continue; | 1771 | continue; |
1497 | } | 1772 | } |
1498 | spte = &sp->spt[page_offset / sizeof(*spte)]; | 1773 | spte = &sp->spt[page_offset / sizeof(*spte)]; |
1774 | if ((gpa & (pte_size - 1)) || (bytes < pte_size)) { | ||
1775 | gentry = 0; | ||
1776 | r = kvm_read_guest_atomic(vcpu->kvm, | ||
1777 | gpa & ~(u64)(pte_size - 1), | ||
1778 | &gentry, pte_size); | ||
1779 | new = (const void *)&gentry; | ||
1780 | if (r < 0) | ||
1781 | new = NULL; | ||
1782 | } | ||
1499 | while (npte--) { | 1783 | while (npte--) { |
1500 | entry = *spte; | 1784 | entry = *spte; |
1501 | mmu_pte_write_zap_pte(vcpu, sp, spte); | 1785 | mmu_pte_write_zap_pte(vcpu, sp, spte); |
1502 | mmu_pte_write_new_pte(vcpu, sp, spte, new, bytes, | 1786 | if (new) |
1503 | page_offset & (pte_size - 1)); | 1787 | mmu_pte_write_new_pte(vcpu, sp, spte, new); |
1504 | mmu_pte_write_flush_tlb(vcpu, entry, *spte); | 1788 | mmu_pte_write_flush_tlb(vcpu, entry, *spte); |
1505 | ++spte; | 1789 | ++spte; |
1506 | } | 1790 | } |
1507 | } | 1791 | } |
1508 | kvm_mmu_audit(vcpu, "post pte write"); | 1792 | kvm_mmu_audit(vcpu, "post pte write"); |
1509 | spin_unlock(&vcpu->kvm->mmu_lock); | 1793 | spin_unlock(&vcpu->kvm->mmu_lock); |
1510 | if (vcpu->arch.update_pte.page) { | 1794 | if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { |
1511 | kvm_release_page_clean(vcpu->arch.update_pte.page); | 1795 | kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); |
1512 | vcpu->arch.update_pte.page = NULL; | 1796 | vcpu->arch.update_pte.pfn = bad_pfn; |
1513 | } | 1797 | } |
1514 | } | 1798 | } |
1515 | 1799 | ||
@@ -1518,9 +1802,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) | |||
1518 | gpa_t gpa; | 1802 | gpa_t gpa; |
1519 | int r; | 1803 | int r; |
1520 | 1804 | ||
1521 | down_read(&vcpu->kvm->slots_lock); | ||
1522 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva); | 1805 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva); |
1523 | up_read(&vcpu->kvm->slots_lock); | ||
1524 | 1806 | ||
1525 | spin_lock(&vcpu->kvm->mmu_lock); | 1807 | spin_lock(&vcpu->kvm->mmu_lock); |
1526 | r = kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT); | 1808 | r = kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT); |
@@ -1577,6 +1859,12 @@ out: | |||
1577 | } | 1859 | } |
1578 | EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); | 1860 | EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); |
1579 | 1861 | ||
1862 | void kvm_enable_tdp(void) | ||
1863 | { | ||
1864 | tdp_enabled = true; | ||
1865 | } | ||
1866 | EXPORT_SYMBOL_GPL(kvm_enable_tdp); | ||
1867 | |||
1580 | static void free_mmu_pages(struct kvm_vcpu *vcpu) | 1868 | static void free_mmu_pages(struct kvm_vcpu *vcpu) |
1581 | { | 1869 | { |
1582 | struct kvm_mmu_page *sp; | 1870 | struct kvm_mmu_page *sp; |
@@ -1677,7 +1965,53 @@ void kvm_mmu_zap_all(struct kvm *kvm) | |||
1677 | kvm_flush_remote_tlbs(kvm); | 1965 | kvm_flush_remote_tlbs(kvm); |
1678 | } | 1966 | } |
1679 | 1967 | ||
1680 | void kvm_mmu_module_exit(void) | 1968 | void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm) |
1969 | { | ||
1970 | struct kvm_mmu_page *page; | ||
1971 | |||
1972 | page = container_of(kvm->arch.active_mmu_pages.prev, | ||
1973 | struct kvm_mmu_page, link); | ||
1974 | kvm_mmu_zap_page(kvm, page); | ||
1975 | } | ||
1976 | |||
1977 | static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) | ||
1978 | { | ||
1979 | struct kvm *kvm; | ||
1980 | struct kvm *kvm_freed = NULL; | ||
1981 | int cache_count = 0; | ||
1982 | |||
1983 | spin_lock(&kvm_lock); | ||
1984 | |||
1985 | list_for_each_entry(kvm, &vm_list, vm_list) { | ||
1986 | int npages; | ||
1987 | |||
1988 | spin_lock(&kvm->mmu_lock); | ||
1989 | npages = kvm->arch.n_alloc_mmu_pages - | ||
1990 | kvm->arch.n_free_mmu_pages; | ||
1991 | cache_count += npages; | ||
1992 | if (!kvm_freed && nr_to_scan > 0 && npages > 0) { | ||
1993 | kvm_mmu_remove_one_alloc_mmu_page(kvm); | ||
1994 | cache_count--; | ||
1995 | kvm_freed = kvm; | ||
1996 | } | ||
1997 | nr_to_scan--; | ||
1998 | |||
1999 | spin_unlock(&kvm->mmu_lock); | ||
2000 | } | ||
2001 | if (kvm_freed) | ||
2002 | list_move_tail(&kvm_freed->vm_list, &vm_list); | ||
2003 | |||
2004 | spin_unlock(&kvm_lock); | ||
2005 | |||
2006 | return cache_count; | ||
2007 | } | ||
2008 | |||
2009 | static struct shrinker mmu_shrinker = { | ||
2010 | .shrink = mmu_shrink, | ||
2011 | .seeks = DEFAULT_SEEKS * 10, | ||
2012 | }; | ||
2013 | |||
2014 | void mmu_destroy_caches(void) | ||
1681 | { | 2015 | { |
1682 | if (pte_chain_cache) | 2016 | if (pte_chain_cache) |
1683 | kmem_cache_destroy(pte_chain_cache); | 2017 | kmem_cache_destroy(pte_chain_cache); |
@@ -1687,6 +2021,12 @@ void kvm_mmu_module_exit(void) | |||
1687 | kmem_cache_destroy(mmu_page_header_cache); | 2021 | kmem_cache_destroy(mmu_page_header_cache); |
1688 | } | 2022 | } |
1689 | 2023 | ||
2024 | void kvm_mmu_module_exit(void) | ||
2025 | { | ||
2026 | mmu_destroy_caches(); | ||
2027 | unregister_shrinker(&mmu_shrinker); | ||
2028 | } | ||
2029 | |||
1690 | int kvm_mmu_module_init(void) | 2030 | int kvm_mmu_module_init(void) |
1691 | { | 2031 | { |
1692 | pte_chain_cache = kmem_cache_create("kvm_pte_chain", | 2032 | pte_chain_cache = kmem_cache_create("kvm_pte_chain", |
@@ -1706,10 +2046,12 @@ int kvm_mmu_module_init(void) | |||
1706 | if (!mmu_page_header_cache) | 2046 | if (!mmu_page_header_cache) |
1707 | goto nomem; | 2047 | goto nomem; |
1708 | 2048 | ||
2049 | register_shrinker(&mmu_shrinker); | ||
2050 | |||
1709 | return 0; | 2051 | return 0; |
1710 | 2052 | ||
1711 | nomem: | 2053 | nomem: |
1712 | kvm_mmu_module_exit(); | 2054 | mmu_destroy_caches(); |
1713 | return -ENOMEM; | 2055 | return -ENOMEM; |
1714 | } | 2056 | } |
1715 | 2057 | ||
@@ -1732,6 +2074,127 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm) | |||
1732 | return nr_mmu_pages; | 2074 | return nr_mmu_pages; |
1733 | } | 2075 | } |
1734 | 2076 | ||
2077 | static void *pv_mmu_peek_buffer(struct kvm_pv_mmu_op_buffer *buffer, | ||
2078 | unsigned len) | ||
2079 | { | ||
2080 | if (len > buffer->len) | ||
2081 | return NULL; | ||
2082 | return buffer->ptr; | ||
2083 | } | ||
2084 | |||
2085 | static void *pv_mmu_read_buffer(struct kvm_pv_mmu_op_buffer *buffer, | ||
2086 | unsigned len) | ||
2087 | { | ||
2088 | void *ret; | ||
2089 | |||
2090 | ret = pv_mmu_peek_buffer(buffer, len); | ||
2091 | if (!ret) | ||
2092 | return ret; | ||
2093 | buffer->ptr += len; | ||
2094 | buffer->len -= len; | ||
2095 | buffer->processed += len; | ||
2096 | return ret; | ||
2097 | } | ||
2098 | |||
2099 | static int kvm_pv_mmu_write(struct kvm_vcpu *vcpu, | ||
2100 | gpa_t addr, gpa_t value) | ||
2101 | { | ||
2102 | int bytes = 8; | ||
2103 | int r; | ||
2104 | |||
2105 | if (!is_long_mode(vcpu) && !is_pae(vcpu)) | ||
2106 | bytes = 4; | ||
2107 | |||
2108 | r = mmu_topup_memory_caches(vcpu); | ||
2109 | if (r) | ||
2110 | return r; | ||
2111 | |||
2112 | if (!emulator_write_phys(vcpu, addr, &value, bytes)) | ||
2113 | return -EFAULT; | ||
2114 | |||
2115 | return 1; | ||
2116 | } | ||
2117 | |||
2118 | static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu) | ||
2119 | { | ||
2120 | kvm_x86_ops->tlb_flush(vcpu); | ||
2121 | return 1; | ||
2122 | } | ||
2123 | |||
2124 | static int kvm_pv_mmu_release_pt(struct kvm_vcpu *vcpu, gpa_t addr) | ||
2125 | { | ||
2126 | spin_lock(&vcpu->kvm->mmu_lock); | ||
2127 | mmu_unshadow(vcpu->kvm, addr >> PAGE_SHIFT); | ||
2128 | spin_unlock(&vcpu->kvm->mmu_lock); | ||
2129 | return 1; | ||
2130 | } | ||
2131 | |||
2132 | static int kvm_pv_mmu_op_one(struct kvm_vcpu *vcpu, | ||
2133 | struct kvm_pv_mmu_op_buffer *buffer) | ||
2134 | { | ||
2135 | struct kvm_mmu_op_header *header; | ||
2136 | |||
2137 | header = pv_mmu_peek_buffer(buffer, sizeof *header); | ||
2138 | if (!header) | ||
2139 | return 0; | ||
2140 | switch (header->op) { | ||
2141 | case KVM_MMU_OP_WRITE_PTE: { | ||
2142 | struct kvm_mmu_op_write_pte *wpte; | ||
2143 | |||
2144 | wpte = pv_mmu_read_buffer(buffer, sizeof *wpte); | ||
2145 | if (!wpte) | ||
2146 | return 0; | ||
2147 | return kvm_pv_mmu_write(vcpu, wpte->pte_phys, | ||
2148 | wpte->pte_val); | ||
2149 | } | ||
2150 | case KVM_MMU_OP_FLUSH_TLB: { | ||
2151 | struct kvm_mmu_op_flush_tlb *ftlb; | ||
2152 | |||
2153 | ftlb = pv_mmu_read_buffer(buffer, sizeof *ftlb); | ||
2154 | if (!ftlb) | ||
2155 | return 0; | ||
2156 | return kvm_pv_mmu_flush_tlb(vcpu); | ||
2157 | } | ||
2158 | case KVM_MMU_OP_RELEASE_PT: { | ||
2159 | struct kvm_mmu_op_release_pt *rpt; | ||
2160 | |||
2161 | rpt = pv_mmu_read_buffer(buffer, sizeof *rpt); | ||
2162 | if (!rpt) | ||
2163 | return 0; | ||
2164 | return kvm_pv_mmu_release_pt(vcpu, rpt->pt_phys); | ||
2165 | } | ||
2166 | default: return 0; | ||
2167 | } | ||
2168 | } | ||
2169 | |||
2170 | int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes, | ||
2171 | gpa_t addr, unsigned long *ret) | ||
2172 | { | ||
2173 | int r; | ||
2174 | struct kvm_pv_mmu_op_buffer buffer; | ||
2175 | |||
2176 | buffer.ptr = buffer.buf; | ||
2177 | buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf); | ||
2178 | buffer.processed = 0; | ||
2179 | |||
2180 | r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len); | ||
2181 | if (r) | ||
2182 | goto out; | ||
2183 | |||
2184 | while (buffer.len) { | ||
2185 | r = kvm_pv_mmu_op_one(vcpu, &buffer); | ||
2186 | if (r < 0) | ||
2187 | goto out; | ||
2188 | if (r == 0) | ||
2189 | break; | ||
2190 | } | ||
2191 | |||
2192 | r = 1; | ||
2193 | out: | ||
2194 | *ret = buffer.processed; | ||
2195 | return r; | ||
2196 | } | ||
2197 | |||
1735 | #ifdef AUDIT | 2198 | #ifdef AUDIT |
1736 | 2199 | ||
1737 | static const char *audit_msg; | 2200 | static const char *audit_msg; |
@@ -1768,8 +2231,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, | |||
1768 | audit_mappings_page(vcpu, ent, va, level - 1); | 2231 | audit_mappings_page(vcpu, ent, va, level - 1); |
1769 | } else { | 2232 | } else { |
1770 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va); | 2233 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va); |
1771 | struct page *page = gpa_to_page(vcpu, gpa); | 2234 | hpa_t hpa = (hpa_t)gpa_to_pfn(vcpu, gpa) << PAGE_SHIFT; |
1772 | hpa_t hpa = page_to_phys(page); | ||
1773 | 2235 | ||
1774 | if (is_shadow_present_pte(ent) | 2236 | if (is_shadow_present_pte(ent) |
1775 | && (ent & PT64_BASE_ADDR_MASK) != hpa) | 2237 | && (ent & PT64_BASE_ADDR_MASK) != hpa) |
@@ -1782,7 +2244,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, | |||
1782 | && !is_error_hpa(hpa)) | 2244 | && !is_error_hpa(hpa)) |
1783 | printk(KERN_ERR "audit: (%s) notrap shadow," | 2245 | printk(KERN_ERR "audit: (%s) notrap shadow," |
1784 | " valid guest gva %lx\n", audit_msg, va); | 2246 | " valid guest gva %lx\n", audit_msg, va); |
1785 | kvm_release_page_clean(page); | 2247 | kvm_release_pfn_clean(pfn); |
1786 | 2248 | ||
1787 | } | 2249 | } |
1788 | } | 2250 | } |
@@ -1867,7 +2329,7 @@ static void audit_rmap(struct kvm_vcpu *vcpu) | |||
1867 | 2329 | ||
1868 | if (n_rmap != n_actual) | 2330 | if (n_rmap != n_actual) |
1869 | printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", | 2331 | printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", |
1870 | __FUNCTION__, audit_msg, n_rmap, n_actual); | 2332 | __func__, audit_msg, n_rmap, n_actual); |
1871 | } | 2333 | } |
1872 | 2334 | ||
1873 | static void audit_write_protection(struct kvm_vcpu *vcpu) | 2335 | static void audit_write_protection(struct kvm_vcpu *vcpu) |
@@ -1887,7 +2349,7 @@ static void audit_write_protection(struct kvm_vcpu *vcpu) | |||
1887 | if (*rmapp) | 2349 | if (*rmapp) |
1888 | printk(KERN_ERR "%s: (%s) shadow page has writable" | 2350 | printk(KERN_ERR "%s: (%s) shadow page has writable" |
1889 | " mappings: gfn %lx role %x\n", | 2351 | " mappings: gfn %lx role %x\n", |
1890 | __FUNCTION__, audit_msg, sp->gfn, | 2352 | __func__, audit_msg, sp->gfn, |
1891 | sp->role.word); | 2353 | sp->role.word); |
1892 | } | 2354 | } |
1893 | } | 2355 | } |
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 1fce19ec7a23..e64e9f56a65e 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h | |||
@@ -3,6 +3,12 @@ | |||
3 | 3 | ||
4 | #include <linux/kvm_host.h> | 4 | #include <linux/kvm_host.h> |
5 | 5 | ||
6 | #ifdef CONFIG_X86_64 | ||
7 | #define TDP_ROOT_LEVEL PT64_ROOT_LEVEL | ||
8 | #else | ||
9 | #define TDP_ROOT_LEVEL PT32E_ROOT_LEVEL | ||
10 | #endif | ||
11 | |||
6 | static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) | 12 | static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) |
7 | { | 13 | { |
8 | if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) | 14 | if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index ecc0856268c4..156fe10288ae 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -130,7 +130,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, | |||
130 | unsigned index, pt_access, pte_access; | 130 | unsigned index, pt_access, pte_access; |
131 | gpa_t pte_gpa; | 131 | gpa_t pte_gpa; |
132 | 132 | ||
133 | pgprintk("%s: addr %lx\n", __FUNCTION__, addr); | 133 | pgprintk("%s: addr %lx\n", __func__, addr); |
134 | walk: | 134 | walk: |
135 | walker->level = vcpu->arch.mmu.root_level; | 135 | walker->level = vcpu->arch.mmu.root_level; |
136 | pte = vcpu->arch.cr3; | 136 | pte = vcpu->arch.cr3; |
@@ -155,7 +155,7 @@ walk: | |||
155 | pte_gpa += index * sizeof(pt_element_t); | 155 | pte_gpa += index * sizeof(pt_element_t); |
156 | walker->table_gfn[walker->level - 1] = table_gfn; | 156 | walker->table_gfn[walker->level - 1] = table_gfn; |
157 | walker->pte_gpa[walker->level - 1] = pte_gpa; | 157 | walker->pte_gpa[walker->level - 1] = pte_gpa; |
158 | pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, | 158 | pgprintk("%s: table_gfn[%d] %lx\n", __func__, |
159 | walker->level - 1, table_gfn); | 159 | walker->level - 1, table_gfn); |
160 | 160 | ||
161 | kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)); | 161 | kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)); |
@@ -222,7 +222,7 @@ walk: | |||
222 | walker->pt_access = pt_access; | 222 | walker->pt_access = pt_access; |
223 | walker->pte_access = pte_access; | 223 | walker->pte_access = pte_access; |
224 | pgprintk("%s: pte %llx pte_access %x pt_access %x\n", | 224 | pgprintk("%s: pte %llx pte_access %x pt_access %x\n", |
225 | __FUNCTION__, (u64)pte, pt_access, pte_access); | 225 | __func__, (u64)pte, pt_access, pte_access); |
226 | return 1; | 226 | return 1; |
227 | 227 | ||
228 | not_present: | 228 | not_present: |
@@ -243,31 +243,30 @@ err: | |||
243 | } | 243 | } |
244 | 244 | ||
245 | static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | 245 | static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, |
246 | u64 *spte, const void *pte, int bytes, | 246 | u64 *spte, const void *pte) |
247 | int offset_in_pte) | ||
248 | { | 247 | { |
249 | pt_element_t gpte; | 248 | pt_element_t gpte; |
250 | unsigned pte_access; | 249 | unsigned pte_access; |
251 | struct page *npage; | 250 | pfn_t pfn; |
251 | int largepage = vcpu->arch.update_pte.largepage; | ||
252 | 252 | ||
253 | gpte = *(const pt_element_t *)pte; | 253 | gpte = *(const pt_element_t *)pte; |
254 | if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { | 254 | if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { |
255 | if (!offset_in_pte && !is_present_pte(gpte)) | 255 | if (!is_present_pte(gpte)) |
256 | set_shadow_pte(spte, shadow_notrap_nonpresent_pte); | 256 | set_shadow_pte(spte, shadow_notrap_nonpresent_pte); |
257 | return; | 257 | return; |
258 | } | 258 | } |
259 | if (bytes < sizeof(pt_element_t)) | 259 | pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); |
260 | return; | ||
261 | pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); | ||
262 | pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte); | 260 | pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte); |
263 | if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn) | 261 | if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn) |
264 | return; | 262 | return; |
265 | npage = vcpu->arch.update_pte.page; | 263 | pfn = vcpu->arch.update_pte.pfn; |
266 | if (!npage) | 264 | if (is_error_pfn(pfn)) |
267 | return; | 265 | return; |
268 | get_page(npage); | 266 | kvm_get_pfn(pfn); |
269 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, | 267 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, |
270 | gpte & PT_DIRTY_MASK, NULL, gpte_to_gfn(gpte), npage); | 268 | gpte & PT_DIRTY_MASK, NULL, largepage, gpte_to_gfn(gpte), |
269 | pfn, true); | ||
271 | } | 270 | } |
272 | 271 | ||
273 | /* | 272 | /* |
@@ -275,8 +274,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | |||
275 | */ | 274 | */ |
276 | static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | 275 | static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, |
277 | struct guest_walker *walker, | 276 | struct guest_walker *walker, |
278 | int user_fault, int write_fault, int *ptwrite, | 277 | int user_fault, int write_fault, int largepage, |
279 | struct page *page) | 278 | int *ptwrite, pfn_t pfn) |
280 | { | 279 | { |
281 | hpa_t shadow_addr; | 280 | hpa_t shadow_addr; |
282 | int level; | 281 | int level; |
@@ -304,11 +303,19 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
304 | shadow_ent = ((u64 *)__va(shadow_addr)) + index; | 303 | shadow_ent = ((u64 *)__va(shadow_addr)) + index; |
305 | if (level == PT_PAGE_TABLE_LEVEL) | 304 | if (level == PT_PAGE_TABLE_LEVEL) |
306 | break; | 305 | break; |
307 | if (is_shadow_present_pte(*shadow_ent)) { | 306 | |
307 | if (largepage && level == PT_DIRECTORY_LEVEL) | ||
308 | break; | ||
309 | |||
310 | if (is_shadow_present_pte(*shadow_ent) | ||
311 | && !is_large_pte(*shadow_ent)) { | ||
308 | shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK; | 312 | shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK; |
309 | continue; | 313 | continue; |
310 | } | 314 | } |
311 | 315 | ||
316 | if (is_large_pte(*shadow_ent)) | ||
317 | rmap_remove(vcpu->kvm, shadow_ent); | ||
318 | |||
312 | if (level - 1 == PT_PAGE_TABLE_LEVEL | 319 | if (level - 1 == PT_PAGE_TABLE_LEVEL |
313 | && walker->level == PT_DIRECTORY_LEVEL) { | 320 | && walker->level == PT_DIRECTORY_LEVEL) { |
314 | metaphysical = 1; | 321 | metaphysical = 1; |
@@ -329,7 +336,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
329 | walker->pte_gpa[level - 2], | 336 | walker->pte_gpa[level - 2], |
330 | &curr_pte, sizeof(curr_pte)); | 337 | &curr_pte, sizeof(curr_pte)); |
331 | if (r || curr_pte != walker->ptes[level - 2]) { | 338 | if (r || curr_pte != walker->ptes[level - 2]) { |
332 | kvm_release_page_clean(page); | 339 | kvm_release_pfn_clean(pfn); |
333 | return NULL; | 340 | return NULL; |
334 | } | 341 | } |
335 | } | 342 | } |
@@ -342,7 +349,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
342 | mmu_set_spte(vcpu, shadow_ent, access, walker->pte_access & access, | 349 | mmu_set_spte(vcpu, shadow_ent, access, walker->pte_access & access, |
343 | user_fault, write_fault, | 350 | user_fault, write_fault, |
344 | walker->ptes[walker->level-1] & PT_DIRTY_MASK, | 351 | walker->ptes[walker->level-1] & PT_DIRTY_MASK, |
345 | ptwrite, walker->gfn, page); | 352 | ptwrite, largepage, walker->gfn, pfn, false); |
346 | 353 | ||
347 | return shadow_ent; | 354 | return shadow_ent; |
348 | } | 355 | } |
@@ -371,16 +378,16 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
371 | u64 *shadow_pte; | 378 | u64 *shadow_pte; |
372 | int write_pt = 0; | 379 | int write_pt = 0; |
373 | int r; | 380 | int r; |
374 | struct page *page; | 381 | pfn_t pfn; |
382 | int largepage = 0; | ||
375 | 383 | ||
376 | pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code); | 384 | pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code); |
377 | kvm_mmu_audit(vcpu, "pre page fault"); | 385 | kvm_mmu_audit(vcpu, "pre page fault"); |
378 | 386 | ||
379 | r = mmu_topup_memory_caches(vcpu); | 387 | r = mmu_topup_memory_caches(vcpu); |
380 | if (r) | 388 | if (r) |
381 | return r; | 389 | return r; |
382 | 390 | ||
383 | down_read(&vcpu->kvm->slots_lock); | ||
384 | /* | 391 | /* |
385 | * Look up the shadow pte for the faulting address. | 392 | * Look up the shadow pte for the faulting address. |
386 | */ | 393 | */ |
@@ -391,40 +398,45 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, | |||
391 | * The page is not mapped by the guest. Let the guest handle it. | 398 | * The page is not mapped by the guest. Let the guest handle it. |
392 | */ | 399 | */ |
393 | if (!r) { | 400 | if (!r) { |
394 | pgprintk("%s: guest page fault\n", __FUNCTION__); | 401 | pgprintk("%s: guest page fault\n", __func__); |
395 | inject_page_fault(vcpu, addr, walker.error_code); | 402 | inject_page_fault(vcpu, addr, walker.error_code); |
396 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ | 403 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ |
397 | up_read(&vcpu->kvm->slots_lock); | ||
398 | return 0; | 404 | return 0; |
399 | } | 405 | } |
400 | 406 | ||
401 | down_read(¤t->mm->mmap_sem); | 407 | down_read(¤t->mm->mmap_sem); |
402 | page = gfn_to_page(vcpu->kvm, walker.gfn); | 408 | if (walker.level == PT_DIRECTORY_LEVEL) { |
409 | gfn_t large_gfn; | ||
410 | large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1); | ||
411 | if (is_largepage_backed(vcpu, large_gfn)) { | ||
412 | walker.gfn = large_gfn; | ||
413 | largepage = 1; | ||
414 | } | ||
415 | } | ||
416 | pfn = gfn_to_pfn(vcpu->kvm, walker.gfn); | ||
403 | up_read(¤t->mm->mmap_sem); | 417 | up_read(¤t->mm->mmap_sem); |
404 | 418 | ||
419 | /* mmio */ | ||
420 | if (is_error_pfn(pfn)) { | ||
421 | pgprintk("gfn %x is mmio\n", walker.gfn); | ||
422 | kvm_release_pfn_clean(pfn); | ||
423 | return 1; | ||
424 | } | ||
425 | |||
405 | spin_lock(&vcpu->kvm->mmu_lock); | 426 | spin_lock(&vcpu->kvm->mmu_lock); |
406 | kvm_mmu_free_some_pages(vcpu); | 427 | kvm_mmu_free_some_pages(vcpu); |
407 | shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, | 428 | shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, |
408 | &write_pt, page); | 429 | largepage, &write_pt, pfn); |
409 | pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__, | 430 | |
431 | pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__, | ||
410 | shadow_pte, *shadow_pte, write_pt); | 432 | shadow_pte, *shadow_pte, write_pt); |
411 | 433 | ||
412 | if (!write_pt) | 434 | if (!write_pt) |
413 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ | 435 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ |
414 | 436 | ||
415 | /* | ||
416 | * mmio: emulate if accessible, otherwise its a guest fault. | ||
417 | */ | ||
418 | if (shadow_pte && is_io_pte(*shadow_pte)) { | ||
419 | spin_unlock(&vcpu->kvm->mmu_lock); | ||
420 | up_read(&vcpu->kvm->slots_lock); | ||
421 | return 1; | ||
422 | } | ||
423 | |||
424 | ++vcpu->stat.pf_fixed; | 437 | ++vcpu->stat.pf_fixed; |
425 | kvm_mmu_audit(vcpu, "post page fault (fixed)"); | 438 | kvm_mmu_audit(vcpu, "post page fault (fixed)"); |
426 | spin_unlock(&vcpu->kvm->mmu_lock); | 439 | spin_unlock(&vcpu->kvm->mmu_lock); |
427 | up_read(&vcpu->kvm->slots_lock); | ||
428 | 440 | ||
429 | return write_pt; | 441 | return write_pt; |
430 | } | 442 | } |
diff --git a/arch/x86/kvm/segment_descriptor.h b/arch/x86/kvm/segment_descriptor.h deleted file mode 100644 index 56fc4c873389..000000000000 --- a/arch/x86/kvm/segment_descriptor.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | #ifndef __SEGMENT_DESCRIPTOR_H | ||
2 | #define __SEGMENT_DESCRIPTOR_H | ||
3 | |||
4 | struct segment_descriptor { | ||
5 | u16 limit_low; | ||
6 | u16 base_low; | ||
7 | u8 base_mid; | ||
8 | u8 type : 4; | ||
9 | u8 system : 1; | ||
10 | u8 dpl : 2; | ||
11 | u8 present : 1; | ||
12 | u8 limit_high : 4; | ||
13 | u8 avl : 1; | ||
14 | u8 long_mode : 1; | ||
15 | u8 default_op : 1; | ||
16 | u8 granularity : 1; | ||
17 | u8 base_high; | ||
18 | } __attribute__((packed)); | ||
19 | |||
20 | #ifdef CONFIG_X86_64 | ||
21 | /* LDT or TSS descriptor in the GDT. 16 bytes. */ | ||
22 | struct segment_descriptor_64 { | ||
23 | struct segment_descriptor s; | ||
24 | u32 base_higher; | ||
25 | u32 pad_zero; | ||
26 | }; | ||
27 | |||
28 | #endif | ||
29 | #endif | ||
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 1a582f1090e8..89e0be2c10d0 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -47,6 +47,18 @@ MODULE_LICENSE("GPL"); | |||
47 | #define SVM_FEATURE_LBRV (1 << 1) | 47 | #define SVM_FEATURE_LBRV (1 << 1) |
48 | #define SVM_DEATURE_SVML (1 << 2) | 48 | #define SVM_DEATURE_SVML (1 << 2) |
49 | 49 | ||
50 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) | ||
51 | |||
52 | /* enable NPT for AMD64 and X86 with PAE */ | ||
53 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) | ||
54 | static bool npt_enabled = true; | ||
55 | #else | ||
56 | static bool npt_enabled = false; | ||
57 | #endif | ||
58 | static int npt = 1; | ||
59 | |||
60 | module_param(npt, int, S_IRUGO); | ||
61 | |||
50 | static void kvm_reput_irq(struct vcpu_svm *svm); | 62 | static void kvm_reput_irq(struct vcpu_svm *svm); |
51 | 63 | ||
52 | static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) | 64 | static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) |
@@ -54,8 +66,7 @@ static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) | |||
54 | return container_of(vcpu, struct vcpu_svm, vcpu); | 66 | return container_of(vcpu, struct vcpu_svm, vcpu); |
55 | } | 67 | } |
56 | 68 | ||
57 | unsigned long iopm_base; | 69 | static unsigned long iopm_base; |
58 | unsigned long msrpm_base; | ||
59 | 70 | ||
60 | struct kvm_ldttss_desc { | 71 | struct kvm_ldttss_desc { |
61 | u16 limit0; | 72 | u16 limit0; |
@@ -182,7 +193,7 @@ static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) | |||
182 | 193 | ||
183 | static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) | 194 | static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) |
184 | { | 195 | { |
185 | if (!(efer & EFER_LMA)) | 196 | if (!npt_enabled && !(efer & EFER_LMA)) |
186 | efer &= ~EFER_LME; | 197 | efer &= ~EFER_LME; |
187 | 198 | ||
188 | to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; | 199 | to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; |
@@ -219,12 +230,12 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | |||
219 | struct vcpu_svm *svm = to_svm(vcpu); | 230 | struct vcpu_svm *svm = to_svm(vcpu); |
220 | 231 | ||
221 | if (!svm->next_rip) { | 232 | if (!svm->next_rip) { |
222 | printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); | 233 | printk(KERN_DEBUG "%s: NOP\n", __func__); |
223 | return; | 234 | return; |
224 | } | 235 | } |
225 | if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) | 236 | if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) |
226 | printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", | 237 | printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", |
227 | __FUNCTION__, | 238 | __func__, |
228 | svm->vmcb->save.rip, | 239 | svm->vmcb->save.rip, |
229 | svm->next_rip); | 240 | svm->next_rip); |
230 | 241 | ||
@@ -279,11 +290,7 @@ static void svm_hardware_enable(void *garbage) | |||
279 | 290 | ||
280 | struct svm_cpu_data *svm_data; | 291 | struct svm_cpu_data *svm_data; |
281 | uint64_t efer; | 292 | uint64_t efer; |
282 | #ifdef CONFIG_X86_64 | ||
283 | struct desc_ptr gdt_descr; | ||
284 | #else | ||
285 | struct desc_ptr gdt_descr; | 293 | struct desc_ptr gdt_descr; |
286 | #endif | ||
287 | struct desc_struct *gdt; | 294 | struct desc_struct *gdt; |
288 | int me = raw_smp_processor_id(); | 295 | int me = raw_smp_processor_id(); |
289 | 296 | ||
@@ -302,7 +309,6 @@ static void svm_hardware_enable(void *garbage) | |||
302 | svm_data->asid_generation = 1; | 309 | svm_data->asid_generation = 1; |
303 | svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; | 310 | svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; |
304 | svm_data->next_asid = svm_data->max_asid + 1; | 311 | svm_data->next_asid = svm_data->max_asid + 1; |
305 | svm_features = cpuid_edx(SVM_CPUID_FUNC); | ||
306 | 312 | ||
307 | asm volatile ("sgdt %0" : "=m"(gdt_descr)); | 313 | asm volatile ("sgdt %0" : "=m"(gdt_descr)); |
308 | gdt = (struct desc_struct *)gdt_descr.address; | 314 | gdt = (struct desc_struct *)gdt_descr.address; |
@@ -361,12 +367,51 @@ static void set_msr_interception(u32 *msrpm, unsigned msr, | |||
361 | BUG(); | 367 | BUG(); |
362 | } | 368 | } |
363 | 369 | ||
370 | static void svm_vcpu_init_msrpm(u32 *msrpm) | ||
371 | { | ||
372 | memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); | ||
373 | |||
374 | #ifdef CONFIG_X86_64 | ||
375 | set_msr_interception(msrpm, MSR_GS_BASE, 1, 1); | ||
376 | set_msr_interception(msrpm, MSR_FS_BASE, 1, 1); | ||
377 | set_msr_interception(msrpm, MSR_KERNEL_GS_BASE, 1, 1); | ||
378 | set_msr_interception(msrpm, MSR_LSTAR, 1, 1); | ||
379 | set_msr_interception(msrpm, MSR_CSTAR, 1, 1); | ||
380 | set_msr_interception(msrpm, MSR_SYSCALL_MASK, 1, 1); | ||
381 | #endif | ||
382 | set_msr_interception(msrpm, MSR_K6_STAR, 1, 1); | ||
383 | set_msr_interception(msrpm, MSR_IA32_SYSENTER_CS, 1, 1); | ||
384 | set_msr_interception(msrpm, MSR_IA32_SYSENTER_ESP, 1, 1); | ||
385 | set_msr_interception(msrpm, MSR_IA32_SYSENTER_EIP, 1, 1); | ||
386 | } | ||
387 | |||
388 | static void svm_enable_lbrv(struct vcpu_svm *svm) | ||
389 | { | ||
390 | u32 *msrpm = svm->msrpm; | ||
391 | |||
392 | svm->vmcb->control.lbr_ctl = 1; | ||
393 | set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1); | ||
394 | set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1); | ||
395 | set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); | ||
396 | set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 1, 1); | ||
397 | } | ||
398 | |||
399 | static void svm_disable_lbrv(struct vcpu_svm *svm) | ||
400 | { | ||
401 | u32 *msrpm = svm->msrpm; | ||
402 | |||
403 | svm->vmcb->control.lbr_ctl = 0; | ||
404 | set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0); | ||
405 | set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0); | ||
406 | set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 0, 0); | ||
407 | set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0); | ||
408 | } | ||
409 | |||
364 | static __init int svm_hardware_setup(void) | 410 | static __init int svm_hardware_setup(void) |
365 | { | 411 | { |
366 | int cpu; | 412 | int cpu; |
367 | struct page *iopm_pages; | 413 | struct page *iopm_pages; |
368 | struct page *msrpm_pages; | 414 | void *iopm_va; |
369 | void *iopm_va, *msrpm_va; | ||
370 | int r; | 415 | int r; |
371 | 416 | ||
372 | iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); | 417 | iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); |
@@ -379,41 +424,33 @@ static __init int svm_hardware_setup(void) | |||
379 | clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */ | 424 | clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */ |
380 | iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; | 425 | iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; |
381 | 426 | ||
427 | if (boot_cpu_has(X86_FEATURE_NX)) | ||
428 | kvm_enable_efer_bits(EFER_NX); | ||
382 | 429 | ||
383 | msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); | 430 | for_each_online_cpu(cpu) { |
431 | r = svm_cpu_init(cpu); | ||
432 | if (r) | ||
433 | goto err; | ||
434 | } | ||
384 | 435 | ||
385 | r = -ENOMEM; | 436 | svm_features = cpuid_edx(SVM_CPUID_FUNC); |
386 | if (!msrpm_pages) | ||
387 | goto err_1; | ||
388 | 437 | ||
389 | msrpm_va = page_address(msrpm_pages); | 438 | if (!svm_has(SVM_FEATURE_NPT)) |
390 | memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); | 439 | npt_enabled = false; |
391 | msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT; | ||
392 | 440 | ||
393 | #ifdef CONFIG_X86_64 | 441 | if (npt_enabled && !npt) { |
394 | set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1); | 442 | printk(KERN_INFO "kvm: Nested Paging disabled\n"); |
395 | set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1); | 443 | npt_enabled = false; |
396 | set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1); | 444 | } |
397 | set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1); | ||
398 | set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1); | ||
399 | set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1); | ||
400 | #endif | ||
401 | set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1); | ||
402 | set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1); | ||
403 | set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1); | ||
404 | set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1); | ||
405 | 445 | ||
406 | for_each_online_cpu(cpu) { | 446 | if (npt_enabled) { |
407 | r = svm_cpu_init(cpu); | 447 | printk(KERN_INFO "kvm: Nested Paging enabled\n"); |
408 | if (r) | 448 | kvm_enable_tdp(); |
409 | goto err_2; | ||
410 | } | 449 | } |
450 | |||
411 | return 0; | 451 | return 0; |
412 | 452 | ||
413 | err_2: | 453 | err: |
414 | __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER); | ||
415 | msrpm_base = 0; | ||
416 | err_1: | ||
417 | __free_pages(iopm_pages, IOPM_ALLOC_ORDER); | 454 | __free_pages(iopm_pages, IOPM_ALLOC_ORDER); |
418 | iopm_base = 0; | 455 | iopm_base = 0; |
419 | return r; | 456 | return r; |
@@ -421,9 +458,8 @@ err_1: | |||
421 | 458 | ||
422 | static __exit void svm_hardware_unsetup(void) | 459 | static __exit void svm_hardware_unsetup(void) |
423 | { | 460 | { |
424 | __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER); | ||
425 | __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); | 461 | __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); |
426 | iopm_base = msrpm_base = 0; | 462 | iopm_base = 0; |
427 | } | 463 | } |
428 | 464 | ||
429 | static void init_seg(struct vmcb_seg *seg) | 465 | static void init_seg(struct vmcb_seg *seg) |
@@ -443,15 +479,14 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) | |||
443 | seg->base = 0; | 479 | seg->base = 0; |
444 | } | 480 | } |
445 | 481 | ||
446 | static void init_vmcb(struct vmcb *vmcb) | 482 | static void init_vmcb(struct vcpu_svm *svm) |
447 | { | 483 | { |
448 | struct vmcb_control_area *control = &vmcb->control; | 484 | struct vmcb_control_area *control = &svm->vmcb->control; |
449 | struct vmcb_save_area *save = &vmcb->save; | 485 | struct vmcb_save_area *save = &svm->vmcb->save; |
450 | 486 | ||
451 | control->intercept_cr_read = INTERCEPT_CR0_MASK | | 487 | control->intercept_cr_read = INTERCEPT_CR0_MASK | |
452 | INTERCEPT_CR3_MASK | | 488 | INTERCEPT_CR3_MASK | |
453 | INTERCEPT_CR4_MASK | | 489 | INTERCEPT_CR4_MASK; |
454 | INTERCEPT_CR8_MASK; | ||
455 | 490 | ||
456 | control->intercept_cr_write = INTERCEPT_CR0_MASK | | 491 | control->intercept_cr_write = INTERCEPT_CR0_MASK | |
457 | INTERCEPT_CR3_MASK | | 492 | INTERCEPT_CR3_MASK | |
@@ -471,23 +506,13 @@ static void init_vmcb(struct vmcb *vmcb) | |||
471 | INTERCEPT_DR7_MASK; | 506 | INTERCEPT_DR7_MASK; |
472 | 507 | ||
473 | control->intercept_exceptions = (1 << PF_VECTOR) | | 508 | control->intercept_exceptions = (1 << PF_VECTOR) | |
474 | (1 << UD_VECTOR); | 509 | (1 << UD_VECTOR) | |
510 | (1 << MC_VECTOR); | ||
475 | 511 | ||
476 | 512 | ||
477 | control->intercept = (1ULL << INTERCEPT_INTR) | | 513 | control->intercept = (1ULL << INTERCEPT_INTR) | |
478 | (1ULL << INTERCEPT_NMI) | | 514 | (1ULL << INTERCEPT_NMI) | |
479 | (1ULL << INTERCEPT_SMI) | | 515 | (1ULL << INTERCEPT_SMI) | |
480 | /* | ||
481 | * selective cr0 intercept bug? | ||
482 | * 0: 0f 22 d8 mov %eax,%cr3 | ||
483 | * 3: 0f 20 c0 mov %cr0,%eax | ||
484 | * 6: 0d 00 00 00 80 or $0x80000000,%eax | ||
485 | * b: 0f 22 c0 mov %eax,%cr0 | ||
486 | * set cr3 ->interception | ||
487 | * get cr0 ->interception | ||
488 | * set cr0 -> no interception | ||
489 | */ | ||
490 | /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ | ||
491 | (1ULL << INTERCEPT_CPUID) | | 516 | (1ULL << INTERCEPT_CPUID) | |
492 | (1ULL << INTERCEPT_INVD) | | 517 | (1ULL << INTERCEPT_INVD) | |
493 | (1ULL << INTERCEPT_HLT) | | 518 | (1ULL << INTERCEPT_HLT) | |
@@ -508,7 +533,7 @@ static void init_vmcb(struct vmcb *vmcb) | |||
508 | (1ULL << INTERCEPT_MWAIT); | 533 | (1ULL << INTERCEPT_MWAIT); |
509 | 534 | ||
510 | control->iopm_base_pa = iopm_base; | 535 | control->iopm_base_pa = iopm_base; |
511 | control->msrpm_base_pa = msrpm_base; | 536 | control->msrpm_base_pa = __pa(svm->msrpm); |
512 | control->tsc_offset = 0; | 537 | control->tsc_offset = 0; |
513 | control->int_ctl = V_INTR_MASKING_MASK; | 538 | control->int_ctl = V_INTR_MASKING_MASK; |
514 | 539 | ||
@@ -550,13 +575,30 @@ static void init_vmcb(struct vmcb *vmcb) | |||
550 | save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; | 575 | save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; |
551 | save->cr4 = X86_CR4_PAE; | 576 | save->cr4 = X86_CR4_PAE; |
552 | /* rdx = ?? */ | 577 | /* rdx = ?? */ |
578 | |||
579 | if (npt_enabled) { | ||
580 | /* Setup VMCB for Nested Paging */ | ||
581 | control->nested_ctl = 1; | ||
582 | control->intercept &= ~(1ULL << INTERCEPT_TASK_SWITCH); | ||
583 | control->intercept_exceptions &= ~(1 << PF_VECTOR); | ||
584 | control->intercept_cr_read &= ~(INTERCEPT_CR0_MASK| | ||
585 | INTERCEPT_CR3_MASK); | ||
586 | control->intercept_cr_write &= ~(INTERCEPT_CR0_MASK| | ||
587 | INTERCEPT_CR3_MASK); | ||
588 | save->g_pat = 0x0007040600070406ULL; | ||
589 | /* enable caching because the QEMU Bios doesn't enable it */ | ||
590 | save->cr0 = X86_CR0_ET; | ||
591 | save->cr3 = 0; | ||
592 | save->cr4 = 0; | ||
593 | } | ||
594 | force_new_asid(&svm->vcpu); | ||
553 | } | 595 | } |
554 | 596 | ||
555 | static int svm_vcpu_reset(struct kvm_vcpu *vcpu) | 597 | static int svm_vcpu_reset(struct kvm_vcpu *vcpu) |
556 | { | 598 | { |
557 | struct vcpu_svm *svm = to_svm(vcpu); | 599 | struct vcpu_svm *svm = to_svm(vcpu); |
558 | 600 | ||
559 | init_vmcb(svm->vmcb); | 601 | init_vmcb(svm); |
560 | 602 | ||
561 | if (vcpu->vcpu_id != 0) { | 603 | if (vcpu->vcpu_id != 0) { |
562 | svm->vmcb->save.rip = 0; | 604 | svm->vmcb->save.rip = 0; |
@@ -571,6 +613,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
571 | { | 613 | { |
572 | struct vcpu_svm *svm; | 614 | struct vcpu_svm *svm; |
573 | struct page *page; | 615 | struct page *page; |
616 | struct page *msrpm_pages; | ||
574 | int err; | 617 | int err; |
575 | 618 | ||
576 | svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); | 619 | svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); |
@@ -589,12 +632,19 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
589 | goto uninit; | 632 | goto uninit; |
590 | } | 633 | } |
591 | 634 | ||
635 | err = -ENOMEM; | ||
636 | msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); | ||
637 | if (!msrpm_pages) | ||
638 | goto uninit; | ||
639 | svm->msrpm = page_address(msrpm_pages); | ||
640 | svm_vcpu_init_msrpm(svm->msrpm); | ||
641 | |||
592 | svm->vmcb = page_address(page); | 642 | svm->vmcb = page_address(page); |
593 | clear_page(svm->vmcb); | 643 | clear_page(svm->vmcb); |
594 | svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; | 644 | svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; |
595 | svm->asid_generation = 0; | 645 | svm->asid_generation = 0; |
596 | memset(svm->db_regs, 0, sizeof(svm->db_regs)); | 646 | memset(svm->db_regs, 0, sizeof(svm->db_regs)); |
597 | init_vmcb(svm->vmcb); | 647 | init_vmcb(svm); |
598 | 648 | ||
599 | fx_init(&svm->vcpu); | 649 | fx_init(&svm->vcpu); |
600 | svm->vcpu.fpu_active = 1; | 650 | svm->vcpu.fpu_active = 1; |
@@ -617,6 +667,7 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu) | |||
617 | struct vcpu_svm *svm = to_svm(vcpu); | 667 | struct vcpu_svm *svm = to_svm(vcpu); |
618 | 668 | ||
619 | __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); | 669 | __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); |
670 | __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER); | ||
620 | kvm_vcpu_uninit(vcpu); | 671 | kvm_vcpu_uninit(vcpu); |
621 | kmem_cache_free(kvm_vcpu_cache, svm); | 672 | kmem_cache_free(kvm_vcpu_cache, svm); |
622 | } | 673 | } |
@@ -731,6 +782,13 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, | |||
731 | var->unusable = !var->present; | 782 | var->unusable = !var->present; |
732 | } | 783 | } |
733 | 784 | ||
785 | static int svm_get_cpl(struct kvm_vcpu *vcpu) | ||
786 | { | ||
787 | struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; | ||
788 | |||
789 | return save->cpl; | ||
790 | } | ||
791 | |||
734 | static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | 792 | static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) |
735 | { | 793 | { |
736 | struct vcpu_svm *svm = to_svm(vcpu); | 794 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -784,6 +842,9 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
784 | } | 842 | } |
785 | } | 843 | } |
786 | #endif | 844 | #endif |
845 | if (npt_enabled) | ||
846 | goto set; | ||
847 | |||
787 | if ((vcpu->arch.cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { | 848 | if ((vcpu->arch.cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { |
788 | svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); | 849 | svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); |
789 | vcpu->fpu_active = 1; | 850 | vcpu->fpu_active = 1; |
@@ -791,18 +852,29 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
791 | 852 | ||
792 | vcpu->arch.cr0 = cr0; | 853 | vcpu->arch.cr0 = cr0; |
793 | cr0 |= X86_CR0_PG | X86_CR0_WP; | 854 | cr0 |= X86_CR0_PG | X86_CR0_WP; |
794 | cr0 &= ~(X86_CR0_CD | X86_CR0_NW); | ||
795 | if (!vcpu->fpu_active) { | 855 | if (!vcpu->fpu_active) { |
796 | svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); | 856 | svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); |
797 | cr0 |= X86_CR0_TS; | 857 | cr0 |= X86_CR0_TS; |
798 | } | 858 | } |
859 | set: | ||
860 | /* | ||
861 | * re-enable caching here because the QEMU bios | ||
862 | * does not do it - this results in some delay at | ||
863 | * reboot | ||
864 | */ | ||
865 | cr0 &= ~(X86_CR0_CD | X86_CR0_NW); | ||
799 | svm->vmcb->save.cr0 = cr0; | 866 | svm->vmcb->save.cr0 = cr0; |
800 | } | 867 | } |
801 | 868 | ||
802 | static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | 869 | static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) |
803 | { | 870 | { |
804 | vcpu->arch.cr4 = cr4; | 871 | unsigned long host_cr4_mce = read_cr4() & X86_CR4_MCE; |
805 | to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE; | 872 | |
873 | vcpu->arch.cr4 = cr4; | ||
874 | if (!npt_enabled) | ||
875 | cr4 |= X86_CR4_PAE; | ||
876 | cr4 |= host_cr4_mce; | ||
877 | to_svm(vcpu)->vmcb->save.cr4 = cr4; | ||
806 | } | 878 | } |
807 | 879 | ||
808 | static void svm_set_segment(struct kvm_vcpu *vcpu, | 880 | static void svm_set_segment(struct kvm_vcpu *vcpu, |
@@ -833,13 +905,6 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, | |||
833 | 905 | ||
834 | } | 906 | } |
835 | 907 | ||
836 | /* FIXME: | ||
837 | |||
838 | svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK; | ||
839 | svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); | ||
840 | |||
841 | */ | ||
842 | |||
843 | static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) | 908 | static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) |
844 | { | 909 | { |
845 | return -EOPNOTSUPP; | 910 | return -EOPNOTSUPP; |
@@ -920,7 +985,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, | |||
920 | } | 985 | } |
921 | default: | 986 | default: |
922 | printk(KERN_DEBUG "%s: unexpected dr %u\n", | 987 | printk(KERN_DEBUG "%s: unexpected dr %u\n", |
923 | __FUNCTION__, dr); | 988 | __func__, dr); |
924 | *exception = UD_VECTOR; | 989 | *exception = UD_VECTOR; |
925 | return; | 990 | return; |
926 | } | 991 | } |
@@ -962,6 +1027,19 @@ static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
962 | return 1; | 1027 | return 1; |
963 | } | 1028 | } |
964 | 1029 | ||
1030 | static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | ||
1031 | { | ||
1032 | /* | ||
1033 | * On an #MC intercept the MCE handler is not called automatically in | ||
1034 | * the host. So do it by hand here. | ||
1035 | */ | ||
1036 | asm volatile ( | ||
1037 | "int $0x12\n"); | ||
1038 | /* not sure if we ever come back to this point */ | ||
1039 | |||
1040 | return 1; | ||
1041 | } | ||
1042 | |||
965 | static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | 1043 | static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) |
966 | { | 1044 | { |
967 | /* | 1045 | /* |
@@ -969,7 +1047,7 @@ static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
969 | * so reinitialize it. | 1047 | * so reinitialize it. |
970 | */ | 1048 | */ |
971 | clear_page(svm->vmcb); | 1049 | clear_page(svm->vmcb); |
972 | init_vmcb(svm->vmcb); | 1050 | init_vmcb(svm); |
973 | 1051 | ||
974 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; | 1052 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; |
975 | return 0; | 1053 | return 0; |
@@ -1033,9 +1111,18 @@ static int invalid_op_interception(struct vcpu_svm *svm, | |||
1033 | static int task_switch_interception(struct vcpu_svm *svm, | 1111 | static int task_switch_interception(struct vcpu_svm *svm, |
1034 | struct kvm_run *kvm_run) | 1112 | struct kvm_run *kvm_run) |
1035 | { | 1113 | { |
1036 | pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__); | 1114 | u16 tss_selector; |
1037 | kvm_run->exit_reason = KVM_EXIT_UNKNOWN; | 1115 | |
1038 | return 0; | 1116 | tss_selector = (u16)svm->vmcb->control.exit_info_1; |
1117 | if (svm->vmcb->control.exit_info_2 & | ||
1118 | (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET)) | ||
1119 | return kvm_task_switch(&svm->vcpu, tss_selector, | ||
1120 | TASK_SWITCH_IRET); | ||
1121 | if (svm->vmcb->control.exit_info_2 & | ||
1122 | (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) | ||
1123 | return kvm_task_switch(&svm->vcpu, tss_selector, | ||
1124 | TASK_SWITCH_JMP); | ||
1125 | return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL); | ||
1039 | } | 1126 | } |
1040 | 1127 | ||
1041 | static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | 1128 | static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) |
@@ -1049,7 +1136,7 @@ static int emulate_on_interception(struct vcpu_svm *svm, | |||
1049 | struct kvm_run *kvm_run) | 1136 | struct kvm_run *kvm_run) |
1050 | { | 1137 | { |
1051 | if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE) | 1138 | if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE) |
1052 | pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); | 1139 | pr_unimpl(&svm->vcpu, "%s: failed\n", __func__); |
1053 | return 1; | 1140 | return 1; |
1054 | } | 1141 | } |
1055 | 1142 | ||
@@ -1179,8 +1266,19 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) | |||
1179 | svm->vmcb->save.sysenter_esp = data; | 1266 | svm->vmcb->save.sysenter_esp = data; |
1180 | break; | 1267 | break; |
1181 | case MSR_IA32_DEBUGCTLMSR: | 1268 | case MSR_IA32_DEBUGCTLMSR: |
1182 | pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n", | 1269 | if (!svm_has(SVM_FEATURE_LBRV)) { |
1183 | __FUNCTION__, data); | 1270 | pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n", |
1271 | __func__, data); | ||
1272 | break; | ||
1273 | } | ||
1274 | if (data & DEBUGCTL_RESERVED_BITS) | ||
1275 | return 1; | ||
1276 | |||
1277 | svm->vmcb->save.dbgctl = data; | ||
1278 | if (data & (1ULL<<0)) | ||
1279 | svm_enable_lbrv(svm); | ||
1280 | else | ||
1281 | svm_disable_lbrv(svm); | ||
1184 | break; | 1282 | break; |
1185 | case MSR_K7_EVNTSEL0: | 1283 | case MSR_K7_EVNTSEL0: |
1186 | case MSR_K7_EVNTSEL1: | 1284 | case MSR_K7_EVNTSEL1: |
@@ -1265,6 +1363,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, | |||
1265 | [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, | 1363 | [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, |
1266 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, | 1364 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, |
1267 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, | 1365 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, |
1366 | [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, | ||
1268 | [SVM_EXIT_INTR] = nop_on_interception, | 1367 | [SVM_EXIT_INTR] = nop_on_interception, |
1269 | [SVM_EXIT_NMI] = nop_on_interception, | 1368 | [SVM_EXIT_NMI] = nop_on_interception, |
1270 | [SVM_EXIT_SMI] = nop_on_interception, | 1369 | [SVM_EXIT_SMI] = nop_on_interception, |
@@ -1290,14 +1389,34 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, | |||
1290 | [SVM_EXIT_WBINVD] = emulate_on_interception, | 1389 | [SVM_EXIT_WBINVD] = emulate_on_interception, |
1291 | [SVM_EXIT_MONITOR] = invalid_op_interception, | 1390 | [SVM_EXIT_MONITOR] = invalid_op_interception, |
1292 | [SVM_EXIT_MWAIT] = invalid_op_interception, | 1391 | [SVM_EXIT_MWAIT] = invalid_op_interception, |
1392 | [SVM_EXIT_NPF] = pf_interception, | ||
1293 | }; | 1393 | }; |
1294 | 1394 | ||
1295 | |||
1296 | static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | 1395 | static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) |
1297 | { | 1396 | { |
1298 | struct vcpu_svm *svm = to_svm(vcpu); | 1397 | struct vcpu_svm *svm = to_svm(vcpu); |
1299 | u32 exit_code = svm->vmcb->control.exit_code; | 1398 | u32 exit_code = svm->vmcb->control.exit_code; |
1300 | 1399 | ||
1400 | if (npt_enabled) { | ||
1401 | int mmu_reload = 0; | ||
1402 | if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) { | ||
1403 | svm_set_cr0(vcpu, svm->vmcb->save.cr0); | ||
1404 | mmu_reload = 1; | ||
1405 | } | ||
1406 | vcpu->arch.cr0 = svm->vmcb->save.cr0; | ||
1407 | vcpu->arch.cr3 = svm->vmcb->save.cr3; | ||
1408 | if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) { | ||
1409 | if (!load_pdptrs(vcpu, vcpu->arch.cr3)) { | ||
1410 | kvm_inject_gp(vcpu, 0); | ||
1411 | return 1; | ||
1412 | } | ||
1413 | } | ||
1414 | if (mmu_reload) { | ||
1415 | kvm_mmu_reset_context(vcpu); | ||
1416 | kvm_mmu_load(vcpu); | ||
1417 | } | ||
1418 | } | ||
1419 | |||
1301 | kvm_reput_irq(svm); | 1420 | kvm_reput_irq(svm); |
1302 | 1421 | ||
1303 | if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { | 1422 | if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { |
@@ -1308,10 +1427,11 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
1308 | } | 1427 | } |
1309 | 1428 | ||
1310 | if (is_external_interrupt(svm->vmcb->control.exit_int_info) && | 1429 | if (is_external_interrupt(svm->vmcb->control.exit_int_info) && |
1311 | exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) | 1430 | exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR && |
1431 | exit_code != SVM_EXIT_NPF) | ||
1312 | printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " | 1432 | printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " |
1313 | "exit_code 0x%x\n", | 1433 | "exit_code 0x%x\n", |
1314 | __FUNCTION__, svm->vmcb->control.exit_int_info, | 1434 | __func__, svm->vmcb->control.exit_int_info, |
1315 | exit_code); | 1435 | exit_code); |
1316 | 1436 | ||
1317 | if (exit_code >= ARRAY_SIZE(svm_exit_handlers) | 1437 | if (exit_code >= ARRAY_SIZE(svm_exit_handlers) |
@@ -1364,6 +1484,27 @@ static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) | |||
1364 | svm_inject_irq(svm, irq); | 1484 | svm_inject_irq(svm, irq); |
1365 | } | 1485 | } |
1366 | 1486 | ||
1487 | static void update_cr8_intercept(struct kvm_vcpu *vcpu) | ||
1488 | { | ||
1489 | struct vcpu_svm *svm = to_svm(vcpu); | ||
1490 | struct vmcb *vmcb = svm->vmcb; | ||
1491 | int max_irr, tpr; | ||
1492 | |||
1493 | if (!irqchip_in_kernel(vcpu->kvm) || vcpu->arch.apic->vapic_addr) | ||
1494 | return; | ||
1495 | |||
1496 | vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK; | ||
1497 | |||
1498 | max_irr = kvm_lapic_find_highest_irr(vcpu); | ||
1499 | if (max_irr == -1) | ||
1500 | return; | ||
1501 | |||
1502 | tpr = kvm_lapic_get_cr8(vcpu) << 4; | ||
1503 | |||
1504 | if (tpr >= (max_irr & 0xf0)) | ||
1505 | vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK; | ||
1506 | } | ||
1507 | |||
1367 | static void svm_intr_assist(struct kvm_vcpu *vcpu) | 1508 | static void svm_intr_assist(struct kvm_vcpu *vcpu) |
1368 | { | 1509 | { |
1369 | struct vcpu_svm *svm = to_svm(vcpu); | 1510 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -1376,14 +1517,14 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) | |||
1376 | SVM_EVTINJ_VEC_MASK; | 1517 | SVM_EVTINJ_VEC_MASK; |
1377 | vmcb->control.exit_int_info = 0; | 1518 | vmcb->control.exit_int_info = 0; |
1378 | svm_inject_irq(svm, intr_vector); | 1519 | svm_inject_irq(svm, intr_vector); |
1379 | return; | 1520 | goto out; |
1380 | } | 1521 | } |
1381 | 1522 | ||
1382 | if (vmcb->control.int_ctl & V_IRQ_MASK) | 1523 | if (vmcb->control.int_ctl & V_IRQ_MASK) |
1383 | return; | 1524 | goto out; |
1384 | 1525 | ||
1385 | if (!kvm_cpu_has_interrupt(vcpu)) | 1526 | if (!kvm_cpu_has_interrupt(vcpu)) |
1386 | return; | 1527 | goto out; |
1387 | 1528 | ||
1388 | if (!(vmcb->save.rflags & X86_EFLAGS_IF) || | 1529 | if (!(vmcb->save.rflags & X86_EFLAGS_IF) || |
1389 | (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || | 1530 | (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || |
@@ -1391,12 +1532,14 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) | |||
1391 | /* unable to deliver irq, set pending irq */ | 1532 | /* unable to deliver irq, set pending irq */ |
1392 | vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); | 1533 | vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); |
1393 | svm_inject_irq(svm, 0x0); | 1534 | svm_inject_irq(svm, 0x0); |
1394 | return; | 1535 | goto out; |
1395 | } | 1536 | } |
1396 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ | 1537 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ |
1397 | intr_vector = kvm_cpu_get_interrupt(vcpu); | 1538 | intr_vector = kvm_cpu_get_interrupt(vcpu); |
1398 | svm_inject_irq(svm, intr_vector); | 1539 | svm_inject_irq(svm, intr_vector); |
1399 | kvm_timer_intr_post(vcpu, intr_vector); | 1540 | kvm_timer_intr_post(vcpu, intr_vector); |
1541 | out: | ||
1542 | update_cr8_intercept(vcpu); | ||
1400 | } | 1543 | } |
1401 | 1544 | ||
1402 | static void kvm_reput_irq(struct vcpu_svm *svm) | 1545 | static void kvm_reput_irq(struct vcpu_svm *svm) |
@@ -1482,6 +1625,29 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) | |||
1482 | { | 1625 | { |
1483 | } | 1626 | } |
1484 | 1627 | ||
1628 | static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) | ||
1629 | { | ||
1630 | struct vcpu_svm *svm = to_svm(vcpu); | ||
1631 | |||
1632 | if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) { | ||
1633 | int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK; | ||
1634 | kvm_lapic_set_tpr(vcpu, cr8); | ||
1635 | } | ||
1636 | } | ||
1637 | |||
1638 | static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) | ||
1639 | { | ||
1640 | struct vcpu_svm *svm = to_svm(vcpu); | ||
1641 | u64 cr8; | ||
1642 | |||
1643 | if (!irqchip_in_kernel(vcpu->kvm)) | ||
1644 | return; | ||
1645 | |||
1646 | cr8 = kvm_get_cr8(vcpu); | ||
1647 | svm->vmcb->control.int_ctl &= ~V_TPR_MASK; | ||
1648 | svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; | ||
1649 | } | ||
1650 | |||
1485 | static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1651 | static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
1486 | { | 1652 | { |
1487 | struct vcpu_svm *svm = to_svm(vcpu); | 1653 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -1491,6 +1657,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1491 | 1657 | ||
1492 | pre_svm_run(svm); | 1658 | pre_svm_run(svm); |
1493 | 1659 | ||
1660 | sync_lapic_to_cr8(vcpu); | ||
1661 | |||
1494 | save_host_msrs(vcpu); | 1662 | save_host_msrs(vcpu); |
1495 | fs_selector = read_fs(); | 1663 | fs_selector = read_fs(); |
1496 | gs_selector = read_gs(); | 1664 | gs_selector = read_gs(); |
@@ -1499,6 +1667,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1499 | svm->host_dr6 = read_dr6(); | 1667 | svm->host_dr6 = read_dr6(); |
1500 | svm->host_dr7 = read_dr7(); | 1668 | svm->host_dr7 = read_dr7(); |
1501 | svm->vmcb->save.cr2 = vcpu->arch.cr2; | 1669 | svm->vmcb->save.cr2 = vcpu->arch.cr2; |
1670 | /* required for live migration with NPT */ | ||
1671 | if (npt_enabled) | ||
1672 | svm->vmcb->save.cr3 = vcpu->arch.cr3; | ||
1502 | 1673 | ||
1503 | if (svm->vmcb->save.dr7 & 0xff) { | 1674 | if (svm->vmcb->save.dr7 & 0xff) { |
1504 | write_dr7(0); | 1675 | write_dr7(0); |
@@ -1635,6 +1806,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1635 | 1806 | ||
1636 | stgi(); | 1807 | stgi(); |
1637 | 1808 | ||
1809 | sync_cr8_to_lapic(vcpu); | ||
1810 | |||
1638 | svm->next_rip = 0; | 1811 | svm->next_rip = 0; |
1639 | } | 1812 | } |
1640 | 1813 | ||
@@ -1642,6 +1815,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) | |||
1642 | { | 1815 | { |
1643 | struct vcpu_svm *svm = to_svm(vcpu); | 1816 | struct vcpu_svm *svm = to_svm(vcpu); |
1644 | 1817 | ||
1818 | if (npt_enabled) { | ||
1819 | svm->vmcb->control.nested_cr3 = root; | ||
1820 | force_new_asid(vcpu); | ||
1821 | return; | ||
1822 | } | ||
1823 | |||
1645 | svm->vmcb->save.cr3 = root; | 1824 | svm->vmcb->save.cr3 = root; |
1646 | force_new_asid(vcpu); | 1825 | force_new_asid(vcpu); |
1647 | 1826 | ||
@@ -1709,6 +1888,7 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
1709 | .get_segment_base = svm_get_segment_base, | 1888 | .get_segment_base = svm_get_segment_base, |
1710 | .get_segment = svm_get_segment, | 1889 | .get_segment = svm_get_segment, |
1711 | .set_segment = svm_set_segment, | 1890 | .set_segment = svm_set_segment, |
1891 | .get_cpl = svm_get_cpl, | ||
1712 | .get_cs_db_l_bits = kvm_get_cs_db_l_bits, | 1892 | .get_cs_db_l_bits = kvm_get_cs_db_l_bits, |
1713 | .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, | 1893 | .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, |
1714 | .set_cr0 = svm_set_cr0, | 1894 | .set_cr0 = svm_set_cr0, |
diff --git a/arch/x86/kvm/svm.h b/arch/x86/kvm/svm.h index 5fd50491b555..1b8afa78e869 100644 --- a/arch/x86/kvm/svm.h +++ b/arch/x86/kvm/svm.h | |||
@@ -238,6 +238,9 @@ struct __attribute__ ((__packed__)) vmcb { | |||
238 | #define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID | 238 | #define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID |
239 | #define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR | 239 | #define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR |
240 | 240 | ||
241 | #define SVM_EXITINFOSHIFT_TS_REASON_IRET 36 | ||
242 | #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 | ||
243 | |||
241 | #define SVM_EXIT_READ_CR0 0x000 | 244 | #define SVM_EXIT_READ_CR0 0x000 |
242 | #define SVM_EXIT_READ_CR3 0x003 | 245 | #define SVM_EXIT_READ_CR3 0x003 |
243 | #define SVM_EXIT_READ_CR4 0x004 | 246 | #define SVM_EXIT_READ_CR4 0x004 |
diff --git a/arch/x86/kvm/tss.h b/arch/x86/kvm/tss.h new file mode 100644 index 000000000000..622aa10f692f --- /dev/null +++ b/arch/x86/kvm/tss.h | |||
@@ -0,0 +1,59 @@ | |||
1 | #ifndef __TSS_SEGMENT_H | ||
2 | #define __TSS_SEGMENT_H | ||
3 | |||
4 | struct tss_segment_32 { | ||
5 | u32 prev_task_link; | ||
6 | u32 esp0; | ||
7 | u32 ss0; | ||
8 | u32 esp1; | ||
9 | u32 ss1; | ||
10 | u32 esp2; | ||
11 | u32 ss2; | ||
12 | u32 cr3; | ||
13 | u32 eip; | ||
14 | u32 eflags; | ||
15 | u32 eax; | ||
16 | u32 ecx; | ||
17 | u32 edx; | ||
18 | u32 ebx; | ||
19 | u32 esp; | ||
20 | u32 ebp; | ||
21 | u32 esi; | ||
22 | u32 edi; | ||
23 | u32 es; | ||
24 | u32 cs; | ||
25 | u32 ss; | ||
26 | u32 ds; | ||
27 | u32 fs; | ||
28 | u32 gs; | ||
29 | u32 ldt_selector; | ||
30 | u16 t; | ||
31 | u16 io_map; | ||
32 | }; | ||
33 | |||
34 | struct tss_segment_16 { | ||
35 | u16 prev_task_link; | ||
36 | u16 sp0; | ||
37 | u16 ss0; | ||
38 | u16 sp1; | ||
39 | u16 ss1; | ||
40 | u16 sp2; | ||
41 | u16 ss2; | ||
42 | u16 ip; | ||
43 | u16 flag; | ||
44 | u16 ax; | ||
45 | u16 cx; | ||
46 | u16 dx; | ||
47 | u16 bx; | ||
48 | u16 sp; | ||
49 | u16 bp; | ||
50 | u16 si; | ||
51 | u16 di; | ||
52 | u16 es; | ||
53 | u16 cs; | ||
54 | u16 ss; | ||
55 | u16 ds; | ||
56 | u16 ldt; | ||
57 | }; | ||
58 | |||
59 | #endif | ||
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8e1462880d1f..8e5d6645b90d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -17,7 +17,6 @@ | |||
17 | 17 | ||
18 | #include "irq.h" | 18 | #include "irq.h" |
19 | #include "vmx.h" | 19 | #include "vmx.h" |
20 | #include "segment_descriptor.h" | ||
21 | #include "mmu.h" | 20 | #include "mmu.h" |
22 | 21 | ||
23 | #include <linux/kvm_host.h> | 22 | #include <linux/kvm_host.h> |
@@ -37,6 +36,12 @@ MODULE_LICENSE("GPL"); | |||
37 | static int bypass_guest_pf = 1; | 36 | static int bypass_guest_pf = 1; |
38 | module_param(bypass_guest_pf, bool, 0); | 37 | module_param(bypass_guest_pf, bool, 0); |
39 | 38 | ||
39 | static int enable_vpid = 1; | ||
40 | module_param(enable_vpid, bool, 0); | ||
41 | |||
42 | static int flexpriority_enabled = 1; | ||
43 | module_param(flexpriority_enabled, bool, 0); | ||
44 | |||
40 | struct vmcs { | 45 | struct vmcs { |
41 | u32 revision_id; | 46 | u32 revision_id; |
42 | u32 abort; | 47 | u32 abort; |
@@ -71,6 +76,7 @@ struct vcpu_vmx { | |||
71 | unsigned rip; | 76 | unsigned rip; |
72 | } irq; | 77 | } irq; |
73 | } rmode; | 78 | } rmode; |
79 | int vpid; | ||
74 | }; | 80 | }; |
75 | 81 | ||
76 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) | 82 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) |
@@ -85,6 +91,10 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | |||
85 | 91 | ||
86 | static struct page *vmx_io_bitmap_a; | 92 | static struct page *vmx_io_bitmap_a; |
87 | static struct page *vmx_io_bitmap_b; | 93 | static struct page *vmx_io_bitmap_b; |
94 | static struct page *vmx_msr_bitmap; | ||
95 | |||
96 | static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); | ||
97 | static DEFINE_SPINLOCK(vmx_vpid_lock); | ||
88 | 98 | ||
89 | static struct vmcs_config { | 99 | static struct vmcs_config { |
90 | int size; | 100 | int size; |
@@ -176,6 +186,11 @@ static inline int is_external_interrupt(u32 intr_info) | |||
176 | == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); | 186 | == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); |
177 | } | 187 | } |
178 | 188 | ||
189 | static inline int cpu_has_vmx_msr_bitmap(void) | ||
190 | { | ||
191 | return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS); | ||
192 | } | ||
193 | |||
179 | static inline int cpu_has_vmx_tpr_shadow(void) | 194 | static inline int cpu_has_vmx_tpr_shadow(void) |
180 | { | 195 | { |
181 | return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); | 196 | return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); |
@@ -194,8 +209,9 @@ static inline int cpu_has_secondary_exec_ctrls(void) | |||
194 | 209 | ||
195 | static inline bool cpu_has_vmx_virtualize_apic_accesses(void) | 210 | static inline bool cpu_has_vmx_virtualize_apic_accesses(void) |
196 | { | 211 | { |
197 | return (vmcs_config.cpu_based_2nd_exec_ctrl & | 212 | return flexpriority_enabled |
198 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); | 213 | && (vmcs_config.cpu_based_2nd_exec_ctrl & |
214 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); | ||
199 | } | 215 | } |
200 | 216 | ||
201 | static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) | 217 | static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) |
@@ -204,6 +220,12 @@ static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) | |||
204 | (irqchip_in_kernel(kvm))); | 220 | (irqchip_in_kernel(kvm))); |
205 | } | 221 | } |
206 | 222 | ||
223 | static inline int cpu_has_vmx_vpid(void) | ||
224 | { | ||
225 | return (vmcs_config.cpu_based_2nd_exec_ctrl & | ||
226 | SECONDARY_EXEC_ENABLE_VPID); | ||
227 | } | ||
228 | |||
207 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | 229 | static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) |
208 | { | 230 | { |
209 | int i; | 231 | int i; |
@@ -214,6 +236,20 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) | |||
214 | return -1; | 236 | return -1; |
215 | } | 237 | } |
216 | 238 | ||
239 | static inline void __invvpid(int ext, u16 vpid, gva_t gva) | ||
240 | { | ||
241 | struct { | ||
242 | u64 vpid : 16; | ||
243 | u64 rsvd : 48; | ||
244 | u64 gva; | ||
245 | } operand = { vpid, 0, gva }; | ||
246 | |||
247 | asm volatile (ASM_VMX_INVVPID | ||
248 | /* CF==1 or ZF==1 --> rc = -1 */ | ||
249 | "; ja 1f ; ud2 ; 1:" | ||
250 | : : "a"(&operand), "c"(ext) : "cc", "memory"); | ||
251 | } | ||
252 | |||
217 | static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) | 253 | static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) |
218 | { | 254 | { |
219 | int i; | 255 | int i; |
@@ -257,6 +293,14 @@ static void vcpu_clear(struct vcpu_vmx *vmx) | |||
257 | vmx->launched = 0; | 293 | vmx->launched = 0; |
258 | } | 294 | } |
259 | 295 | ||
296 | static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx) | ||
297 | { | ||
298 | if (vmx->vpid == 0) | ||
299 | return; | ||
300 | |||
301 | __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0); | ||
302 | } | ||
303 | |||
260 | static unsigned long vmcs_readl(unsigned long field) | 304 | static unsigned long vmcs_readl(unsigned long field) |
261 | { | 305 | { |
262 | unsigned long value; | 306 | unsigned long value; |
@@ -353,7 +397,7 @@ static void reload_tss(void) | |||
353 | * VT restores TR but not its size. Useless. | 397 | * VT restores TR but not its size. Useless. |
354 | */ | 398 | */ |
355 | struct descriptor_table gdt; | 399 | struct descriptor_table gdt; |
356 | struct segment_descriptor *descs; | 400 | struct desc_struct *descs; |
357 | 401 | ||
358 | get_gdt(&gdt); | 402 | get_gdt(&gdt); |
359 | descs = (void *)gdt.base; | 403 | descs = (void *)gdt.base; |
@@ -485,11 +529,12 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
485 | { | 529 | { |
486 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 530 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
487 | u64 phys_addr = __pa(vmx->vmcs); | 531 | u64 phys_addr = __pa(vmx->vmcs); |
488 | u64 tsc_this, delta; | 532 | u64 tsc_this, delta, new_offset; |
489 | 533 | ||
490 | if (vcpu->cpu != cpu) { | 534 | if (vcpu->cpu != cpu) { |
491 | vcpu_clear(vmx); | 535 | vcpu_clear(vmx); |
492 | kvm_migrate_apic_timer(vcpu); | 536 | kvm_migrate_apic_timer(vcpu); |
537 | vpid_sync_vcpu_all(vmx); | ||
493 | } | 538 | } |
494 | 539 | ||
495 | if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { | 540 | if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { |
@@ -524,8 +569,11 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
524 | * Make sure the time stamp counter is monotonous. | 569 | * Make sure the time stamp counter is monotonous. |
525 | */ | 570 | */ |
526 | rdtscll(tsc_this); | 571 | rdtscll(tsc_this); |
527 | delta = vcpu->arch.host_tsc - tsc_this; | 572 | if (tsc_this < vcpu->arch.host_tsc) { |
528 | vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta); | 573 | delta = vcpu->arch.host_tsc - tsc_this; |
574 | new_offset = vmcs_read64(TSC_OFFSET) + delta; | ||
575 | vmcs_write64(TSC_OFFSET, new_offset); | ||
576 | } | ||
529 | } | 577 | } |
530 | } | 578 | } |
531 | 579 | ||
@@ -596,7 +644,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | |||
596 | { | 644 | { |
597 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | 645 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, |
598 | nr | INTR_TYPE_EXCEPTION | 646 | nr | INTR_TYPE_EXCEPTION |
599 | | (has_error_code ? INTR_INFO_DELIEVER_CODE_MASK : 0) | 647 | | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0) |
600 | | INTR_INFO_VALID_MASK); | 648 | | INTR_INFO_VALID_MASK); |
601 | if (has_error_code) | 649 | if (has_error_code) |
602 | vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); | 650 | vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); |
@@ -959,6 +1007,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) | |||
959 | CPU_BASED_MOV_DR_EXITING | | 1007 | CPU_BASED_MOV_DR_EXITING | |
960 | CPU_BASED_USE_TSC_OFFSETING; | 1008 | CPU_BASED_USE_TSC_OFFSETING; |
961 | opt = CPU_BASED_TPR_SHADOW | | 1009 | opt = CPU_BASED_TPR_SHADOW | |
1010 | CPU_BASED_USE_MSR_BITMAPS | | ||
962 | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; | 1011 | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; |
963 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, | 1012 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, |
964 | &_cpu_based_exec_control) < 0) | 1013 | &_cpu_based_exec_control) < 0) |
@@ -971,7 +1020,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) | |||
971 | if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { | 1020 | if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { |
972 | min = 0; | 1021 | min = 0; |
973 | opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | | 1022 | opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | |
974 | SECONDARY_EXEC_WBINVD_EXITING; | 1023 | SECONDARY_EXEC_WBINVD_EXITING | |
1024 | SECONDARY_EXEC_ENABLE_VPID; | ||
975 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2, | 1025 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2, |
976 | &_cpu_based_2nd_exec_control) < 0) | 1026 | &_cpu_based_2nd_exec_control) < 0) |
977 | return -EIO; | 1027 | return -EIO; |
@@ -1080,6 +1130,10 @@ static __init int hardware_setup(void) | |||
1080 | { | 1130 | { |
1081 | if (setup_vmcs_config(&vmcs_config) < 0) | 1131 | if (setup_vmcs_config(&vmcs_config) < 0) |
1082 | return -EIO; | 1132 | return -EIO; |
1133 | |||
1134 | if (boot_cpu_has(X86_FEATURE_NX)) | ||
1135 | kvm_enable_efer_bits(EFER_NX); | ||
1136 | |||
1083 | return alloc_kvm_area(); | 1137 | return alloc_kvm_area(); |
1084 | } | 1138 | } |
1085 | 1139 | ||
@@ -1214,7 +1268,7 @@ static void enter_lmode(struct kvm_vcpu *vcpu) | |||
1214 | guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); | 1268 | guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); |
1215 | if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { | 1269 | if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { |
1216 | printk(KERN_DEBUG "%s: tss fixup for long mode. \n", | 1270 | printk(KERN_DEBUG "%s: tss fixup for long mode. \n", |
1217 | __FUNCTION__); | 1271 | __func__); |
1218 | vmcs_write32(GUEST_TR_AR_BYTES, | 1272 | vmcs_write32(GUEST_TR_AR_BYTES, |
1219 | (guest_tr_ar & ~AR_TYPE_MASK) | 1273 | (guest_tr_ar & ~AR_TYPE_MASK) |
1220 | | AR_TYPE_BUSY_64_TSS); | 1274 | | AR_TYPE_BUSY_64_TSS); |
@@ -1239,6 +1293,11 @@ static void exit_lmode(struct kvm_vcpu *vcpu) | |||
1239 | 1293 | ||
1240 | #endif | 1294 | #endif |
1241 | 1295 | ||
1296 | static void vmx_flush_tlb(struct kvm_vcpu *vcpu) | ||
1297 | { | ||
1298 | vpid_sync_vcpu_all(to_vmx(vcpu)); | ||
1299 | } | ||
1300 | |||
1242 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) | 1301 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) |
1243 | { | 1302 | { |
1244 | vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK; | 1303 | vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK; |
@@ -1275,6 +1334,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
1275 | 1334 | ||
1276 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | 1335 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) |
1277 | { | 1336 | { |
1337 | vmx_flush_tlb(vcpu); | ||
1278 | vmcs_writel(GUEST_CR3, cr3); | 1338 | vmcs_writel(GUEST_CR3, cr3); |
1279 | if (vcpu->arch.cr0 & X86_CR0_PE) | 1339 | if (vcpu->arch.cr0 & X86_CR0_PE) |
1280 | vmx_fpu_deactivate(vcpu); | 1340 | vmx_fpu_deactivate(vcpu); |
@@ -1288,14 +1348,14 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | |||
1288 | vcpu->arch.cr4 = cr4; | 1348 | vcpu->arch.cr4 = cr4; |
1289 | } | 1349 | } |
1290 | 1350 | ||
1291 | #ifdef CONFIG_X86_64 | ||
1292 | |||
1293 | static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) | 1351 | static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) |
1294 | { | 1352 | { |
1295 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 1353 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
1296 | struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); | 1354 | struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); |
1297 | 1355 | ||
1298 | vcpu->arch.shadow_efer = efer; | 1356 | vcpu->arch.shadow_efer = efer; |
1357 | if (!msr) | ||
1358 | return; | ||
1299 | if (efer & EFER_LMA) { | 1359 | if (efer & EFER_LMA) { |
1300 | vmcs_write32(VM_ENTRY_CONTROLS, | 1360 | vmcs_write32(VM_ENTRY_CONTROLS, |
1301 | vmcs_read32(VM_ENTRY_CONTROLS) | | 1361 | vmcs_read32(VM_ENTRY_CONTROLS) | |
@@ -1312,8 +1372,6 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) | |||
1312 | setup_msrs(vmx); | 1372 | setup_msrs(vmx); |
1313 | } | 1373 | } |
1314 | 1374 | ||
1315 | #endif | ||
1316 | |||
1317 | static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) | 1375 | static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) |
1318 | { | 1376 | { |
1319 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; | 1377 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; |
@@ -1344,6 +1402,20 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu, | |||
1344 | var->unusable = (ar >> 16) & 1; | 1402 | var->unusable = (ar >> 16) & 1; |
1345 | } | 1403 | } |
1346 | 1404 | ||
1405 | static int vmx_get_cpl(struct kvm_vcpu *vcpu) | ||
1406 | { | ||
1407 | struct kvm_segment kvm_seg; | ||
1408 | |||
1409 | if (!(vcpu->arch.cr0 & X86_CR0_PE)) /* if real mode */ | ||
1410 | return 0; | ||
1411 | |||
1412 | if (vmx_get_rflags(vcpu) & X86_EFLAGS_VM) /* if virtual 8086 */ | ||
1413 | return 3; | ||
1414 | |||
1415 | vmx_get_segment(vcpu, &kvm_seg, VCPU_SREG_CS); | ||
1416 | return kvm_seg.selector & 3; | ||
1417 | } | ||
1418 | |||
1347 | static u32 vmx_segment_access_rights(struct kvm_segment *var) | 1419 | static u32 vmx_segment_access_rights(struct kvm_segment *var) |
1348 | { | 1420 | { |
1349 | u32 ar; | 1421 | u32 ar; |
@@ -1433,7 +1505,6 @@ static int init_rmode_tss(struct kvm *kvm) | |||
1433 | int ret = 0; | 1505 | int ret = 0; |
1434 | int r; | 1506 | int r; |
1435 | 1507 | ||
1436 | down_read(&kvm->slots_lock); | ||
1437 | r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE); | 1508 | r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE); |
1438 | if (r < 0) | 1509 | if (r < 0) |
1439 | goto out; | 1510 | goto out; |
@@ -1456,7 +1527,6 @@ static int init_rmode_tss(struct kvm *kvm) | |||
1456 | 1527 | ||
1457 | ret = 1; | 1528 | ret = 1; |
1458 | out: | 1529 | out: |
1459 | up_read(&kvm->slots_lock); | ||
1460 | return ret; | 1530 | return ret; |
1461 | } | 1531 | } |
1462 | 1532 | ||
@@ -1494,6 +1564,46 @@ out: | |||
1494 | return r; | 1564 | return r; |
1495 | } | 1565 | } |
1496 | 1566 | ||
1567 | static void allocate_vpid(struct vcpu_vmx *vmx) | ||
1568 | { | ||
1569 | int vpid; | ||
1570 | |||
1571 | vmx->vpid = 0; | ||
1572 | if (!enable_vpid || !cpu_has_vmx_vpid()) | ||
1573 | return; | ||
1574 | spin_lock(&vmx_vpid_lock); | ||
1575 | vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS); | ||
1576 | if (vpid < VMX_NR_VPIDS) { | ||
1577 | vmx->vpid = vpid; | ||
1578 | __set_bit(vpid, vmx_vpid_bitmap); | ||
1579 | } | ||
1580 | spin_unlock(&vmx_vpid_lock); | ||
1581 | } | ||
1582 | |||
1583 | void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) | ||
1584 | { | ||
1585 | void *va; | ||
1586 | |||
1587 | if (!cpu_has_vmx_msr_bitmap()) | ||
1588 | return; | ||
1589 | |||
1590 | /* | ||
1591 | * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals | ||
1592 | * have the write-low and read-high bitmap offsets the wrong way round. | ||
1593 | * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff. | ||
1594 | */ | ||
1595 | va = kmap(msr_bitmap); | ||
1596 | if (msr <= 0x1fff) { | ||
1597 | __clear_bit(msr, va + 0x000); /* read-low */ | ||
1598 | __clear_bit(msr, va + 0x800); /* write-low */ | ||
1599 | } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) { | ||
1600 | msr &= 0x1fff; | ||
1601 | __clear_bit(msr, va + 0x400); /* read-high */ | ||
1602 | __clear_bit(msr, va + 0xc00); /* write-high */ | ||
1603 | } | ||
1604 | kunmap(msr_bitmap); | ||
1605 | } | ||
1606 | |||
1497 | /* | 1607 | /* |
1498 | * Sets up the vmcs for emulated real mode. | 1608 | * Sets up the vmcs for emulated real mode. |
1499 | */ | 1609 | */ |
@@ -1511,6 +1621,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
1511 | vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a)); | 1621 | vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a)); |
1512 | vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b)); | 1622 | vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b)); |
1513 | 1623 | ||
1624 | if (cpu_has_vmx_msr_bitmap()) | ||
1625 | vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap)); | ||
1626 | |||
1514 | vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ | 1627 | vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ |
1515 | 1628 | ||
1516 | /* Control */ | 1629 | /* Control */ |
@@ -1532,6 +1645,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
1532 | if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) | 1645 | if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) |
1533 | exec_control &= | 1646 | exec_control &= |
1534 | ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; | 1647 | ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; |
1648 | if (vmx->vpid == 0) | ||
1649 | exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; | ||
1535 | vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); | 1650 | vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); |
1536 | } | 1651 | } |
1537 | 1652 | ||
@@ -1613,6 +1728,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1613 | u64 msr; | 1728 | u64 msr; |
1614 | int ret; | 1729 | int ret; |
1615 | 1730 | ||
1731 | down_read(&vcpu->kvm->slots_lock); | ||
1616 | if (!init_rmode_tss(vmx->vcpu.kvm)) { | 1732 | if (!init_rmode_tss(vmx->vcpu.kvm)) { |
1617 | ret = -ENOMEM; | 1733 | ret = -ENOMEM; |
1618 | goto out; | 1734 | goto out; |
@@ -1621,7 +1737,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1621 | vmx->vcpu.arch.rmode.active = 0; | 1737 | vmx->vcpu.arch.rmode.active = 0; |
1622 | 1738 | ||
1623 | vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); | 1739 | vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); |
1624 | set_cr8(&vmx->vcpu, 0); | 1740 | kvm_set_cr8(&vmx->vcpu, 0); |
1625 | msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; | 1741 | msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; |
1626 | if (vmx->vcpu.vcpu_id == 0) | 1742 | if (vmx->vcpu.vcpu_id == 0) |
1627 | msr |= MSR_IA32_APICBASE_BSP; | 1743 | msr |= MSR_IA32_APICBASE_BSP; |
@@ -1704,18 +1820,22 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) | |||
1704 | vmcs_write64(APIC_ACCESS_ADDR, | 1820 | vmcs_write64(APIC_ACCESS_ADDR, |
1705 | page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); | 1821 | page_to_phys(vmx->vcpu.kvm->arch.apic_access_page)); |
1706 | 1822 | ||
1823 | if (vmx->vpid != 0) | ||
1824 | vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); | ||
1825 | |||
1707 | vmx->vcpu.arch.cr0 = 0x60000010; | 1826 | vmx->vcpu.arch.cr0 = 0x60000010; |
1708 | vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */ | 1827 | vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */ |
1709 | vmx_set_cr4(&vmx->vcpu, 0); | 1828 | vmx_set_cr4(&vmx->vcpu, 0); |
1710 | #ifdef CONFIG_X86_64 | ||
1711 | vmx_set_efer(&vmx->vcpu, 0); | 1829 | vmx_set_efer(&vmx->vcpu, 0); |
1712 | #endif | ||
1713 | vmx_fpu_activate(&vmx->vcpu); | 1830 | vmx_fpu_activate(&vmx->vcpu); |
1714 | update_exception_bitmap(&vmx->vcpu); | 1831 | update_exception_bitmap(&vmx->vcpu); |
1715 | 1832 | ||
1716 | return 0; | 1833 | vpid_sync_vcpu_all(vmx); |
1834 | |||
1835 | ret = 0; | ||
1717 | 1836 | ||
1718 | out: | 1837 | out: |
1838 | up_read(&vcpu->kvm->slots_lock); | ||
1719 | return ret; | 1839 | return ret; |
1720 | } | 1840 | } |
1721 | 1841 | ||
@@ -1723,6 +1843,8 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) | |||
1723 | { | 1843 | { |
1724 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 1844 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
1725 | 1845 | ||
1846 | KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler); | ||
1847 | |||
1726 | if (vcpu->arch.rmode.active) { | 1848 | if (vcpu->arch.rmode.active) { |
1727 | vmx->rmode.irq.pending = true; | 1849 | vmx->rmode.irq.pending = true; |
1728 | vmx->rmode.irq.vector = irq; | 1850 | vmx->rmode.irq.vector = irq; |
@@ -1844,7 +1966,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1844 | if ((vect_info & VECTORING_INFO_VALID_MASK) && | 1966 | if ((vect_info & VECTORING_INFO_VALID_MASK) && |
1845 | !is_page_fault(intr_info)) | 1967 | !is_page_fault(intr_info)) |
1846 | printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " | 1968 | printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " |
1847 | "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); | 1969 | "intr info 0x%x\n", __func__, vect_info, intr_info); |
1848 | 1970 | ||
1849 | if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { | 1971 | if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { |
1850 | int irq = vect_info & VECTORING_INFO_VECTOR_MASK; | 1972 | int irq = vect_info & VECTORING_INFO_VECTOR_MASK; |
@@ -1869,10 +1991,12 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1869 | 1991 | ||
1870 | error_code = 0; | 1992 | error_code = 0; |
1871 | rip = vmcs_readl(GUEST_RIP); | 1993 | rip = vmcs_readl(GUEST_RIP); |
1872 | if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) | 1994 | if (intr_info & INTR_INFO_DELIVER_CODE_MASK) |
1873 | error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); | 1995 | error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); |
1874 | if (is_page_fault(intr_info)) { | 1996 | if (is_page_fault(intr_info)) { |
1875 | cr2 = vmcs_readl(EXIT_QUALIFICATION); | 1997 | cr2 = vmcs_readl(EXIT_QUALIFICATION); |
1998 | KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2, | ||
1999 | (u32)((u64)cr2 >> 32), handler); | ||
1876 | return kvm_mmu_page_fault(vcpu, cr2, error_code); | 2000 | return kvm_mmu_page_fault(vcpu, cr2, error_code); |
1877 | } | 2001 | } |
1878 | 2002 | ||
@@ -1901,6 +2025,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu, | |||
1901 | struct kvm_run *kvm_run) | 2025 | struct kvm_run *kvm_run) |
1902 | { | 2026 | { |
1903 | ++vcpu->stat.irq_exits; | 2027 | ++vcpu->stat.irq_exits; |
2028 | KVMTRACE_1D(INTR, vcpu, vmcs_read32(VM_EXIT_INTR_INFO), handler); | ||
1904 | return 1; | 2029 | return 1; |
1905 | } | 2030 | } |
1906 | 2031 | ||
@@ -1958,25 +2083,27 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1958 | reg = (exit_qualification >> 8) & 15; | 2083 | reg = (exit_qualification >> 8) & 15; |
1959 | switch ((exit_qualification >> 4) & 3) { | 2084 | switch ((exit_qualification >> 4) & 3) { |
1960 | case 0: /* mov to cr */ | 2085 | case 0: /* mov to cr */ |
2086 | KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)vcpu->arch.regs[reg], | ||
2087 | (u32)((u64)vcpu->arch.regs[reg] >> 32), handler); | ||
1961 | switch (cr) { | 2088 | switch (cr) { |
1962 | case 0: | 2089 | case 0: |
1963 | vcpu_load_rsp_rip(vcpu); | 2090 | vcpu_load_rsp_rip(vcpu); |
1964 | set_cr0(vcpu, vcpu->arch.regs[reg]); | 2091 | kvm_set_cr0(vcpu, vcpu->arch.regs[reg]); |
1965 | skip_emulated_instruction(vcpu); | 2092 | skip_emulated_instruction(vcpu); |
1966 | return 1; | 2093 | return 1; |
1967 | case 3: | 2094 | case 3: |
1968 | vcpu_load_rsp_rip(vcpu); | 2095 | vcpu_load_rsp_rip(vcpu); |
1969 | set_cr3(vcpu, vcpu->arch.regs[reg]); | 2096 | kvm_set_cr3(vcpu, vcpu->arch.regs[reg]); |
1970 | skip_emulated_instruction(vcpu); | 2097 | skip_emulated_instruction(vcpu); |
1971 | return 1; | 2098 | return 1; |
1972 | case 4: | 2099 | case 4: |
1973 | vcpu_load_rsp_rip(vcpu); | 2100 | vcpu_load_rsp_rip(vcpu); |
1974 | set_cr4(vcpu, vcpu->arch.regs[reg]); | 2101 | kvm_set_cr4(vcpu, vcpu->arch.regs[reg]); |
1975 | skip_emulated_instruction(vcpu); | 2102 | skip_emulated_instruction(vcpu); |
1976 | return 1; | 2103 | return 1; |
1977 | case 8: | 2104 | case 8: |
1978 | vcpu_load_rsp_rip(vcpu); | 2105 | vcpu_load_rsp_rip(vcpu); |
1979 | set_cr8(vcpu, vcpu->arch.regs[reg]); | 2106 | kvm_set_cr8(vcpu, vcpu->arch.regs[reg]); |
1980 | skip_emulated_instruction(vcpu); | 2107 | skip_emulated_instruction(vcpu); |
1981 | if (irqchip_in_kernel(vcpu->kvm)) | 2108 | if (irqchip_in_kernel(vcpu->kvm)) |
1982 | return 1; | 2109 | return 1; |
@@ -1990,6 +2117,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1990 | vcpu->arch.cr0 &= ~X86_CR0_TS; | 2117 | vcpu->arch.cr0 &= ~X86_CR0_TS; |
1991 | vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); | 2118 | vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); |
1992 | vmx_fpu_activate(vcpu); | 2119 | vmx_fpu_activate(vcpu); |
2120 | KVMTRACE_0D(CLTS, vcpu, handler); | ||
1993 | skip_emulated_instruction(vcpu); | 2121 | skip_emulated_instruction(vcpu); |
1994 | return 1; | 2122 | return 1; |
1995 | case 1: /*mov from cr*/ | 2123 | case 1: /*mov from cr*/ |
@@ -1998,18 +2126,24 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1998 | vcpu_load_rsp_rip(vcpu); | 2126 | vcpu_load_rsp_rip(vcpu); |
1999 | vcpu->arch.regs[reg] = vcpu->arch.cr3; | 2127 | vcpu->arch.regs[reg] = vcpu->arch.cr3; |
2000 | vcpu_put_rsp_rip(vcpu); | 2128 | vcpu_put_rsp_rip(vcpu); |
2129 | KVMTRACE_3D(CR_READ, vcpu, (u32)cr, | ||
2130 | (u32)vcpu->arch.regs[reg], | ||
2131 | (u32)((u64)vcpu->arch.regs[reg] >> 32), | ||
2132 | handler); | ||
2001 | skip_emulated_instruction(vcpu); | 2133 | skip_emulated_instruction(vcpu); |
2002 | return 1; | 2134 | return 1; |
2003 | case 8: | 2135 | case 8: |
2004 | vcpu_load_rsp_rip(vcpu); | 2136 | vcpu_load_rsp_rip(vcpu); |
2005 | vcpu->arch.regs[reg] = get_cr8(vcpu); | 2137 | vcpu->arch.regs[reg] = kvm_get_cr8(vcpu); |
2006 | vcpu_put_rsp_rip(vcpu); | 2138 | vcpu_put_rsp_rip(vcpu); |
2139 | KVMTRACE_2D(CR_READ, vcpu, (u32)cr, | ||
2140 | (u32)vcpu->arch.regs[reg], handler); | ||
2007 | skip_emulated_instruction(vcpu); | 2141 | skip_emulated_instruction(vcpu); |
2008 | return 1; | 2142 | return 1; |
2009 | } | 2143 | } |
2010 | break; | 2144 | break; |
2011 | case 3: /* lmsw */ | 2145 | case 3: /* lmsw */ |
2012 | lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); | 2146 | kvm_lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); |
2013 | 2147 | ||
2014 | skip_emulated_instruction(vcpu); | 2148 | skip_emulated_instruction(vcpu); |
2015 | return 1; | 2149 | return 1; |
@@ -2049,6 +2183,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2049 | val = 0; | 2183 | val = 0; |
2050 | } | 2184 | } |
2051 | vcpu->arch.regs[reg] = val; | 2185 | vcpu->arch.regs[reg] = val; |
2186 | KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler); | ||
2052 | } else { | 2187 | } else { |
2053 | /* mov to dr */ | 2188 | /* mov to dr */ |
2054 | } | 2189 | } |
@@ -2073,6 +2208,9 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2073 | return 1; | 2208 | return 1; |
2074 | } | 2209 | } |
2075 | 2210 | ||
2211 | KVMTRACE_3D(MSR_READ, vcpu, ecx, (u32)data, (u32)(data >> 32), | ||
2212 | handler); | ||
2213 | |||
2076 | /* FIXME: handling of bits 32:63 of rax, rdx */ | 2214 | /* FIXME: handling of bits 32:63 of rax, rdx */ |
2077 | vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u; | 2215 | vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u; |
2078 | vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u; | 2216 | vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u; |
@@ -2086,6 +2224,9 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2086 | u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u) | 2224 | u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u) |
2087 | | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32); | 2225 | | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32); |
2088 | 2226 | ||
2227 | KVMTRACE_3D(MSR_WRITE, vcpu, ecx, (u32)data, (u32)(data >> 32), | ||
2228 | handler); | ||
2229 | |||
2089 | if (vmx_set_msr(vcpu, ecx, data) != 0) { | 2230 | if (vmx_set_msr(vcpu, ecx, data) != 0) { |
2090 | kvm_inject_gp(vcpu, 0); | 2231 | kvm_inject_gp(vcpu, 0); |
2091 | return 1; | 2232 | return 1; |
@@ -2110,6 +2251,9 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu, | |||
2110 | cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); | 2251 | cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); |
2111 | cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; | 2252 | cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; |
2112 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); | 2253 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); |
2254 | |||
2255 | KVMTRACE_0D(PEND_INTR, vcpu, handler); | ||
2256 | |||
2113 | /* | 2257 | /* |
2114 | * If the user space waits to inject interrupts, exit as soon as | 2258 | * If the user space waits to inject interrupts, exit as soon as |
2115 | * possible | 2259 | * possible |
@@ -2152,6 +2296,8 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2152 | exit_qualification = vmcs_read64(EXIT_QUALIFICATION); | 2296 | exit_qualification = vmcs_read64(EXIT_QUALIFICATION); |
2153 | offset = exit_qualification & 0xffful; | 2297 | offset = exit_qualification & 0xffful; |
2154 | 2298 | ||
2299 | KVMTRACE_1D(APIC_ACCESS, vcpu, (u32)offset, handler); | ||
2300 | |||
2155 | er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); | 2301 | er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); |
2156 | 2302 | ||
2157 | if (er != EMULATE_DONE) { | 2303 | if (er != EMULATE_DONE) { |
@@ -2163,6 +2309,20 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2163 | return 1; | 2309 | return 1; |
2164 | } | 2310 | } |
2165 | 2311 | ||
2312 | static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
2313 | { | ||
2314 | unsigned long exit_qualification; | ||
2315 | u16 tss_selector; | ||
2316 | int reason; | ||
2317 | |||
2318 | exit_qualification = vmcs_readl(EXIT_QUALIFICATION); | ||
2319 | |||
2320 | reason = (u32)exit_qualification >> 30; | ||
2321 | tss_selector = exit_qualification; | ||
2322 | |||
2323 | return kvm_task_switch(vcpu, tss_selector, reason); | ||
2324 | } | ||
2325 | |||
2166 | /* | 2326 | /* |
2167 | * The exit handlers return 1 if the exit was handled fully and guest execution | 2327 | * The exit handlers return 1 if the exit was handled fully and guest execution |
2168 | * may resume. Otherwise they set the kvm_run parameter to indicate what needs | 2328 | * may resume. Otherwise they set the kvm_run parameter to indicate what needs |
@@ -2185,6 +2345,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, | |||
2185 | [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, | 2345 | [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, |
2186 | [EXIT_REASON_APIC_ACCESS] = handle_apic_access, | 2346 | [EXIT_REASON_APIC_ACCESS] = handle_apic_access, |
2187 | [EXIT_REASON_WBINVD] = handle_wbinvd, | 2347 | [EXIT_REASON_WBINVD] = handle_wbinvd, |
2348 | [EXIT_REASON_TASK_SWITCH] = handle_task_switch, | ||
2188 | }; | 2349 | }; |
2189 | 2350 | ||
2190 | static const int kvm_vmx_max_exit_handlers = | 2351 | static const int kvm_vmx_max_exit_handlers = |
@@ -2200,6 +2361,9 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
2200 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2361 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
2201 | u32 vectoring_info = vmx->idt_vectoring_info; | 2362 | u32 vectoring_info = vmx->idt_vectoring_info; |
2202 | 2363 | ||
2364 | KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)vmcs_readl(GUEST_RIP), | ||
2365 | (u32)((u64)vmcs_readl(GUEST_RIP) >> 32), entryexit); | ||
2366 | |||
2203 | if (unlikely(vmx->fail)) { | 2367 | if (unlikely(vmx->fail)) { |
2204 | kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; | 2368 | kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; |
2205 | kvm_run->fail_entry.hardware_entry_failure_reason | 2369 | kvm_run->fail_entry.hardware_entry_failure_reason |
@@ -2210,7 +2374,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
2210 | if ((vectoring_info & VECTORING_INFO_VALID_MASK) && | 2374 | if ((vectoring_info & VECTORING_INFO_VALID_MASK) && |
2211 | exit_reason != EXIT_REASON_EXCEPTION_NMI) | 2375 | exit_reason != EXIT_REASON_EXCEPTION_NMI) |
2212 | printk(KERN_WARNING "%s: unexpected, valid vectoring info and " | 2376 | printk(KERN_WARNING "%s: unexpected, valid vectoring info and " |
2213 | "exit reason is 0x%x\n", __FUNCTION__, exit_reason); | 2377 | "exit reason is 0x%x\n", __func__, exit_reason); |
2214 | if (exit_reason < kvm_vmx_max_exit_handlers | 2378 | if (exit_reason < kvm_vmx_max_exit_handlers |
2215 | && kvm_vmx_exit_handlers[exit_reason]) | 2379 | && kvm_vmx_exit_handlers[exit_reason]) |
2216 | return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); | 2380 | return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); |
@@ -2221,10 +2385,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
2221 | return 0; | 2385 | return 0; |
2222 | } | 2386 | } |
2223 | 2387 | ||
2224 | static void vmx_flush_tlb(struct kvm_vcpu *vcpu) | ||
2225 | { | ||
2226 | } | ||
2227 | |||
2228 | static void update_tpr_threshold(struct kvm_vcpu *vcpu) | 2388 | static void update_tpr_threshold(struct kvm_vcpu *vcpu) |
2229 | { | 2389 | { |
2230 | int max_irr, tpr; | 2390 | int max_irr, tpr; |
@@ -2285,11 +2445,13 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
2285 | return; | 2445 | return; |
2286 | } | 2446 | } |
2287 | 2447 | ||
2448 | KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler); | ||
2449 | |||
2288 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); | 2450 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); |
2289 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, | 2451 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, |
2290 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); | 2452 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); |
2291 | 2453 | ||
2292 | if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK)) | 2454 | if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK)) |
2293 | vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, | 2455 | vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, |
2294 | vmcs_read32(IDT_VECTORING_ERROR_CODE)); | 2456 | vmcs_read32(IDT_VECTORING_ERROR_CODE)); |
2295 | if (unlikely(has_ext_irq)) | 2457 | if (unlikely(has_ext_irq)) |
@@ -2470,8 +2632,10 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2470 | intr_info = vmcs_read32(VM_EXIT_INTR_INFO); | 2632 | intr_info = vmcs_read32(VM_EXIT_INTR_INFO); |
2471 | 2633 | ||
2472 | /* We need to handle NMIs before interrupts are enabled */ | 2634 | /* We need to handle NMIs before interrupts are enabled */ |
2473 | if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ | 2635 | if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */ |
2636 | KVMTRACE_0D(NMI, vcpu, handler); | ||
2474 | asm("int $2"); | 2637 | asm("int $2"); |
2638 | } | ||
2475 | } | 2639 | } |
2476 | 2640 | ||
2477 | static void vmx_free_vmcs(struct kvm_vcpu *vcpu) | 2641 | static void vmx_free_vmcs(struct kvm_vcpu *vcpu) |
@@ -2489,6 +2653,10 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu) | |||
2489 | { | 2653 | { |
2490 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2654 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
2491 | 2655 | ||
2656 | spin_lock(&vmx_vpid_lock); | ||
2657 | if (vmx->vpid != 0) | ||
2658 | __clear_bit(vmx->vpid, vmx_vpid_bitmap); | ||
2659 | spin_unlock(&vmx_vpid_lock); | ||
2492 | vmx_free_vmcs(vcpu); | 2660 | vmx_free_vmcs(vcpu); |
2493 | kfree(vmx->host_msrs); | 2661 | kfree(vmx->host_msrs); |
2494 | kfree(vmx->guest_msrs); | 2662 | kfree(vmx->guest_msrs); |
@@ -2505,6 +2673,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
2505 | if (!vmx) | 2673 | if (!vmx) |
2506 | return ERR_PTR(-ENOMEM); | 2674 | return ERR_PTR(-ENOMEM); |
2507 | 2675 | ||
2676 | allocate_vpid(vmx); | ||
2677 | |||
2508 | err = kvm_vcpu_init(&vmx->vcpu, kvm, id); | 2678 | err = kvm_vcpu_init(&vmx->vcpu, kvm, id); |
2509 | if (err) | 2679 | if (err) |
2510 | goto free_vcpu; | 2680 | goto free_vcpu; |
@@ -2591,14 +2761,13 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
2591 | .get_segment_base = vmx_get_segment_base, | 2761 | .get_segment_base = vmx_get_segment_base, |
2592 | .get_segment = vmx_get_segment, | 2762 | .get_segment = vmx_get_segment, |
2593 | .set_segment = vmx_set_segment, | 2763 | .set_segment = vmx_set_segment, |
2764 | .get_cpl = vmx_get_cpl, | ||
2594 | .get_cs_db_l_bits = vmx_get_cs_db_l_bits, | 2765 | .get_cs_db_l_bits = vmx_get_cs_db_l_bits, |
2595 | .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, | 2766 | .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, |
2596 | .set_cr0 = vmx_set_cr0, | 2767 | .set_cr0 = vmx_set_cr0, |
2597 | .set_cr3 = vmx_set_cr3, | 2768 | .set_cr3 = vmx_set_cr3, |
2598 | .set_cr4 = vmx_set_cr4, | 2769 | .set_cr4 = vmx_set_cr4, |
2599 | #ifdef CONFIG_X86_64 | ||
2600 | .set_efer = vmx_set_efer, | 2770 | .set_efer = vmx_set_efer, |
2601 | #endif | ||
2602 | .get_idt = vmx_get_idt, | 2771 | .get_idt = vmx_get_idt, |
2603 | .set_idt = vmx_set_idt, | 2772 | .set_idt = vmx_set_idt, |
2604 | .get_gdt = vmx_get_gdt, | 2773 | .get_gdt = vmx_get_gdt, |
@@ -2626,7 +2795,7 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
2626 | 2795 | ||
2627 | static int __init vmx_init(void) | 2796 | static int __init vmx_init(void) |
2628 | { | 2797 | { |
2629 | void *iova; | 2798 | void *va; |
2630 | int r; | 2799 | int r; |
2631 | 2800 | ||
2632 | vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); | 2801 | vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); |
@@ -2639,28 +2808,48 @@ static int __init vmx_init(void) | |||
2639 | goto out; | 2808 | goto out; |
2640 | } | 2809 | } |
2641 | 2810 | ||
2811 | vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); | ||
2812 | if (!vmx_msr_bitmap) { | ||
2813 | r = -ENOMEM; | ||
2814 | goto out1; | ||
2815 | } | ||
2816 | |||
2642 | /* | 2817 | /* |
2643 | * Allow direct access to the PC debug port (it is often used for I/O | 2818 | * Allow direct access to the PC debug port (it is often used for I/O |
2644 | * delays, but the vmexits simply slow things down). | 2819 | * delays, but the vmexits simply slow things down). |
2645 | */ | 2820 | */ |
2646 | iova = kmap(vmx_io_bitmap_a); | 2821 | va = kmap(vmx_io_bitmap_a); |
2647 | memset(iova, 0xff, PAGE_SIZE); | 2822 | memset(va, 0xff, PAGE_SIZE); |
2648 | clear_bit(0x80, iova); | 2823 | clear_bit(0x80, va); |
2649 | kunmap(vmx_io_bitmap_a); | 2824 | kunmap(vmx_io_bitmap_a); |
2650 | 2825 | ||
2651 | iova = kmap(vmx_io_bitmap_b); | 2826 | va = kmap(vmx_io_bitmap_b); |
2652 | memset(iova, 0xff, PAGE_SIZE); | 2827 | memset(va, 0xff, PAGE_SIZE); |
2653 | kunmap(vmx_io_bitmap_b); | 2828 | kunmap(vmx_io_bitmap_b); |
2654 | 2829 | ||
2830 | va = kmap(vmx_msr_bitmap); | ||
2831 | memset(va, 0xff, PAGE_SIZE); | ||
2832 | kunmap(vmx_msr_bitmap); | ||
2833 | |||
2834 | set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ | ||
2835 | |||
2655 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); | 2836 | r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); |
2656 | if (r) | 2837 | if (r) |
2657 | goto out1; | 2838 | goto out2; |
2839 | |||
2840 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE); | ||
2841 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE); | ||
2842 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS); | ||
2843 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP); | ||
2844 | vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP); | ||
2658 | 2845 | ||
2659 | if (bypass_guest_pf) | 2846 | if (bypass_guest_pf) |
2660 | kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); | 2847 | kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); |
2661 | 2848 | ||
2662 | return 0; | 2849 | return 0; |
2663 | 2850 | ||
2851 | out2: | ||
2852 | __free_page(vmx_msr_bitmap); | ||
2664 | out1: | 2853 | out1: |
2665 | __free_page(vmx_io_bitmap_b); | 2854 | __free_page(vmx_io_bitmap_b); |
2666 | out: | 2855 | out: |
@@ -2670,6 +2859,7 @@ out: | |||
2670 | 2859 | ||
2671 | static void __exit vmx_exit(void) | 2860 | static void __exit vmx_exit(void) |
2672 | { | 2861 | { |
2862 | __free_page(vmx_msr_bitmap); | ||
2673 | __free_page(vmx_io_bitmap_b); | 2863 | __free_page(vmx_io_bitmap_b); |
2674 | __free_page(vmx_io_bitmap_a); | 2864 | __free_page(vmx_io_bitmap_a); |
2675 | 2865 | ||
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index d52ae8d7303d..5dff4606b988 100644 --- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h | |||
@@ -49,6 +49,7 @@ | |||
49 | * Definitions of Secondary Processor-Based VM-Execution Controls. | 49 | * Definitions of Secondary Processor-Based VM-Execution Controls. |
50 | */ | 50 | */ |
51 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 | 51 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 |
52 | #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 | ||
52 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 | 53 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 |
53 | 54 | ||
54 | 55 | ||
@@ -65,6 +66,7 @@ | |||
65 | 66 | ||
66 | /* VMCS Encodings */ | 67 | /* VMCS Encodings */ |
67 | enum vmcs_field { | 68 | enum vmcs_field { |
69 | VIRTUAL_PROCESSOR_ID = 0x00000000, | ||
68 | GUEST_ES_SELECTOR = 0x00000800, | 70 | GUEST_ES_SELECTOR = 0x00000800, |
69 | GUEST_CS_SELECTOR = 0x00000802, | 71 | GUEST_CS_SELECTOR = 0x00000802, |
70 | GUEST_SS_SELECTOR = 0x00000804, | 72 | GUEST_SS_SELECTOR = 0x00000804, |
@@ -231,12 +233,12 @@ enum vmcs_field { | |||
231 | */ | 233 | */ |
232 | #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ | 234 | #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ |
233 | #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ | 235 | #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ |
234 | #define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */ | 236 | #define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ |
235 | #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ | 237 | #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ |
236 | 238 | ||
237 | #define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK | 239 | #define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK |
238 | #define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK | 240 | #define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK |
239 | #define VECTORING_INFO_DELIEVER_CODE_MASK INTR_INFO_DELIEVER_CODE_MASK | 241 | #define VECTORING_INFO_DELIVER_CODE_MASK INTR_INFO_DELIVER_CODE_MASK |
240 | #define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK | 242 | #define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK |
241 | 243 | ||
242 | #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ | 244 | #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ |
@@ -321,4 +323,8 @@ enum vmcs_field { | |||
321 | 323 | ||
322 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 | 324 | #define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9 |
323 | 325 | ||
326 | #define VMX_NR_VPIDS (1 << 16) | ||
327 | #define VMX_VPID_EXTENT_SINGLE_CONTEXT 1 | ||
328 | #define VMX_VPID_EXTENT_ALL_CONTEXT 2 | ||
329 | |||
324 | #endif | 330 | #endif |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6b01552bd1f1..0ce556372a4d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -15,10 +15,12 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kvm_host.h> | 17 | #include <linux/kvm_host.h> |
18 | #include "segment_descriptor.h" | ||
19 | #include "irq.h" | 18 | #include "irq.h" |
20 | #include "mmu.h" | 19 | #include "mmu.h" |
20 | #include "i8254.h" | ||
21 | #include "tss.h" | ||
21 | 22 | ||
23 | #include <linux/clocksource.h> | ||
22 | #include <linux/kvm.h> | 24 | #include <linux/kvm.h> |
23 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
24 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
@@ -28,6 +30,7 @@ | |||
28 | 30 | ||
29 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
30 | #include <asm/msr.h> | 32 | #include <asm/msr.h> |
33 | #include <asm/desc.h> | ||
31 | 34 | ||
32 | #define MAX_IO_MSRS 256 | 35 | #define MAX_IO_MSRS 256 |
33 | #define CR0_RESERVED_BITS \ | 36 | #define CR0_RESERVED_BITS \ |
@@ -41,7 +44,15 @@ | |||
41 | | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) | 44 | | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) |
42 | 45 | ||
43 | #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) | 46 | #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) |
44 | #define EFER_RESERVED_BITS 0xfffffffffffff2fe | 47 | /* EFER defaults: |
48 | * - enable syscall per default because its emulated by KVM | ||
49 | * - enable LME and LMA per default on 64 bit KVM | ||
50 | */ | ||
51 | #ifdef CONFIG_X86_64 | ||
52 | static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffafeULL; | ||
53 | #else | ||
54 | static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL; | ||
55 | #endif | ||
45 | 56 | ||
46 | #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM | 57 | #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM |
47 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | 58 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU |
@@ -63,6 +74,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
63 | { "irq_window", VCPU_STAT(irq_window_exits) }, | 74 | { "irq_window", VCPU_STAT(irq_window_exits) }, |
64 | { "halt_exits", VCPU_STAT(halt_exits) }, | 75 | { "halt_exits", VCPU_STAT(halt_exits) }, |
65 | { "halt_wakeup", VCPU_STAT(halt_wakeup) }, | 76 | { "halt_wakeup", VCPU_STAT(halt_wakeup) }, |
77 | { "hypercalls", VCPU_STAT(hypercalls) }, | ||
66 | { "request_irq", VCPU_STAT(request_irq_exits) }, | 78 | { "request_irq", VCPU_STAT(request_irq_exits) }, |
67 | { "irq_exits", VCPU_STAT(irq_exits) }, | 79 | { "irq_exits", VCPU_STAT(irq_exits) }, |
68 | { "host_state_reload", VCPU_STAT(host_state_reload) }, | 80 | { "host_state_reload", VCPU_STAT(host_state_reload) }, |
@@ -78,6 +90,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
78 | { "mmu_recycled", VM_STAT(mmu_recycled) }, | 90 | { "mmu_recycled", VM_STAT(mmu_recycled) }, |
79 | { "mmu_cache_miss", VM_STAT(mmu_cache_miss) }, | 91 | { "mmu_cache_miss", VM_STAT(mmu_cache_miss) }, |
80 | { "remote_tlb_flush", VM_STAT(remote_tlb_flush) }, | 92 | { "remote_tlb_flush", VM_STAT(remote_tlb_flush) }, |
93 | { "largepages", VM_STAT(lpages) }, | ||
81 | { NULL } | 94 | { NULL } |
82 | }; | 95 | }; |
83 | 96 | ||
@@ -85,7 +98,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
85 | unsigned long segment_base(u16 selector) | 98 | unsigned long segment_base(u16 selector) |
86 | { | 99 | { |
87 | struct descriptor_table gdt; | 100 | struct descriptor_table gdt; |
88 | struct segment_descriptor *d; | 101 | struct desc_struct *d; |
89 | unsigned long table_base; | 102 | unsigned long table_base; |
90 | unsigned long v; | 103 | unsigned long v; |
91 | 104 | ||
@@ -101,13 +114,12 @@ unsigned long segment_base(u16 selector) | |||
101 | asm("sldt %0" : "=g"(ldt_selector)); | 114 | asm("sldt %0" : "=g"(ldt_selector)); |
102 | table_base = segment_base(ldt_selector); | 115 | table_base = segment_base(ldt_selector); |
103 | } | 116 | } |
104 | d = (struct segment_descriptor *)(table_base + (selector & ~7)); | 117 | d = (struct desc_struct *)(table_base + (selector & ~7)); |
105 | v = d->base_low | ((unsigned long)d->base_mid << 16) | | 118 | v = d->base0 | ((unsigned long)d->base1 << 16) | |
106 | ((unsigned long)d->base_high << 24); | 119 | ((unsigned long)d->base2 << 24); |
107 | #ifdef CONFIG_X86_64 | 120 | #ifdef CONFIG_X86_64 |
108 | if (d->system == 0 && (d->type == 2 || d->type == 9 || d->type == 11)) | 121 | if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11)) |
109 | v |= ((unsigned long) \ | 122 | v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32; |
110 | ((struct segment_descriptor_64 *)d)->base_higher) << 32; | ||
111 | #endif | 123 | #endif |
112 | return v; | 124 | return v; |
113 | } | 125 | } |
@@ -145,11 +157,16 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr, | |||
145 | u32 error_code) | 157 | u32 error_code) |
146 | { | 158 | { |
147 | ++vcpu->stat.pf_guest; | 159 | ++vcpu->stat.pf_guest; |
148 | if (vcpu->arch.exception.pending && vcpu->arch.exception.nr == PF_VECTOR) { | 160 | if (vcpu->arch.exception.pending) { |
149 | printk(KERN_DEBUG "kvm: inject_page_fault:" | 161 | if (vcpu->arch.exception.nr == PF_VECTOR) { |
150 | " double fault 0x%lx\n", addr); | 162 | printk(KERN_DEBUG "kvm: inject_page_fault:" |
151 | vcpu->arch.exception.nr = DF_VECTOR; | 163 | " double fault 0x%lx\n", addr); |
152 | vcpu->arch.exception.error_code = 0; | 164 | vcpu->arch.exception.nr = DF_VECTOR; |
165 | vcpu->arch.exception.error_code = 0; | ||
166 | } else if (vcpu->arch.exception.nr == DF_VECTOR) { | ||
167 | /* triple fault -> shutdown */ | ||
168 | set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); | ||
169 | } | ||
153 | return; | 170 | return; |
154 | } | 171 | } |
155 | vcpu->arch.cr2 = addr; | 172 | vcpu->arch.cr2 = addr; |
@@ -184,7 +201,6 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
184 | int ret; | 201 | int ret; |
185 | u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; | 202 | u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)]; |
186 | 203 | ||
187 | down_read(&vcpu->kvm->slots_lock); | ||
188 | ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, | 204 | ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte, |
189 | offset * sizeof(u64), sizeof(pdpte)); | 205 | offset * sizeof(u64), sizeof(pdpte)); |
190 | if (ret < 0) { | 206 | if (ret < 0) { |
@@ -201,10 +217,10 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
201 | 217 | ||
202 | memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); | 218 | memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)); |
203 | out: | 219 | out: |
204 | up_read(&vcpu->kvm->slots_lock); | ||
205 | 220 | ||
206 | return ret; | 221 | return ret; |
207 | } | 222 | } |
223 | EXPORT_SYMBOL_GPL(load_pdptrs); | ||
208 | 224 | ||
209 | static bool pdptrs_changed(struct kvm_vcpu *vcpu) | 225 | static bool pdptrs_changed(struct kvm_vcpu *vcpu) |
210 | { | 226 | { |
@@ -215,18 +231,16 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu) | |||
215 | if (is_long_mode(vcpu) || !is_pae(vcpu)) | 231 | if (is_long_mode(vcpu) || !is_pae(vcpu)) |
216 | return false; | 232 | return false; |
217 | 233 | ||
218 | down_read(&vcpu->kvm->slots_lock); | ||
219 | r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); | 234 | r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte)); |
220 | if (r < 0) | 235 | if (r < 0) |
221 | goto out; | 236 | goto out; |
222 | changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; | 237 | changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0; |
223 | out: | 238 | out: |
224 | up_read(&vcpu->kvm->slots_lock); | ||
225 | 239 | ||
226 | return changed; | 240 | return changed; |
227 | } | 241 | } |
228 | 242 | ||
229 | void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | 243 | void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) |
230 | { | 244 | { |
231 | if (cr0 & CR0_RESERVED_BITS) { | 245 | if (cr0 & CR0_RESERVED_BITS) { |
232 | printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", | 246 | printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", |
@@ -284,15 +298,18 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
284 | kvm_mmu_reset_context(vcpu); | 298 | kvm_mmu_reset_context(vcpu); |
285 | return; | 299 | return; |
286 | } | 300 | } |
287 | EXPORT_SYMBOL_GPL(set_cr0); | 301 | EXPORT_SYMBOL_GPL(kvm_set_cr0); |
288 | 302 | ||
289 | void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) | 303 | void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) |
290 | { | 304 | { |
291 | set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)); | 305 | kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)); |
306 | KVMTRACE_1D(LMSW, vcpu, | ||
307 | (u32)((vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)), | ||
308 | handler); | ||
292 | } | 309 | } |
293 | EXPORT_SYMBOL_GPL(lmsw); | 310 | EXPORT_SYMBOL_GPL(kvm_lmsw); |
294 | 311 | ||
295 | void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | 312 | void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) |
296 | { | 313 | { |
297 | if (cr4 & CR4_RESERVED_BITS) { | 314 | if (cr4 & CR4_RESERVED_BITS) { |
298 | printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); | 315 | printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); |
@@ -323,9 +340,9 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | |||
323 | vcpu->arch.cr4 = cr4; | 340 | vcpu->arch.cr4 = cr4; |
324 | kvm_mmu_reset_context(vcpu); | 341 | kvm_mmu_reset_context(vcpu); |
325 | } | 342 | } |
326 | EXPORT_SYMBOL_GPL(set_cr4); | 343 | EXPORT_SYMBOL_GPL(kvm_set_cr4); |
327 | 344 | ||
328 | void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | 345 | void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) |
329 | { | 346 | { |
330 | if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) { | 347 | if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) { |
331 | kvm_mmu_flush_tlb(vcpu); | 348 | kvm_mmu_flush_tlb(vcpu); |
@@ -359,7 +376,6 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
359 | */ | 376 | */ |
360 | } | 377 | } |
361 | 378 | ||
362 | down_read(&vcpu->kvm->slots_lock); | ||
363 | /* | 379 | /* |
364 | * Does the new cr3 value map to physical memory? (Note, we | 380 | * Does the new cr3 value map to physical memory? (Note, we |
365 | * catch an invalid cr3 even in real-mode, because it would | 381 | * catch an invalid cr3 even in real-mode, because it would |
@@ -375,11 +391,10 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
375 | vcpu->arch.cr3 = cr3; | 391 | vcpu->arch.cr3 = cr3; |
376 | vcpu->arch.mmu.new_cr3(vcpu); | 392 | vcpu->arch.mmu.new_cr3(vcpu); |
377 | } | 393 | } |
378 | up_read(&vcpu->kvm->slots_lock); | ||
379 | } | 394 | } |
380 | EXPORT_SYMBOL_GPL(set_cr3); | 395 | EXPORT_SYMBOL_GPL(kvm_set_cr3); |
381 | 396 | ||
382 | void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | 397 | void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) |
383 | { | 398 | { |
384 | if (cr8 & CR8_RESERVED_BITS) { | 399 | if (cr8 & CR8_RESERVED_BITS) { |
385 | printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); | 400 | printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); |
@@ -391,16 +406,16 @@ void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
391 | else | 406 | else |
392 | vcpu->arch.cr8 = cr8; | 407 | vcpu->arch.cr8 = cr8; |
393 | } | 408 | } |
394 | EXPORT_SYMBOL_GPL(set_cr8); | 409 | EXPORT_SYMBOL_GPL(kvm_set_cr8); |
395 | 410 | ||
396 | unsigned long get_cr8(struct kvm_vcpu *vcpu) | 411 | unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) |
397 | { | 412 | { |
398 | if (irqchip_in_kernel(vcpu->kvm)) | 413 | if (irqchip_in_kernel(vcpu->kvm)) |
399 | return kvm_lapic_get_cr8(vcpu); | 414 | return kvm_lapic_get_cr8(vcpu); |
400 | else | 415 | else |
401 | return vcpu->arch.cr8; | 416 | return vcpu->arch.cr8; |
402 | } | 417 | } |
403 | EXPORT_SYMBOL_GPL(get_cr8); | 418 | EXPORT_SYMBOL_GPL(kvm_get_cr8); |
404 | 419 | ||
405 | /* | 420 | /* |
406 | * List of msr numbers which we expose to userspace through KVM_GET_MSRS | 421 | * List of msr numbers which we expose to userspace through KVM_GET_MSRS |
@@ -415,7 +430,8 @@ static u32 msrs_to_save[] = { | |||
415 | #ifdef CONFIG_X86_64 | 430 | #ifdef CONFIG_X86_64 |
416 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, | 431 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, |
417 | #endif | 432 | #endif |
418 | MSR_IA32_TIME_STAMP_COUNTER, | 433 | MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, |
434 | MSR_IA32_PERF_STATUS, | ||
419 | }; | 435 | }; |
420 | 436 | ||
421 | static unsigned num_msrs_to_save; | 437 | static unsigned num_msrs_to_save; |
@@ -424,11 +440,9 @@ static u32 emulated_msrs[] = { | |||
424 | MSR_IA32_MISC_ENABLE, | 440 | MSR_IA32_MISC_ENABLE, |
425 | }; | 441 | }; |
426 | 442 | ||
427 | #ifdef CONFIG_X86_64 | ||
428 | |||
429 | static void set_efer(struct kvm_vcpu *vcpu, u64 efer) | 443 | static void set_efer(struct kvm_vcpu *vcpu, u64 efer) |
430 | { | 444 | { |
431 | if (efer & EFER_RESERVED_BITS) { | 445 | if (efer & efer_reserved_bits) { |
432 | printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", | 446 | printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", |
433 | efer); | 447 | efer); |
434 | kvm_inject_gp(vcpu, 0); | 448 | kvm_inject_gp(vcpu, 0); |
@@ -450,7 +464,12 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) | |||
450 | vcpu->arch.shadow_efer = efer; | 464 | vcpu->arch.shadow_efer = efer; |
451 | } | 465 | } |
452 | 466 | ||
453 | #endif | 467 | void kvm_enable_efer_bits(u64 mask) |
468 | { | ||
469 | efer_reserved_bits &= ~mask; | ||
470 | } | ||
471 | EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); | ||
472 | |||
454 | 473 | ||
455 | /* | 474 | /* |
456 | * Writes msr value into into the appropriate "register". | 475 | * Writes msr value into into the appropriate "register". |
@@ -470,26 +489,86 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) | |||
470 | return kvm_set_msr(vcpu, index, *data); | 489 | return kvm_set_msr(vcpu, index, *data); |
471 | } | 490 | } |
472 | 491 | ||
492 | static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock) | ||
493 | { | ||
494 | static int version; | ||
495 | struct kvm_wall_clock wc; | ||
496 | struct timespec wc_ts; | ||
497 | |||
498 | if (!wall_clock) | ||
499 | return; | ||
500 | |||
501 | version++; | ||
502 | |||
503 | kvm_write_guest(kvm, wall_clock, &version, sizeof(version)); | ||
504 | |||
505 | wc_ts = current_kernel_time(); | ||
506 | wc.wc_sec = wc_ts.tv_sec; | ||
507 | wc.wc_nsec = wc_ts.tv_nsec; | ||
508 | wc.wc_version = version; | ||
509 | |||
510 | kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc)); | ||
511 | |||
512 | version++; | ||
513 | kvm_write_guest(kvm, wall_clock, &version, sizeof(version)); | ||
514 | } | ||
515 | |||
516 | static void kvm_write_guest_time(struct kvm_vcpu *v) | ||
517 | { | ||
518 | struct timespec ts; | ||
519 | unsigned long flags; | ||
520 | struct kvm_vcpu_arch *vcpu = &v->arch; | ||
521 | void *shared_kaddr; | ||
522 | |||
523 | if ((!vcpu->time_page)) | ||
524 | return; | ||
525 | |||
526 | /* Keep irq disabled to prevent changes to the clock */ | ||
527 | local_irq_save(flags); | ||
528 | kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER, | ||
529 | &vcpu->hv_clock.tsc_timestamp); | ||
530 | ktime_get_ts(&ts); | ||
531 | local_irq_restore(flags); | ||
532 | |||
533 | /* With all the info we got, fill in the values */ | ||
534 | |||
535 | vcpu->hv_clock.system_time = ts.tv_nsec + | ||
536 | (NSEC_PER_SEC * (u64)ts.tv_sec); | ||
537 | /* | ||
538 | * The interface expects us to write an even number signaling that the | ||
539 | * update is finished. Since the guest won't see the intermediate | ||
540 | * state, we just write "2" at the end | ||
541 | */ | ||
542 | vcpu->hv_clock.version = 2; | ||
543 | |||
544 | shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0); | ||
545 | |||
546 | memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock, | ||
547 | sizeof(vcpu->hv_clock)); | ||
548 | |||
549 | kunmap_atomic(shared_kaddr, KM_USER0); | ||
550 | |||
551 | mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); | ||
552 | } | ||
553 | |||
473 | 554 | ||
474 | int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) | 555 | int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) |
475 | { | 556 | { |
476 | switch (msr) { | 557 | switch (msr) { |
477 | #ifdef CONFIG_X86_64 | ||
478 | case MSR_EFER: | 558 | case MSR_EFER: |
479 | set_efer(vcpu, data); | 559 | set_efer(vcpu, data); |
480 | break; | 560 | break; |
481 | #endif | ||
482 | case MSR_IA32_MC0_STATUS: | 561 | case MSR_IA32_MC0_STATUS: |
483 | pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", | 562 | pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", |
484 | __FUNCTION__, data); | 563 | __func__, data); |
485 | break; | 564 | break; |
486 | case MSR_IA32_MCG_STATUS: | 565 | case MSR_IA32_MCG_STATUS: |
487 | pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", | 566 | pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", |
488 | __FUNCTION__, data); | 567 | __func__, data); |
489 | break; | 568 | break; |
490 | case MSR_IA32_MCG_CTL: | 569 | case MSR_IA32_MCG_CTL: |
491 | pr_unimpl(vcpu, "%s: MSR_IA32_MCG_CTL 0x%llx, nop\n", | 570 | pr_unimpl(vcpu, "%s: MSR_IA32_MCG_CTL 0x%llx, nop\n", |
492 | __FUNCTION__, data); | 571 | __func__, data); |
493 | break; | 572 | break; |
494 | case MSR_IA32_UCODE_REV: | 573 | case MSR_IA32_UCODE_REV: |
495 | case MSR_IA32_UCODE_WRITE: | 574 | case MSR_IA32_UCODE_WRITE: |
@@ -501,6 +580,42 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) | |||
501 | case MSR_IA32_MISC_ENABLE: | 580 | case MSR_IA32_MISC_ENABLE: |
502 | vcpu->arch.ia32_misc_enable_msr = data; | 581 | vcpu->arch.ia32_misc_enable_msr = data; |
503 | break; | 582 | break; |
583 | case MSR_KVM_WALL_CLOCK: | ||
584 | vcpu->kvm->arch.wall_clock = data; | ||
585 | kvm_write_wall_clock(vcpu->kvm, data); | ||
586 | break; | ||
587 | case MSR_KVM_SYSTEM_TIME: { | ||
588 | if (vcpu->arch.time_page) { | ||
589 | kvm_release_page_dirty(vcpu->arch.time_page); | ||
590 | vcpu->arch.time_page = NULL; | ||
591 | } | ||
592 | |||
593 | vcpu->arch.time = data; | ||
594 | |||
595 | /* we verify if the enable bit is set... */ | ||
596 | if (!(data & 1)) | ||
597 | break; | ||
598 | |||
599 | /* ...but clean it before doing the actual write */ | ||
600 | vcpu->arch.time_offset = data & ~(PAGE_MASK | 1); | ||
601 | |||
602 | vcpu->arch.hv_clock.tsc_to_system_mul = | ||
603 | clocksource_khz2mult(tsc_khz, 22); | ||
604 | vcpu->arch.hv_clock.tsc_shift = 22; | ||
605 | |||
606 | down_read(¤t->mm->mmap_sem); | ||
607 | vcpu->arch.time_page = | ||
608 | gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); | ||
609 | up_read(¤t->mm->mmap_sem); | ||
610 | |||
611 | if (is_error_page(vcpu->arch.time_page)) { | ||
612 | kvm_release_page_clean(vcpu->arch.time_page); | ||
613 | vcpu->arch.time_page = NULL; | ||
614 | } | ||
615 | |||
616 | kvm_write_guest_time(vcpu); | ||
617 | break; | ||
618 | } | ||
504 | default: | 619 | default: |
505 | pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data); | 620 | pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data); |
506 | return 1; | 621 | return 1; |
@@ -540,7 +655,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |||
540 | case MSR_IA32_MC0_MISC+12: | 655 | case MSR_IA32_MC0_MISC+12: |
541 | case MSR_IA32_MC0_MISC+16: | 656 | case MSR_IA32_MC0_MISC+16: |
542 | case MSR_IA32_UCODE_REV: | 657 | case MSR_IA32_UCODE_REV: |
543 | case MSR_IA32_PERF_STATUS: | ||
544 | case MSR_IA32_EBL_CR_POWERON: | 658 | case MSR_IA32_EBL_CR_POWERON: |
545 | /* MTRR registers */ | 659 | /* MTRR registers */ |
546 | case 0xfe: | 660 | case 0xfe: |
@@ -556,11 +670,21 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |||
556 | case MSR_IA32_MISC_ENABLE: | 670 | case MSR_IA32_MISC_ENABLE: |
557 | data = vcpu->arch.ia32_misc_enable_msr; | 671 | data = vcpu->arch.ia32_misc_enable_msr; |
558 | break; | 672 | break; |
559 | #ifdef CONFIG_X86_64 | 673 | case MSR_IA32_PERF_STATUS: |
674 | /* TSC increment by tick */ | ||
675 | data = 1000ULL; | ||
676 | /* CPU multiplier */ | ||
677 | data |= (((uint64_t)4ULL) << 40); | ||
678 | break; | ||
560 | case MSR_EFER: | 679 | case MSR_EFER: |
561 | data = vcpu->arch.shadow_efer; | 680 | data = vcpu->arch.shadow_efer; |
562 | break; | 681 | break; |
563 | #endif | 682 | case MSR_KVM_WALL_CLOCK: |
683 | data = vcpu->kvm->arch.wall_clock; | ||
684 | break; | ||
685 | case MSR_KVM_SYSTEM_TIME: | ||
686 | data = vcpu->arch.time; | ||
687 | break; | ||
564 | default: | 688 | default: |
565 | pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); | 689 | pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); |
566 | return 1; | 690 | return 1; |
@@ -584,9 +708,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, | |||
584 | 708 | ||
585 | vcpu_load(vcpu); | 709 | vcpu_load(vcpu); |
586 | 710 | ||
711 | down_read(&vcpu->kvm->slots_lock); | ||
587 | for (i = 0; i < msrs->nmsrs; ++i) | 712 | for (i = 0; i < msrs->nmsrs; ++i) |
588 | if (do_msr(vcpu, entries[i].index, &entries[i].data)) | 713 | if (do_msr(vcpu, entries[i].index, &entries[i].data)) |
589 | break; | 714 | break; |
715 | up_read(&vcpu->kvm->slots_lock); | ||
590 | 716 | ||
591 | vcpu_put(vcpu); | 717 | vcpu_put(vcpu); |
592 | 718 | ||
@@ -688,11 +814,24 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
688 | case KVM_CAP_USER_MEMORY: | 814 | case KVM_CAP_USER_MEMORY: |
689 | case KVM_CAP_SET_TSS_ADDR: | 815 | case KVM_CAP_SET_TSS_ADDR: |
690 | case KVM_CAP_EXT_CPUID: | 816 | case KVM_CAP_EXT_CPUID: |
817 | case KVM_CAP_CLOCKSOURCE: | ||
818 | case KVM_CAP_PIT: | ||
819 | case KVM_CAP_NOP_IO_DELAY: | ||
820 | case KVM_CAP_MP_STATE: | ||
691 | r = 1; | 821 | r = 1; |
692 | break; | 822 | break; |
693 | case KVM_CAP_VAPIC: | 823 | case KVM_CAP_VAPIC: |
694 | r = !kvm_x86_ops->cpu_has_accelerated_tpr(); | 824 | r = !kvm_x86_ops->cpu_has_accelerated_tpr(); |
695 | break; | 825 | break; |
826 | case KVM_CAP_NR_VCPUS: | ||
827 | r = KVM_MAX_VCPUS; | ||
828 | break; | ||
829 | case KVM_CAP_NR_MEMSLOTS: | ||
830 | r = KVM_MEMORY_SLOTS; | ||
831 | break; | ||
832 | case KVM_CAP_PV_MMU: | ||
833 | r = !tdp_enabled; | ||
834 | break; | ||
696 | default: | 835 | default: |
697 | r = 0; | 836 | r = 0; |
698 | break; | 837 | break; |
@@ -763,6 +902,7 @@ out: | |||
763 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 902 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
764 | { | 903 | { |
765 | kvm_x86_ops->vcpu_load(vcpu, cpu); | 904 | kvm_x86_ops->vcpu_load(vcpu, cpu); |
905 | kvm_write_guest_time(vcpu); | ||
766 | } | 906 | } |
767 | 907 | ||
768 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 908 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) |
@@ -958,32 +1098,32 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, | |||
958 | } | 1098 | } |
959 | /* function 4 and 0xb have additional index. */ | 1099 | /* function 4 and 0xb have additional index. */ |
960 | case 4: { | 1100 | case 4: { |
961 | int index, cache_type; | 1101 | int i, cache_type; |
962 | 1102 | ||
963 | entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; | 1103 | entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; |
964 | /* read more entries until cache_type is zero */ | 1104 | /* read more entries until cache_type is zero */ |
965 | for (index = 1; *nent < maxnent; ++index) { | 1105 | for (i = 1; *nent < maxnent; ++i) { |
966 | cache_type = entry[index - 1].eax & 0x1f; | 1106 | cache_type = entry[i - 1].eax & 0x1f; |
967 | if (!cache_type) | 1107 | if (!cache_type) |
968 | break; | 1108 | break; |
969 | do_cpuid_1_ent(&entry[index], function, index); | 1109 | do_cpuid_1_ent(&entry[i], function, i); |
970 | entry[index].flags |= | 1110 | entry[i].flags |= |
971 | KVM_CPUID_FLAG_SIGNIFCANT_INDEX; | 1111 | KVM_CPUID_FLAG_SIGNIFCANT_INDEX; |
972 | ++*nent; | 1112 | ++*nent; |
973 | } | 1113 | } |
974 | break; | 1114 | break; |
975 | } | 1115 | } |
976 | case 0xb: { | 1116 | case 0xb: { |
977 | int index, level_type; | 1117 | int i, level_type; |
978 | 1118 | ||
979 | entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; | 1119 | entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; |
980 | /* read more entries until level_type is zero */ | 1120 | /* read more entries until level_type is zero */ |
981 | for (index = 1; *nent < maxnent; ++index) { | 1121 | for (i = 1; *nent < maxnent; ++i) { |
982 | level_type = entry[index - 1].ecx & 0xff; | 1122 | level_type = entry[i - 1].ecx & 0xff; |
983 | if (!level_type) | 1123 | if (!level_type) |
984 | break; | 1124 | break; |
985 | do_cpuid_1_ent(&entry[index], function, index); | 1125 | do_cpuid_1_ent(&entry[i], function, i); |
986 | entry[index].flags |= | 1126 | entry[i].flags |= |
987 | KVM_CPUID_FLAG_SIGNIFCANT_INDEX; | 1127 | KVM_CPUID_FLAG_SIGNIFCANT_INDEX; |
988 | ++*nent; | 1128 | ++*nent; |
989 | } | 1129 | } |
@@ -1365,6 +1505,23 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | |||
1365 | return r; | 1505 | return r; |
1366 | } | 1506 | } |
1367 | 1507 | ||
1508 | static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps) | ||
1509 | { | ||
1510 | int r = 0; | ||
1511 | |||
1512 | memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state)); | ||
1513 | return r; | ||
1514 | } | ||
1515 | |||
1516 | static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps) | ||
1517 | { | ||
1518 | int r = 0; | ||
1519 | |||
1520 | memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state)); | ||
1521 | kvm_pit_load_count(kvm, 0, ps->channels[0].count); | ||
1522 | return r; | ||
1523 | } | ||
1524 | |||
1368 | /* | 1525 | /* |
1369 | * Get (and clear) the dirty memory log for a memory slot. | 1526 | * Get (and clear) the dirty memory log for a memory slot. |
1370 | */ | 1527 | */ |
@@ -1457,6 +1614,12 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
1457 | } else | 1614 | } else |
1458 | goto out; | 1615 | goto out; |
1459 | break; | 1616 | break; |
1617 | case KVM_CREATE_PIT: | ||
1618 | r = -ENOMEM; | ||
1619 | kvm->arch.vpit = kvm_create_pit(kvm); | ||
1620 | if (kvm->arch.vpit) | ||
1621 | r = 0; | ||
1622 | break; | ||
1460 | case KVM_IRQ_LINE: { | 1623 | case KVM_IRQ_LINE: { |
1461 | struct kvm_irq_level irq_event; | 1624 | struct kvm_irq_level irq_event; |
1462 | 1625 | ||
@@ -1512,6 +1675,37 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
1512 | r = 0; | 1675 | r = 0; |
1513 | break; | 1676 | break; |
1514 | } | 1677 | } |
1678 | case KVM_GET_PIT: { | ||
1679 | struct kvm_pit_state ps; | ||
1680 | r = -EFAULT; | ||
1681 | if (copy_from_user(&ps, argp, sizeof ps)) | ||
1682 | goto out; | ||
1683 | r = -ENXIO; | ||
1684 | if (!kvm->arch.vpit) | ||
1685 | goto out; | ||
1686 | r = kvm_vm_ioctl_get_pit(kvm, &ps); | ||
1687 | if (r) | ||
1688 | goto out; | ||
1689 | r = -EFAULT; | ||
1690 | if (copy_to_user(argp, &ps, sizeof ps)) | ||
1691 | goto out; | ||
1692 | r = 0; | ||
1693 | break; | ||
1694 | } | ||
1695 | case KVM_SET_PIT: { | ||
1696 | struct kvm_pit_state ps; | ||
1697 | r = -EFAULT; | ||
1698 | if (copy_from_user(&ps, argp, sizeof ps)) | ||
1699 | goto out; | ||
1700 | r = -ENXIO; | ||
1701 | if (!kvm->arch.vpit) | ||
1702 | goto out; | ||
1703 | r = kvm_vm_ioctl_set_pit(kvm, &ps); | ||
1704 | if (r) | ||
1705 | goto out; | ||
1706 | r = 0; | ||
1707 | break; | ||
1708 | } | ||
1515 | default: | 1709 | default: |
1516 | ; | 1710 | ; |
1517 | } | 1711 | } |
@@ -1570,7 +1764,6 @@ int emulator_read_std(unsigned long addr, | |||
1570 | void *data = val; | 1764 | void *data = val; |
1571 | int r = X86EMUL_CONTINUE; | 1765 | int r = X86EMUL_CONTINUE; |
1572 | 1766 | ||
1573 | down_read(&vcpu->kvm->slots_lock); | ||
1574 | while (bytes) { | 1767 | while (bytes) { |
1575 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1768 | gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1576 | unsigned offset = addr & (PAGE_SIZE-1); | 1769 | unsigned offset = addr & (PAGE_SIZE-1); |
@@ -1592,7 +1785,6 @@ int emulator_read_std(unsigned long addr, | |||
1592 | addr += tocopy; | 1785 | addr += tocopy; |
1593 | } | 1786 | } |
1594 | out: | 1787 | out: |
1595 | up_read(&vcpu->kvm->slots_lock); | ||
1596 | return r; | 1788 | return r; |
1597 | } | 1789 | } |
1598 | EXPORT_SYMBOL_GPL(emulator_read_std); | 1790 | EXPORT_SYMBOL_GPL(emulator_read_std); |
@@ -1611,9 +1803,7 @@ static int emulator_read_emulated(unsigned long addr, | |||
1611 | return X86EMUL_CONTINUE; | 1803 | return X86EMUL_CONTINUE; |
1612 | } | 1804 | } |
1613 | 1805 | ||
1614 | down_read(&vcpu->kvm->slots_lock); | ||
1615 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1806 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1616 | up_read(&vcpu->kvm->slots_lock); | ||
1617 | 1807 | ||
1618 | /* For APIC access vmexit */ | 1808 | /* For APIC access vmexit */ |
1619 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) | 1809 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) |
@@ -1646,19 +1836,15 @@ mmio: | |||
1646 | return X86EMUL_UNHANDLEABLE; | 1836 | return X86EMUL_UNHANDLEABLE; |
1647 | } | 1837 | } |
1648 | 1838 | ||
1649 | static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | 1839 | int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, |
1650 | const void *val, int bytes) | 1840 | const void *val, int bytes) |
1651 | { | 1841 | { |
1652 | int ret; | 1842 | int ret; |
1653 | 1843 | ||
1654 | down_read(&vcpu->kvm->slots_lock); | ||
1655 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); | 1844 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); |
1656 | if (ret < 0) { | 1845 | if (ret < 0) |
1657 | up_read(&vcpu->kvm->slots_lock); | ||
1658 | return 0; | 1846 | return 0; |
1659 | } | ||
1660 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); | 1847 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); |
1661 | up_read(&vcpu->kvm->slots_lock); | ||
1662 | return 1; | 1848 | return 1; |
1663 | } | 1849 | } |
1664 | 1850 | ||
@@ -1670,9 +1856,7 @@ static int emulator_write_emulated_onepage(unsigned long addr, | |||
1670 | struct kvm_io_device *mmio_dev; | 1856 | struct kvm_io_device *mmio_dev; |
1671 | gpa_t gpa; | 1857 | gpa_t gpa; |
1672 | 1858 | ||
1673 | down_read(&vcpu->kvm->slots_lock); | ||
1674 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1859 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1675 | up_read(&vcpu->kvm->slots_lock); | ||
1676 | 1860 | ||
1677 | if (gpa == UNMAPPED_GVA) { | 1861 | if (gpa == UNMAPPED_GVA) { |
1678 | kvm_inject_page_fault(vcpu, addr, 2); | 1862 | kvm_inject_page_fault(vcpu, addr, 2); |
@@ -1749,7 +1933,6 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1749 | char *kaddr; | 1933 | char *kaddr; |
1750 | u64 val; | 1934 | u64 val; |
1751 | 1935 | ||
1752 | down_read(&vcpu->kvm->slots_lock); | ||
1753 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); | 1936 | gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr); |
1754 | 1937 | ||
1755 | if (gpa == UNMAPPED_GVA || | 1938 | if (gpa == UNMAPPED_GVA || |
@@ -1769,9 +1952,8 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1769 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); | 1952 | set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); |
1770 | kunmap_atomic(kaddr, KM_USER0); | 1953 | kunmap_atomic(kaddr, KM_USER0); |
1771 | kvm_release_page_dirty(page); | 1954 | kvm_release_page_dirty(page); |
1772 | emul_write: | ||
1773 | up_read(&vcpu->kvm->slots_lock); | ||
1774 | } | 1955 | } |
1956 | emul_write: | ||
1775 | #endif | 1957 | #endif |
1776 | 1958 | ||
1777 | return emulator_write_emulated(addr, new, bytes, vcpu); | 1959 | return emulator_write_emulated(addr, new, bytes, vcpu); |
@@ -1802,7 +1984,7 @@ int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) | |||
1802 | *dest = kvm_x86_ops->get_dr(vcpu, dr); | 1984 | *dest = kvm_x86_ops->get_dr(vcpu, dr); |
1803 | return X86EMUL_CONTINUE; | 1985 | return X86EMUL_CONTINUE; |
1804 | default: | 1986 | default: |
1805 | pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); | 1987 | pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr); |
1806 | return X86EMUL_UNHANDLEABLE; | 1988 | return X86EMUL_UNHANDLEABLE; |
1807 | } | 1989 | } |
1808 | } | 1990 | } |
@@ -1840,7 +2022,7 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) | |||
1840 | } | 2022 | } |
1841 | EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); | 2023 | EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); |
1842 | 2024 | ||
1843 | struct x86_emulate_ops emulate_ops = { | 2025 | static struct x86_emulate_ops emulate_ops = { |
1844 | .read_std = emulator_read_std, | 2026 | .read_std = emulator_read_std, |
1845 | .read_emulated = emulator_read_emulated, | 2027 | .read_emulated = emulator_read_emulated, |
1846 | .write_emulated = emulator_write_emulated, | 2028 | .write_emulated = emulator_write_emulated, |
@@ -2091,6 +2273,13 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2091 | vcpu->arch.pio.guest_page_offset = 0; | 2273 | vcpu->arch.pio.guest_page_offset = 0; |
2092 | vcpu->arch.pio.rep = 0; | 2274 | vcpu->arch.pio.rep = 0; |
2093 | 2275 | ||
2276 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) | ||
2277 | KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size, | ||
2278 | handler); | ||
2279 | else | ||
2280 | KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size, | ||
2281 | handler); | ||
2282 | |||
2094 | kvm_x86_ops->cache_regs(vcpu); | 2283 | kvm_x86_ops->cache_regs(vcpu); |
2095 | memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4); | 2284 | memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4); |
2096 | kvm_x86_ops->decache_regs(vcpu); | 2285 | kvm_x86_ops->decache_regs(vcpu); |
@@ -2129,6 +2318,13 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2129 | vcpu->arch.pio.guest_page_offset = offset_in_page(address); | 2318 | vcpu->arch.pio.guest_page_offset = offset_in_page(address); |
2130 | vcpu->arch.pio.rep = rep; | 2319 | vcpu->arch.pio.rep = rep; |
2131 | 2320 | ||
2321 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) | ||
2322 | KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size, | ||
2323 | handler); | ||
2324 | else | ||
2325 | KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size, | ||
2326 | handler); | ||
2327 | |||
2132 | if (!count) { | 2328 | if (!count) { |
2133 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2329 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2134 | return 1; | 2330 | return 1; |
@@ -2163,10 +2359,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2163 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2359 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2164 | 2360 | ||
2165 | for (i = 0; i < nr_pages; ++i) { | 2361 | for (i = 0; i < nr_pages; ++i) { |
2166 | down_read(&vcpu->kvm->slots_lock); | ||
2167 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | 2362 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); |
2168 | vcpu->arch.pio.guest_pages[i] = page; | 2363 | vcpu->arch.pio.guest_pages[i] = page; |
2169 | up_read(&vcpu->kvm->slots_lock); | ||
2170 | if (!page) { | 2364 | if (!page) { |
2171 | kvm_inject_gp(vcpu, 0); | 2365 | kvm_inject_gp(vcpu, 0); |
2172 | free_pio_guest_pages(vcpu); | 2366 | free_pio_guest_pages(vcpu); |
@@ -2238,10 +2432,13 @@ void kvm_arch_exit(void) | |||
2238 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) | 2432 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) |
2239 | { | 2433 | { |
2240 | ++vcpu->stat.halt_exits; | 2434 | ++vcpu->stat.halt_exits; |
2435 | KVMTRACE_0D(HLT, vcpu, handler); | ||
2241 | if (irqchip_in_kernel(vcpu->kvm)) { | 2436 | if (irqchip_in_kernel(vcpu->kvm)) { |
2242 | vcpu->arch.mp_state = VCPU_MP_STATE_HALTED; | 2437 | vcpu->arch.mp_state = KVM_MP_STATE_HALTED; |
2438 | up_read(&vcpu->kvm->slots_lock); | ||
2243 | kvm_vcpu_block(vcpu); | 2439 | kvm_vcpu_block(vcpu); |
2244 | if (vcpu->arch.mp_state != VCPU_MP_STATE_RUNNABLE) | 2440 | down_read(&vcpu->kvm->slots_lock); |
2441 | if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) | ||
2245 | return -EINTR; | 2442 | return -EINTR; |
2246 | return 1; | 2443 | return 1; |
2247 | } else { | 2444 | } else { |
@@ -2251,9 +2448,19 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu) | |||
2251 | } | 2448 | } |
2252 | EXPORT_SYMBOL_GPL(kvm_emulate_halt); | 2449 | EXPORT_SYMBOL_GPL(kvm_emulate_halt); |
2253 | 2450 | ||
2451 | static inline gpa_t hc_gpa(struct kvm_vcpu *vcpu, unsigned long a0, | ||
2452 | unsigned long a1) | ||
2453 | { | ||
2454 | if (is_long_mode(vcpu)) | ||
2455 | return a0; | ||
2456 | else | ||
2457 | return a0 | ((gpa_t)a1 << 32); | ||
2458 | } | ||
2459 | |||
2254 | int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | 2460 | int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) |
2255 | { | 2461 | { |
2256 | unsigned long nr, a0, a1, a2, a3, ret; | 2462 | unsigned long nr, a0, a1, a2, a3, ret; |
2463 | int r = 1; | ||
2257 | 2464 | ||
2258 | kvm_x86_ops->cache_regs(vcpu); | 2465 | kvm_x86_ops->cache_regs(vcpu); |
2259 | 2466 | ||
@@ -2263,6 +2470,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | |||
2263 | a2 = vcpu->arch.regs[VCPU_REGS_RDX]; | 2470 | a2 = vcpu->arch.regs[VCPU_REGS_RDX]; |
2264 | a3 = vcpu->arch.regs[VCPU_REGS_RSI]; | 2471 | a3 = vcpu->arch.regs[VCPU_REGS_RSI]; |
2265 | 2472 | ||
2473 | KVMTRACE_1D(VMMCALL, vcpu, (u32)nr, handler); | ||
2474 | |||
2266 | if (!is_long_mode(vcpu)) { | 2475 | if (!is_long_mode(vcpu)) { |
2267 | nr &= 0xFFFFFFFF; | 2476 | nr &= 0xFFFFFFFF; |
2268 | a0 &= 0xFFFFFFFF; | 2477 | a0 &= 0xFFFFFFFF; |
@@ -2275,13 +2484,17 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) | |||
2275 | case KVM_HC_VAPIC_POLL_IRQ: | 2484 | case KVM_HC_VAPIC_POLL_IRQ: |
2276 | ret = 0; | 2485 | ret = 0; |
2277 | break; | 2486 | break; |
2487 | case KVM_HC_MMU_OP: | ||
2488 | r = kvm_pv_mmu_op(vcpu, a0, hc_gpa(vcpu, a1, a2), &ret); | ||
2489 | break; | ||
2278 | default: | 2490 | default: |
2279 | ret = -KVM_ENOSYS; | 2491 | ret = -KVM_ENOSYS; |
2280 | break; | 2492 | break; |
2281 | } | 2493 | } |
2282 | vcpu->arch.regs[VCPU_REGS_RAX] = ret; | 2494 | vcpu->arch.regs[VCPU_REGS_RAX] = ret; |
2283 | kvm_x86_ops->decache_regs(vcpu); | 2495 | kvm_x86_ops->decache_regs(vcpu); |
2284 | return 0; | 2496 | ++vcpu->stat.hypercalls; |
2497 | return r; | ||
2285 | } | 2498 | } |
2286 | EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); | 2499 | EXPORT_SYMBOL_GPL(kvm_emulate_hypercall); |
2287 | 2500 | ||
@@ -2329,7 +2542,7 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) | |||
2329 | void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, | 2542 | void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, |
2330 | unsigned long *rflags) | 2543 | unsigned long *rflags) |
2331 | { | 2544 | { |
2332 | lmsw(vcpu, msw); | 2545 | kvm_lmsw(vcpu, msw); |
2333 | *rflags = kvm_x86_ops->get_rflags(vcpu); | 2546 | *rflags = kvm_x86_ops->get_rflags(vcpu); |
2334 | } | 2547 | } |
2335 | 2548 | ||
@@ -2346,9 +2559,9 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) | |||
2346 | case 4: | 2559 | case 4: |
2347 | return vcpu->arch.cr4; | 2560 | return vcpu->arch.cr4; |
2348 | case 8: | 2561 | case 8: |
2349 | return get_cr8(vcpu); | 2562 | return kvm_get_cr8(vcpu); |
2350 | default: | 2563 | default: |
2351 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); | 2564 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr); |
2352 | return 0; | 2565 | return 0; |
2353 | } | 2566 | } |
2354 | } | 2567 | } |
@@ -2358,23 +2571,23 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, | |||
2358 | { | 2571 | { |
2359 | switch (cr) { | 2572 | switch (cr) { |
2360 | case 0: | 2573 | case 0: |
2361 | set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val)); | 2574 | kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val)); |
2362 | *rflags = kvm_x86_ops->get_rflags(vcpu); | 2575 | *rflags = kvm_x86_ops->get_rflags(vcpu); |
2363 | break; | 2576 | break; |
2364 | case 2: | 2577 | case 2: |
2365 | vcpu->arch.cr2 = val; | 2578 | vcpu->arch.cr2 = val; |
2366 | break; | 2579 | break; |
2367 | case 3: | 2580 | case 3: |
2368 | set_cr3(vcpu, val); | 2581 | kvm_set_cr3(vcpu, val); |
2369 | break; | 2582 | break; |
2370 | case 4: | 2583 | case 4: |
2371 | set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val)); | 2584 | kvm_set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val)); |
2372 | break; | 2585 | break; |
2373 | case 8: | 2586 | case 8: |
2374 | set_cr8(vcpu, val & 0xfUL); | 2587 | kvm_set_cr8(vcpu, val & 0xfUL); |
2375 | break; | 2588 | break; |
2376 | default: | 2589 | default: |
2377 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); | 2590 | vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr); |
2378 | } | 2591 | } |
2379 | } | 2592 | } |
2380 | 2593 | ||
@@ -2447,6 +2660,11 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | |||
2447 | } | 2660 | } |
2448 | kvm_x86_ops->decache_regs(vcpu); | 2661 | kvm_x86_ops->decache_regs(vcpu); |
2449 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2662 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2663 | KVMTRACE_5D(CPUID, vcpu, function, | ||
2664 | (u32)vcpu->arch.regs[VCPU_REGS_RAX], | ||
2665 | (u32)vcpu->arch.regs[VCPU_REGS_RBX], | ||
2666 | (u32)vcpu->arch.regs[VCPU_REGS_RCX], | ||
2667 | (u32)vcpu->arch.regs[VCPU_REGS_RDX], handler); | ||
2450 | } | 2668 | } |
2451 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); | 2669 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); |
2452 | 2670 | ||
@@ -2469,7 +2687,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu, | |||
2469 | struct kvm_run *kvm_run) | 2687 | struct kvm_run *kvm_run) |
2470 | { | 2688 | { |
2471 | kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; | 2689 | kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; |
2472 | kvm_run->cr8 = get_cr8(vcpu); | 2690 | kvm_run->cr8 = kvm_get_cr8(vcpu); |
2473 | kvm_run->apic_base = kvm_get_apic_base(vcpu); | 2691 | kvm_run->apic_base = kvm_get_apic_base(vcpu); |
2474 | if (irqchip_in_kernel(vcpu->kvm)) | 2692 | if (irqchip_in_kernel(vcpu->kvm)) |
2475 | kvm_run->ready_for_interrupt_injection = 1; | 2693 | kvm_run->ready_for_interrupt_injection = 1; |
@@ -2509,16 +2727,17 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2509 | { | 2727 | { |
2510 | int r; | 2728 | int r; |
2511 | 2729 | ||
2512 | if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) { | 2730 | if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED)) { |
2513 | pr_debug("vcpu %d received sipi with vector # %x\n", | 2731 | pr_debug("vcpu %d received sipi with vector # %x\n", |
2514 | vcpu->vcpu_id, vcpu->arch.sipi_vector); | 2732 | vcpu->vcpu_id, vcpu->arch.sipi_vector); |
2515 | kvm_lapic_reset(vcpu); | 2733 | kvm_lapic_reset(vcpu); |
2516 | r = kvm_x86_ops->vcpu_reset(vcpu); | 2734 | r = kvm_x86_ops->vcpu_reset(vcpu); |
2517 | if (r) | 2735 | if (r) |
2518 | return r; | 2736 | return r; |
2519 | vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; | 2737 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; |
2520 | } | 2738 | } |
2521 | 2739 | ||
2740 | down_read(&vcpu->kvm->slots_lock); | ||
2522 | vapic_enter(vcpu); | 2741 | vapic_enter(vcpu); |
2523 | 2742 | ||
2524 | preempted: | 2743 | preempted: |
@@ -2526,6 +2745,10 @@ preempted: | |||
2526 | kvm_x86_ops->guest_debug_pre(vcpu); | 2745 | kvm_x86_ops->guest_debug_pre(vcpu); |
2527 | 2746 | ||
2528 | again: | 2747 | again: |
2748 | if (vcpu->requests) | ||
2749 | if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) | ||
2750 | kvm_mmu_unload(vcpu); | ||
2751 | |||
2529 | r = kvm_mmu_reload(vcpu); | 2752 | r = kvm_mmu_reload(vcpu); |
2530 | if (unlikely(r)) | 2753 | if (unlikely(r)) |
2531 | goto out; | 2754 | goto out; |
@@ -2539,6 +2762,11 @@ again: | |||
2539 | r = 0; | 2762 | r = 0; |
2540 | goto out; | 2763 | goto out; |
2541 | } | 2764 | } |
2765 | if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) { | ||
2766 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; | ||
2767 | r = 0; | ||
2768 | goto out; | ||
2769 | } | ||
2542 | } | 2770 | } |
2543 | 2771 | ||
2544 | kvm_inject_pending_timer_irqs(vcpu); | 2772 | kvm_inject_pending_timer_irqs(vcpu); |
@@ -2557,6 +2785,14 @@ again: | |||
2557 | goto out; | 2785 | goto out; |
2558 | } | 2786 | } |
2559 | 2787 | ||
2788 | if (vcpu->requests) | ||
2789 | if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) { | ||
2790 | local_irq_enable(); | ||
2791 | preempt_enable(); | ||
2792 | r = 1; | ||
2793 | goto out; | ||
2794 | } | ||
2795 | |||
2560 | if (signal_pending(current)) { | 2796 | if (signal_pending(current)) { |
2561 | local_irq_enable(); | 2797 | local_irq_enable(); |
2562 | preempt_enable(); | 2798 | preempt_enable(); |
@@ -2566,6 +2802,13 @@ again: | |||
2566 | goto out; | 2802 | goto out; |
2567 | } | 2803 | } |
2568 | 2804 | ||
2805 | vcpu->guest_mode = 1; | ||
2806 | /* | ||
2807 | * Make sure that guest_mode assignment won't happen after | ||
2808 | * testing the pending IRQ vector bitmap. | ||
2809 | */ | ||
2810 | smp_wmb(); | ||
2811 | |||
2569 | if (vcpu->arch.exception.pending) | 2812 | if (vcpu->arch.exception.pending) |
2570 | __queue_exception(vcpu); | 2813 | __queue_exception(vcpu); |
2571 | else if (irqchip_in_kernel(vcpu->kvm)) | 2814 | else if (irqchip_in_kernel(vcpu->kvm)) |
@@ -2575,13 +2818,15 @@ again: | |||
2575 | 2818 | ||
2576 | kvm_lapic_sync_to_vapic(vcpu); | 2819 | kvm_lapic_sync_to_vapic(vcpu); |
2577 | 2820 | ||
2578 | vcpu->guest_mode = 1; | 2821 | up_read(&vcpu->kvm->slots_lock); |
2822 | |||
2579 | kvm_guest_enter(); | 2823 | kvm_guest_enter(); |
2580 | 2824 | ||
2581 | if (vcpu->requests) | 2825 | if (vcpu->requests) |
2582 | if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) | 2826 | if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) |
2583 | kvm_x86_ops->tlb_flush(vcpu); | 2827 | kvm_x86_ops->tlb_flush(vcpu); |
2584 | 2828 | ||
2829 | KVMTRACE_0D(VMENTRY, vcpu, entryexit); | ||
2585 | kvm_x86_ops->run(vcpu, kvm_run); | 2830 | kvm_x86_ops->run(vcpu, kvm_run); |
2586 | 2831 | ||
2587 | vcpu->guest_mode = 0; | 2832 | vcpu->guest_mode = 0; |
@@ -2601,6 +2846,8 @@ again: | |||
2601 | 2846 | ||
2602 | preempt_enable(); | 2847 | preempt_enable(); |
2603 | 2848 | ||
2849 | down_read(&vcpu->kvm->slots_lock); | ||
2850 | |||
2604 | /* | 2851 | /* |
2605 | * Profile KVM exit RIPs: | 2852 | * Profile KVM exit RIPs: |
2606 | */ | 2853 | */ |
@@ -2628,14 +2875,18 @@ again: | |||
2628 | } | 2875 | } |
2629 | 2876 | ||
2630 | out: | 2877 | out: |
2878 | up_read(&vcpu->kvm->slots_lock); | ||
2631 | if (r > 0) { | 2879 | if (r > 0) { |
2632 | kvm_resched(vcpu); | 2880 | kvm_resched(vcpu); |
2881 | down_read(&vcpu->kvm->slots_lock); | ||
2633 | goto preempted; | 2882 | goto preempted; |
2634 | } | 2883 | } |
2635 | 2884 | ||
2636 | post_kvm_run_save(vcpu, kvm_run); | 2885 | post_kvm_run_save(vcpu, kvm_run); |
2637 | 2886 | ||
2887 | down_read(&vcpu->kvm->slots_lock); | ||
2638 | vapic_exit(vcpu); | 2888 | vapic_exit(vcpu); |
2889 | up_read(&vcpu->kvm->slots_lock); | ||
2639 | 2890 | ||
2640 | return r; | 2891 | return r; |
2641 | } | 2892 | } |
@@ -2647,7 +2898,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2647 | 2898 | ||
2648 | vcpu_load(vcpu); | 2899 | vcpu_load(vcpu); |
2649 | 2900 | ||
2650 | if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_UNINITIALIZED)) { | 2901 | if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) { |
2651 | kvm_vcpu_block(vcpu); | 2902 | kvm_vcpu_block(vcpu); |
2652 | vcpu_put(vcpu); | 2903 | vcpu_put(vcpu); |
2653 | return -EAGAIN; | 2904 | return -EAGAIN; |
@@ -2658,7 +2909,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2658 | 2909 | ||
2659 | /* re-sync apic's tpr */ | 2910 | /* re-sync apic's tpr */ |
2660 | if (!irqchip_in_kernel(vcpu->kvm)) | 2911 | if (!irqchip_in_kernel(vcpu->kvm)) |
2661 | set_cr8(vcpu, kvm_run->cr8); | 2912 | kvm_set_cr8(vcpu, kvm_run->cr8); |
2662 | 2913 | ||
2663 | if (vcpu->arch.pio.cur_count) { | 2914 | if (vcpu->arch.pio.cur_count) { |
2664 | r = complete_pio(vcpu); | 2915 | r = complete_pio(vcpu); |
@@ -2670,9 +2921,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2670 | memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); | 2921 | memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); |
2671 | vcpu->mmio_read_completed = 1; | 2922 | vcpu->mmio_read_completed = 1; |
2672 | vcpu->mmio_needed = 0; | 2923 | vcpu->mmio_needed = 0; |
2924 | |||
2925 | down_read(&vcpu->kvm->slots_lock); | ||
2673 | r = emulate_instruction(vcpu, kvm_run, | 2926 | r = emulate_instruction(vcpu, kvm_run, |
2674 | vcpu->arch.mmio_fault_cr2, 0, | 2927 | vcpu->arch.mmio_fault_cr2, 0, |
2675 | EMULTYPE_NO_DECODE); | 2928 | EMULTYPE_NO_DECODE); |
2929 | up_read(&vcpu->kvm->slots_lock); | ||
2676 | if (r == EMULATE_DO_MMIO) { | 2930 | if (r == EMULATE_DO_MMIO) { |
2677 | /* | 2931 | /* |
2678 | * Read-modify-write. Back to userspace. | 2932 | * Read-modify-write. Back to userspace. |
@@ -2773,7 +3027,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | |||
2773 | static void get_segment(struct kvm_vcpu *vcpu, | 3027 | static void get_segment(struct kvm_vcpu *vcpu, |
2774 | struct kvm_segment *var, int seg) | 3028 | struct kvm_segment *var, int seg) |
2775 | { | 3029 | { |
2776 | return kvm_x86_ops->get_segment(vcpu, var, seg); | 3030 | kvm_x86_ops->get_segment(vcpu, var, seg); |
2777 | } | 3031 | } |
2778 | 3032 | ||
2779 | void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) | 3033 | void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) |
@@ -2816,7 +3070,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | |||
2816 | sregs->cr2 = vcpu->arch.cr2; | 3070 | sregs->cr2 = vcpu->arch.cr2; |
2817 | sregs->cr3 = vcpu->arch.cr3; | 3071 | sregs->cr3 = vcpu->arch.cr3; |
2818 | sregs->cr4 = vcpu->arch.cr4; | 3072 | sregs->cr4 = vcpu->arch.cr4; |
2819 | sregs->cr8 = get_cr8(vcpu); | 3073 | sregs->cr8 = kvm_get_cr8(vcpu); |
2820 | sregs->efer = vcpu->arch.shadow_efer; | 3074 | sregs->efer = vcpu->arch.shadow_efer; |
2821 | sregs->apic_base = kvm_get_apic_base(vcpu); | 3075 | sregs->apic_base = kvm_get_apic_base(vcpu); |
2822 | 3076 | ||
@@ -2836,12 +3090,438 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | |||
2836 | return 0; | 3090 | return 0; |
2837 | } | 3091 | } |
2838 | 3092 | ||
3093 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | ||
3094 | struct kvm_mp_state *mp_state) | ||
3095 | { | ||
3096 | vcpu_load(vcpu); | ||
3097 | mp_state->mp_state = vcpu->arch.mp_state; | ||
3098 | vcpu_put(vcpu); | ||
3099 | return 0; | ||
3100 | } | ||
3101 | |||
3102 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | ||
3103 | struct kvm_mp_state *mp_state) | ||
3104 | { | ||
3105 | vcpu_load(vcpu); | ||
3106 | vcpu->arch.mp_state = mp_state->mp_state; | ||
3107 | vcpu_put(vcpu); | ||
3108 | return 0; | ||
3109 | } | ||
3110 | |||
2839 | static void set_segment(struct kvm_vcpu *vcpu, | 3111 | static void set_segment(struct kvm_vcpu *vcpu, |
2840 | struct kvm_segment *var, int seg) | 3112 | struct kvm_segment *var, int seg) |
2841 | { | 3113 | { |
2842 | return kvm_x86_ops->set_segment(vcpu, var, seg); | 3114 | kvm_x86_ops->set_segment(vcpu, var, seg); |
3115 | } | ||
3116 | |||
3117 | static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector, | ||
3118 | struct kvm_segment *kvm_desct) | ||
3119 | { | ||
3120 | kvm_desct->base = seg_desc->base0; | ||
3121 | kvm_desct->base |= seg_desc->base1 << 16; | ||
3122 | kvm_desct->base |= seg_desc->base2 << 24; | ||
3123 | kvm_desct->limit = seg_desc->limit0; | ||
3124 | kvm_desct->limit |= seg_desc->limit << 16; | ||
3125 | kvm_desct->selector = selector; | ||
3126 | kvm_desct->type = seg_desc->type; | ||
3127 | kvm_desct->present = seg_desc->p; | ||
3128 | kvm_desct->dpl = seg_desc->dpl; | ||
3129 | kvm_desct->db = seg_desc->d; | ||
3130 | kvm_desct->s = seg_desc->s; | ||
3131 | kvm_desct->l = seg_desc->l; | ||
3132 | kvm_desct->g = seg_desc->g; | ||
3133 | kvm_desct->avl = seg_desc->avl; | ||
3134 | if (!selector) | ||
3135 | kvm_desct->unusable = 1; | ||
3136 | else | ||
3137 | kvm_desct->unusable = 0; | ||
3138 | kvm_desct->padding = 0; | ||
3139 | } | ||
3140 | |||
3141 | static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu, | ||
3142 | u16 selector, | ||
3143 | struct descriptor_table *dtable) | ||
3144 | { | ||
3145 | if (selector & 1 << 2) { | ||
3146 | struct kvm_segment kvm_seg; | ||
3147 | |||
3148 | get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR); | ||
3149 | |||
3150 | if (kvm_seg.unusable) | ||
3151 | dtable->limit = 0; | ||
3152 | else | ||
3153 | dtable->limit = kvm_seg.limit; | ||
3154 | dtable->base = kvm_seg.base; | ||
3155 | } | ||
3156 | else | ||
3157 | kvm_x86_ops->get_gdt(vcpu, dtable); | ||
3158 | } | ||
3159 | |||
3160 | /* allowed just for 8 bytes segments */ | ||
3161 | static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | ||
3162 | struct desc_struct *seg_desc) | ||
3163 | { | ||
3164 | struct descriptor_table dtable; | ||
3165 | u16 index = selector >> 3; | ||
3166 | |||
3167 | get_segment_descritptor_dtable(vcpu, selector, &dtable); | ||
3168 | |||
3169 | if (dtable.limit < index * 8 + 7) { | ||
3170 | kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc); | ||
3171 | return 1; | ||
3172 | } | ||
3173 | return kvm_read_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8); | ||
3174 | } | ||
3175 | |||
3176 | /* allowed just for 8 bytes segments */ | ||
3177 | static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | ||
3178 | struct desc_struct *seg_desc) | ||
3179 | { | ||
3180 | struct descriptor_table dtable; | ||
3181 | u16 index = selector >> 3; | ||
3182 | |||
3183 | get_segment_descritptor_dtable(vcpu, selector, &dtable); | ||
3184 | |||
3185 | if (dtable.limit < index * 8 + 7) | ||
3186 | return 1; | ||
3187 | return kvm_write_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8); | ||
3188 | } | ||
3189 | |||
3190 | static u32 get_tss_base_addr(struct kvm_vcpu *vcpu, | ||
3191 | struct desc_struct *seg_desc) | ||
3192 | { | ||
3193 | u32 base_addr; | ||
3194 | |||
3195 | base_addr = seg_desc->base0; | ||
3196 | base_addr |= (seg_desc->base1 << 16); | ||
3197 | base_addr |= (seg_desc->base2 << 24); | ||
3198 | |||
3199 | return base_addr; | ||
3200 | } | ||
3201 | |||
3202 | static int load_tss_segment32(struct kvm_vcpu *vcpu, | ||
3203 | struct desc_struct *seg_desc, | ||
3204 | struct tss_segment_32 *tss) | ||
3205 | { | ||
3206 | u32 base_addr; | ||
3207 | |||
3208 | base_addr = get_tss_base_addr(vcpu, seg_desc); | ||
3209 | |||
3210 | return kvm_read_guest(vcpu->kvm, base_addr, tss, | ||
3211 | sizeof(struct tss_segment_32)); | ||
3212 | } | ||
3213 | |||
3214 | static int save_tss_segment32(struct kvm_vcpu *vcpu, | ||
3215 | struct desc_struct *seg_desc, | ||
3216 | struct tss_segment_32 *tss) | ||
3217 | { | ||
3218 | u32 base_addr; | ||
3219 | |||
3220 | base_addr = get_tss_base_addr(vcpu, seg_desc); | ||
3221 | |||
3222 | return kvm_write_guest(vcpu->kvm, base_addr, tss, | ||
3223 | sizeof(struct tss_segment_32)); | ||
3224 | } | ||
3225 | |||
3226 | static int load_tss_segment16(struct kvm_vcpu *vcpu, | ||
3227 | struct desc_struct *seg_desc, | ||
3228 | struct tss_segment_16 *tss) | ||
3229 | { | ||
3230 | u32 base_addr; | ||
3231 | |||
3232 | base_addr = get_tss_base_addr(vcpu, seg_desc); | ||
3233 | |||
3234 | return kvm_read_guest(vcpu->kvm, base_addr, tss, | ||
3235 | sizeof(struct tss_segment_16)); | ||
3236 | } | ||
3237 | |||
3238 | static int save_tss_segment16(struct kvm_vcpu *vcpu, | ||
3239 | struct desc_struct *seg_desc, | ||
3240 | struct tss_segment_16 *tss) | ||
3241 | { | ||
3242 | u32 base_addr; | ||
3243 | |||
3244 | base_addr = get_tss_base_addr(vcpu, seg_desc); | ||
3245 | |||
3246 | return kvm_write_guest(vcpu->kvm, base_addr, tss, | ||
3247 | sizeof(struct tss_segment_16)); | ||
3248 | } | ||
3249 | |||
3250 | static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg) | ||
3251 | { | ||
3252 | struct kvm_segment kvm_seg; | ||
3253 | |||
3254 | get_segment(vcpu, &kvm_seg, seg); | ||
3255 | return kvm_seg.selector; | ||
3256 | } | ||
3257 | |||
3258 | static int load_segment_descriptor_to_kvm_desct(struct kvm_vcpu *vcpu, | ||
3259 | u16 selector, | ||
3260 | struct kvm_segment *kvm_seg) | ||
3261 | { | ||
3262 | struct desc_struct seg_desc; | ||
3263 | |||
3264 | if (load_guest_segment_descriptor(vcpu, selector, &seg_desc)) | ||
3265 | return 1; | ||
3266 | seg_desct_to_kvm_desct(&seg_desc, selector, kvm_seg); | ||
3267 | return 0; | ||
3268 | } | ||
3269 | |||
3270 | static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | ||
3271 | int type_bits, int seg) | ||
3272 | { | ||
3273 | struct kvm_segment kvm_seg; | ||
3274 | |||
3275 | if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg)) | ||
3276 | return 1; | ||
3277 | kvm_seg.type |= type_bits; | ||
3278 | |||
3279 | if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS && | ||
3280 | seg != VCPU_SREG_LDTR) | ||
3281 | if (!kvm_seg.s) | ||
3282 | kvm_seg.unusable = 1; | ||
3283 | |||
3284 | set_segment(vcpu, &kvm_seg, seg); | ||
3285 | return 0; | ||
3286 | } | ||
3287 | |||
3288 | static void save_state_to_tss32(struct kvm_vcpu *vcpu, | ||
3289 | struct tss_segment_32 *tss) | ||
3290 | { | ||
3291 | tss->cr3 = vcpu->arch.cr3; | ||
3292 | tss->eip = vcpu->arch.rip; | ||
3293 | tss->eflags = kvm_x86_ops->get_rflags(vcpu); | ||
3294 | tss->eax = vcpu->arch.regs[VCPU_REGS_RAX]; | ||
3295 | tss->ecx = vcpu->arch.regs[VCPU_REGS_RCX]; | ||
3296 | tss->edx = vcpu->arch.regs[VCPU_REGS_RDX]; | ||
3297 | tss->ebx = vcpu->arch.regs[VCPU_REGS_RBX]; | ||
3298 | tss->esp = vcpu->arch.regs[VCPU_REGS_RSP]; | ||
3299 | tss->ebp = vcpu->arch.regs[VCPU_REGS_RBP]; | ||
3300 | tss->esi = vcpu->arch.regs[VCPU_REGS_RSI]; | ||
3301 | tss->edi = vcpu->arch.regs[VCPU_REGS_RDI]; | ||
3302 | |||
3303 | tss->es = get_segment_selector(vcpu, VCPU_SREG_ES); | ||
3304 | tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS); | ||
3305 | tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS); | ||
3306 | tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS); | ||
3307 | tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS); | ||
3308 | tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS); | ||
3309 | tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR); | ||
3310 | tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR); | ||
3311 | } | ||
3312 | |||
3313 | static int load_state_from_tss32(struct kvm_vcpu *vcpu, | ||
3314 | struct tss_segment_32 *tss) | ||
3315 | { | ||
3316 | kvm_set_cr3(vcpu, tss->cr3); | ||
3317 | |||
3318 | vcpu->arch.rip = tss->eip; | ||
3319 | kvm_x86_ops->set_rflags(vcpu, tss->eflags | 2); | ||
3320 | |||
3321 | vcpu->arch.regs[VCPU_REGS_RAX] = tss->eax; | ||
3322 | vcpu->arch.regs[VCPU_REGS_RCX] = tss->ecx; | ||
3323 | vcpu->arch.regs[VCPU_REGS_RDX] = tss->edx; | ||
3324 | vcpu->arch.regs[VCPU_REGS_RBX] = tss->ebx; | ||
3325 | vcpu->arch.regs[VCPU_REGS_RSP] = tss->esp; | ||
3326 | vcpu->arch.regs[VCPU_REGS_RBP] = tss->ebp; | ||
3327 | vcpu->arch.regs[VCPU_REGS_RSI] = tss->esi; | ||
3328 | vcpu->arch.regs[VCPU_REGS_RDI] = tss->edi; | ||
3329 | |||
3330 | if (load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR)) | ||
3331 | return 1; | ||
3332 | |||
3333 | if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) | ||
3334 | return 1; | ||
3335 | |||
3336 | if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) | ||
3337 | return 1; | ||
3338 | |||
3339 | if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) | ||
3340 | return 1; | ||
3341 | |||
3342 | if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) | ||
3343 | return 1; | ||
3344 | |||
3345 | if (load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS)) | ||
3346 | return 1; | ||
3347 | |||
3348 | if (load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS)) | ||
3349 | return 1; | ||
3350 | return 0; | ||
3351 | } | ||
3352 | |||
3353 | static void save_state_to_tss16(struct kvm_vcpu *vcpu, | ||
3354 | struct tss_segment_16 *tss) | ||
3355 | { | ||
3356 | tss->ip = vcpu->arch.rip; | ||
3357 | tss->flag = kvm_x86_ops->get_rflags(vcpu); | ||
3358 | tss->ax = vcpu->arch.regs[VCPU_REGS_RAX]; | ||
3359 | tss->cx = vcpu->arch.regs[VCPU_REGS_RCX]; | ||
3360 | tss->dx = vcpu->arch.regs[VCPU_REGS_RDX]; | ||
3361 | tss->bx = vcpu->arch.regs[VCPU_REGS_RBX]; | ||
3362 | tss->sp = vcpu->arch.regs[VCPU_REGS_RSP]; | ||
3363 | tss->bp = vcpu->arch.regs[VCPU_REGS_RBP]; | ||
3364 | tss->si = vcpu->arch.regs[VCPU_REGS_RSI]; | ||
3365 | tss->di = vcpu->arch.regs[VCPU_REGS_RDI]; | ||
3366 | |||
3367 | tss->es = get_segment_selector(vcpu, VCPU_SREG_ES); | ||
3368 | tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS); | ||
3369 | tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS); | ||
3370 | tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS); | ||
3371 | tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR); | ||
3372 | tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR); | ||
3373 | } | ||
3374 | |||
3375 | static int load_state_from_tss16(struct kvm_vcpu *vcpu, | ||
3376 | struct tss_segment_16 *tss) | ||
3377 | { | ||
3378 | vcpu->arch.rip = tss->ip; | ||
3379 | kvm_x86_ops->set_rflags(vcpu, tss->flag | 2); | ||
3380 | vcpu->arch.regs[VCPU_REGS_RAX] = tss->ax; | ||
3381 | vcpu->arch.regs[VCPU_REGS_RCX] = tss->cx; | ||
3382 | vcpu->arch.regs[VCPU_REGS_RDX] = tss->dx; | ||
3383 | vcpu->arch.regs[VCPU_REGS_RBX] = tss->bx; | ||
3384 | vcpu->arch.regs[VCPU_REGS_RSP] = tss->sp; | ||
3385 | vcpu->arch.regs[VCPU_REGS_RBP] = tss->bp; | ||
3386 | vcpu->arch.regs[VCPU_REGS_RSI] = tss->si; | ||
3387 | vcpu->arch.regs[VCPU_REGS_RDI] = tss->di; | ||
3388 | |||
3389 | if (load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR)) | ||
3390 | return 1; | ||
3391 | |||
3392 | if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES)) | ||
3393 | return 1; | ||
3394 | |||
3395 | if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS)) | ||
3396 | return 1; | ||
3397 | |||
3398 | if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS)) | ||
3399 | return 1; | ||
3400 | |||
3401 | if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS)) | ||
3402 | return 1; | ||
3403 | return 0; | ||
3404 | } | ||
3405 | |||
3406 | int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, | ||
3407 | struct desc_struct *cseg_desc, | ||
3408 | struct desc_struct *nseg_desc) | ||
3409 | { | ||
3410 | struct tss_segment_16 tss_segment_16; | ||
3411 | int ret = 0; | ||
3412 | |||
3413 | if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16)) | ||
3414 | goto out; | ||
3415 | |||
3416 | save_state_to_tss16(vcpu, &tss_segment_16); | ||
3417 | save_tss_segment16(vcpu, cseg_desc, &tss_segment_16); | ||
3418 | |||
3419 | if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16)) | ||
3420 | goto out; | ||
3421 | if (load_state_from_tss16(vcpu, &tss_segment_16)) | ||
3422 | goto out; | ||
3423 | |||
3424 | ret = 1; | ||
3425 | out: | ||
3426 | return ret; | ||
3427 | } | ||
3428 | |||
3429 | int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, | ||
3430 | struct desc_struct *cseg_desc, | ||
3431 | struct desc_struct *nseg_desc) | ||
3432 | { | ||
3433 | struct tss_segment_32 tss_segment_32; | ||
3434 | int ret = 0; | ||
3435 | |||
3436 | if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32)) | ||
3437 | goto out; | ||
3438 | |||
3439 | save_state_to_tss32(vcpu, &tss_segment_32); | ||
3440 | save_tss_segment32(vcpu, cseg_desc, &tss_segment_32); | ||
3441 | |||
3442 | if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32)) | ||
3443 | goto out; | ||
3444 | if (load_state_from_tss32(vcpu, &tss_segment_32)) | ||
3445 | goto out; | ||
3446 | |||
3447 | ret = 1; | ||
3448 | out: | ||
3449 | return ret; | ||
2843 | } | 3450 | } |
2844 | 3451 | ||
3452 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) | ||
3453 | { | ||
3454 | struct kvm_segment tr_seg; | ||
3455 | struct desc_struct cseg_desc; | ||
3456 | struct desc_struct nseg_desc; | ||
3457 | int ret = 0; | ||
3458 | |||
3459 | get_segment(vcpu, &tr_seg, VCPU_SREG_TR); | ||
3460 | |||
3461 | if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc)) | ||
3462 | goto out; | ||
3463 | |||
3464 | if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc)) | ||
3465 | goto out; | ||
3466 | |||
3467 | |||
3468 | if (reason != TASK_SWITCH_IRET) { | ||
3469 | int cpl; | ||
3470 | |||
3471 | cpl = kvm_x86_ops->get_cpl(vcpu); | ||
3472 | if ((tss_selector & 3) > nseg_desc.dpl || cpl > nseg_desc.dpl) { | ||
3473 | kvm_queue_exception_e(vcpu, GP_VECTOR, 0); | ||
3474 | return 1; | ||
3475 | } | ||
3476 | } | ||
3477 | |||
3478 | if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) { | ||
3479 | kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc); | ||
3480 | return 1; | ||
3481 | } | ||
3482 | |||
3483 | if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) { | ||
3484 | cseg_desc.type &= ~(1 << 8); //clear the B flag | ||
3485 | save_guest_segment_descriptor(vcpu, tr_seg.selector, | ||
3486 | &cseg_desc); | ||
3487 | } | ||
3488 | |||
3489 | if (reason == TASK_SWITCH_IRET) { | ||
3490 | u32 eflags = kvm_x86_ops->get_rflags(vcpu); | ||
3491 | kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT); | ||
3492 | } | ||
3493 | |||
3494 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
3495 | kvm_x86_ops->cache_regs(vcpu); | ||
3496 | |||
3497 | if (nseg_desc.type & 8) | ||
3498 | ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc, | ||
3499 | &nseg_desc); | ||
3500 | else | ||
3501 | ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc, | ||
3502 | &nseg_desc); | ||
3503 | |||
3504 | if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) { | ||
3505 | u32 eflags = kvm_x86_ops->get_rflags(vcpu); | ||
3506 | kvm_x86_ops->set_rflags(vcpu, eflags | X86_EFLAGS_NT); | ||
3507 | } | ||
3508 | |||
3509 | if (reason != TASK_SWITCH_IRET) { | ||
3510 | nseg_desc.type |= (1 << 8); | ||
3511 | save_guest_segment_descriptor(vcpu, tss_selector, | ||
3512 | &nseg_desc); | ||
3513 | } | ||
3514 | |||
3515 | kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS); | ||
3516 | seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg); | ||
3517 | tr_seg.type = 11; | ||
3518 | set_segment(vcpu, &tr_seg, VCPU_SREG_TR); | ||
3519 | out: | ||
3520 | kvm_x86_ops->decache_regs(vcpu); | ||
3521 | return ret; | ||
3522 | } | ||
3523 | EXPORT_SYMBOL_GPL(kvm_task_switch); | ||
3524 | |||
2845 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | 3525 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, |
2846 | struct kvm_sregs *sregs) | 3526 | struct kvm_sregs *sregs) |
2847 | { | 3527 | { |
@@ -2862,12 +3542,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | |||
2862 | mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3; | 3542 | mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3; |
2863 | vcpu->arch.cr3 = sregs->cr3; | 3543 | vcpu->arch.cr3 = sregs->cr3; |
2864 | 3544 | ||
2865 | set_cr8(vcpu, sregs->cr8); | 3545 | kvm_set_cr8(vcpu, sregs->cr8); |
2866 | 3546 | ||
2867 | mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer; | 3547 | mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer; |
2868 | #ifdef CONFIG_X86_64 | ||
2869 | kvm_x86_ops->set_efer(vcpu, sregs->efer); | 3548 | kvm_x86_ops->set_efer(vcpu, sregs->efer); |
2870 | #endif | ||
2871 | kvm_set_apic_base(vcpu, sregs->apic_base); | 3549 | kvm_set_apic_base(vcpu, sregs->apic_base); |
2872 | 3550 | ||
2873 | kvm_x86_ops->decache_cr4_guest_bits(vcpu); | 3551 | kvm_x86_ops->decache_cr4_guest_bits(vcpu); |
@@ -3141,9 +3819,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | |||
3141 | 3819 | ||
3142 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; | 3820 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; |
3143 | if (!irqchip_in_kernel(kvm) || vcpu->vcpu_id == 0) | 3821 | if (!irqchip_in_kernel(kvm) || vcpu->vcpu_id == 0) |
3144 | vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE; | 3822 | vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; |
3145 | else | 3823 | else |
3146 | vcpu->arch.mp_state = VCPU_MP_STATE_UNINITIALIZED; | 3824 | vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED; |
3147 | 3825 | ||
3148 | page = alloc_page(GFP_KERNEL | __GFP_ZERO); | 3826 | page = alloc_page(GFP_KERNEL | __GFP_ZERO); |
3149 | if (!page) { | 3827 | if (!page) { |
@@ -3175,7 +3853,9 @@ fail: | |||
3175 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | 3853 | void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) |
3176 | { | 3854 | { |
3177 | kvm_free_lapic(vcpu); | 3855 | kvm_free_lapic(vcpu); |
3856 | down_read(&vcpu->kvm->slots_lock); | ||
3178 | kvm_mmu_destroy(vcpu); | 3857 | kvm_mmu_destroy(vcpu); |
3858 | up_read(&vcpu->kvm->slots_lock); | ||
3179 | free_page((unsigned long)vcpu->arch.pio_data); | 3859 | free_page((unsigned long)vcpu->arch.pio_data); |
3180 | } | 3860 | } |
3181 | 3861 | ||
@@ -3219,10 +3899,13 @@ static void kvm_free_vcpus(struct kvm *kvm) | |||
3219 | 3899 | ||
3220 | void kvm_arch_destroy_vm(struct kvm *kvm) | 3900 | void kvm_arch_destroy_vm(struct kvm *kvm) |
3221 | { | 3901 | { |
3902 | kvm_free_pit(kvm); | ||
3222 | kfree(kvm->arch.vpic); | 3903 | kfree(kvm->arch.vpic); |
3223 | kfree(kvm->arch.vioapic); | 3904 | kfree(kvm->arch.vioapic); |
3224 | kvm_free_vcpus(kvm); | 3905 | kvm_free_vcpus(kvm); |
3225 | kvm_free_physmem(kvm); | 3906 | kvm_free_physmem(kvm); |
3907 | if (kvm->arch.apic_access_page) | ||
3908 | put_page(kvm->arch.apic_access_page); | ||
3226 | kfree(kvm); | 3909 | kfree(kvm); |
3227 | } | 3910 | } |
3228 | 3911 | ||
@@ -3278,8 +3961,8 @@ int kvm_arch_set_memory_region(struct kvm *kvm, | |||
3278 | 3961 | ||
3279 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) | 3962 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) |
3280 | { | 3963 | { |
3281 | return vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE | 3964 | return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE |
3282 | || vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED; | 3965 | || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED; |
3283 | } | 3966 | } |
3284 | 3967 | ||
3285 | static void vcpu_kick_intr(void *info) | 3968 | static void vcpu_kick_intr(void *info) |
@@ -3293,11 +3976,17 @@ static void vcpu_kick_intr(void *info) | |||
3293 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | 3976 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) |
3294 | { | 3977 | { |
3295 | int ipi_pcpu = vcpu->cpu; | 3978 | int ipi_pcpu = vcpu->cpu; |
3979 | int cpu = get_cpu(); | ||
3296 | 3980 | ||
3297 | if (waitqueue_active(&vcpu->wq)) { | 3981 | if (waitqueue_active(&vcpu->wq)) { |
3298 | wake_up_interruptible(&vcpu->wq); | 3982 | wake_up_interruptible(&vcpu->wq); |
3299 | ++vcpu->stat.halt_wakeup; | 3983 | ++vcpu->stat.halt_wakeup; |
3300 | } | 3984 | } |
3301 | if (vcpu->guest_mode) | 3985 | /* |
3986 | * We may be called synchronously with irqs disabled in guest mode, | ||
3987 | * So need not to call smp_call_function_single() in that case. | ||
3988 | */ | ||
3989 | if (vcpu->guest_mode && vcpu->cpu != cpu) | ||
3302 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); | 3990 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); |
3991 | put_cpu(); | ||
3303 | } | 3992 | } |
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 79586003397a..2ca08386f993 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c | |||
@@ -65,6 +65,14 @@ | |||
65 | #define MemAbs (1<<9) /* Memory operand is absolute displacement */ | 65 | #define MemAbs (1<<9) /* Memory operand is absolute displacement */ |
66 | #define String (1<<10) /* String instruction (rep capable) */ | 66 | #define String (1<<10) /* String instruction (rep capable) */ |
67 | #define Stack (1<<11) /* Stack instruction (push/pop) */ | 67 | #define Stack (1<<11) /* Stack instruction (push/pop) */ |
68 | #define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */ | ||
69 | #define GroupDual (1<<15) /* Alternate decoding of mod == 3 */ | ||
70 | #define GroupMask 0xff /* Group number stored in bits 0:7 */ | ||
71 | |||
72 | enum { | ||
73 | Group1_80, Group1_81, Group1_82, Group1_83, | ||
74 | Group1A, Group3_Byte, Group3, Group4, Group5, Group7, | ||
75 | }; | ||
68 | 76 | ||
69 | static u16 opcode_table[256] = { | 77 | static u16 opcode_table[256] = { |
70 | /* 0x00 - 0x07 */ | 78 | /* 0x00 - 0x07 */ |
@@ -123,14 +131,14 @@ static u16 opcode_table[256] = { | |||
123 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 131 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, |
124 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 132 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, |
125 | /* 0x80 - 0x87 */ | 133 | /* 0x80 - 0x87 */ |
126 | ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, | 134 | Group | Group1_80, Group | Group1_81, |
127 | ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, | 135 | Group | Group1_82, Group | Group1_83, |
128 | ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, | 136 | ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, |
129 | ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, | 137 | ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, |
130 | /* 0x88 - 0x8F */ | 138 | /* 0x88 - 0x8F */ |
131 | ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, | 139 | ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, |
132 | ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, | 140 | ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, |
133 | 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov | Stack, | 141 | 0, ModRM | DstReg, 0, Group | Group1A, |
134 | /* 0x90 - 0x9F */ | 142 | /* 0x90 - 0x9F */ |
135 | 0, 0, 0, 0, 0, 0, 0, 0, | 143 | 0, 0, 0, 0, 0, 0, 0, 0, |
136 | 0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, | 144 | 0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, |
@@ -164,16 +172,15 @@ static u16 opcode_table[256] = { | |||
164 | 0, 0, 0, 0, | 172 | 0, 0, 0, 0, |
165 | /* 0xF0 - 0xF7 */ | 173 | /* 0xF0 - 0xF7 */ |
166 | 0, 0, 0, 0, | 174 | 0, 0, 0, 0, |
167 | ImplicitOps, ImplicitOps, | 175 | ImplicitOps, ImplicitOps, Group | Group3_Byte, Group | Group3, |
168 | ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, | ||
169 | /* 0xF8 - 0xFF */ | 176 | /* 0xF8 - 0xFF */ |
170 | ImplicitOps, 0, ImplicitOps, ImplicitOps, | 177 | ImplicitOps, 0, ImplicitOps, ImplicitOps, |
171 | 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM | 178 | 0, 0, Group | Group4, Group | Group5, |
172 | }; | 179 | }; |
173 | 180 | ||
174 | static u16 twobyte_table[256] = { | 181 | static u16 twobyte_table[256] = { |
175 | /* 0x00 - 0x0F */ | 182 | /* 0x00 - 0x0F */ |
176 | 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, | 183 | 0, Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0, |
177 | ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, | 184 | ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, |
178 | /* 0x10 - 0x1F */ | 185 | /* 0x10 - 0x1F */ |
179 | 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, | 186 | 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, |
@@ -229,6 +236,56 @@ static u16 twobyte_table[256] = { | |||
229 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 236 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
230 | }; | 237 | }; |
231 | 238 | ||
239 | static u16 group_table[] = { | ||
240 | [Group1_80*8] = | ||
241 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
242 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
243 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
244 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
245 | [Group1_81*8] = | ||
246 | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, | ||
247 | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, | ||
248 | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, | ||
249 | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, | ||
250 | [Group1_82*8] = | ||
251 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
252 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
253 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
254 | ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, | ||
255 | [Group1_83*8] = | ||
256 | DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, | ||
257 | DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, | ||
258 | DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, | ||
259 | DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM, | ||
260 | [Group1A*8] = | ||
261 | DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0, | ||
262 | [Group3_Byte*8] = | ||
263 | ByteOp | SrcImm | DstMem | ModRM, 0, | ||
264 | ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, | ||
265 | 0, 0, 0, 0, | ||
266 | [Group3*8] = | ||
267 | DstMem | SrcImm | ModRM | SrcImm, 0, | ||
268 | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, | ||
269 | 0, 0, 0, 0, | ||
270 | [Group4*8] = | ||
271 | ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM, | ||
272 | 0, 0, 0, 0, 0, 0, | ||
273 | [Group5*8] = | ||
274 | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, 0, 0, | ||
275 | SrcMem | ModRM, 0, SrcMem | ModRM | Stack, 0, | ||
276 | [Group7*8] = | ||
277 | 0, 0, ModRM | SrcMem, ModRM | SrcMem, | ||
278 | SrcNone | ModRM | DstMem | Mov, 0, | ||
279 | SrcMem16 | ModRM | Mov, SrcMem | ModRM | ByteOp, | ||
280 | }; | ||
281 | |||
282 | static u16 group2_table[] = { | ||
283 | [Group7*8] = | ||
284 | SrcNone | ModRM, 0, 0, 0, | ||
285 | SrcNone | ModRM | DstMem | Mov, 0, | ||
286 | SrcMem16 | ModRM | Mov, 0, | ||
287 | }; | ||
288 | |||
232 | /* EFLAGS bit definitions. */ | 289 | /* EFLAGS bit definitions. */ |
233 | #define EFLG_OF (1<<11) | 290 | #define EFLG_OF (1<<11) |
234 | #define EFLG_DF (1<<10) | 291 | #define EFLG_DF (1<<10) |
@@ -317,7 +374,7 @@ static u16 twobyte_table[256] = { | |||
317 | 374 | ||
318 | #define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ | 375 | #define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ |
319 | do { \ | 376 | do { \ |
320 | unsigned long _tmp; \ | 377 | unsigned long __tmp; \ |
321 | switch ((_dst).bytes) { \ | 378 | switch ((_dst).bytes) { \ |
322 | case 1: \ | 379 | case 1: \ |
323 | __asm__ __volatile__ ( \ | 380 | __asm__ __volatile__ ( \ |
@@ -325,7 +382,7 @@ static u16 twobyte_table[256] = { | |||
325 | _op"b %"_bx"3,%1; " \ | 382 | _op"b %"_bx"3,%1; " \ |
326 | _POST_EFLAGS("0", "4", "2") \ | 383 | _POST_EFLAGS("0", "4", "2") \ |
327 | : "=m" (_eflags), "=m" ((_dst).val), \ | 384 | : "=m" (_eflags), "=m" ((_dst).val), \ |
328 | "=&r" (_tmp) \ | 385 | "=&r" (__tmp) \ |
329 | : _by ((_src).val), "i" (EFLAGS_MASK)); \ | 386 | : _by ((_src).val), "i" (EFLAGS_MASK)); \ |
330 | break; \ | 387 | break; \ |
331 | default: \ | 388 | default: \ |
@@ -426,29 +483,40 @@ static u16 twobyte_table[256] = { | |||
426 | (_type)_x; \ | 483 | (_type)_x; \ |
427 | }) | 484 | }) |
428 | 485 | ||
486 | static inline unsigned long ad_mask(struct decode_cache *c) | ||
487 | { | ||
488 | return (1UL << (c->ad_bytes << 3)) - 1; | ||
489 | } | ||
490 | |||
429 | /* Access/update address held in a register, based on addressing mode. */ | 491 | /* Access/update address held in a register, based on addressing mode. */ |
430 | #define address_mask(reg) \ | 492 | static inline unsigned long |
431 | ((c->ad_bytes == sizeof(unsigned long)) ? \ | 493 | address_mask(struct decode_cache *c, unsigned long reg) |
432 | (reg) : ((reg) & ((1UL << (c->ad_bytes << 3)) - 1))) | 494 | { |
433 | #define register_address(base, reg) \ | 495 | if (c->ad_bytes == sizeof(unsigned long)) |
434 | ((base) + address_mask(reg)) | 496 | return reg; |
435 | #define register_address_increment(reg, inc) \ | 497 | else |
436 | do { \ | 498 | return reg & ad_mask(c); |
437 | /* signed type ensures sign extension to long */ \ | 499 | } |
438 | int _inc = (inc); \ | ||
439 | if (c->ad_bytes == sizeof(unsigned long)) \ | ||
440 | (reg) += _inc; \ | ||
441 | else \ | ||
442 | (reg) = ((reg) & \ | ||
443 | ~((1UL << (c->ad_bytes << 3)) - 1)) | \ | ||
444 | (((reg) + _inc) & \ | ||
445 | ((1UL << (c->ad_bytes << 3)) - 1)); \ | ||
446 | } while (0) | ||
447 | 500 | ||
448 | #define JMP_REL(rel) \ | 501 | static inline unsigned long |
449 | do { \ | 502 | register_address(struct decode_cache *c, unsigned long base, unsigned long reg) |
450 | register_address_increment(c->eip, rel); \ | 503 | { |
451 | } while (0) | 504 | return base + address_mask(c, reg); |
505 | } | ||
506 | |||
507 | static inline void | ||
508 | register_address_increment(struct decode_cache *c, unsigned long *reg, int inc) | ||
509 | { | ||
510 | if (c->ad_bytes == sizeof(unsigned long)) | ||
511 | *reg += inc; | ||
512 | else | ||
513 | *reg = (*reg & ~ad_mask(c)) | ((*reg + inc) & ad_mask(c)); | ||
514 | } | ||
515 | |||
516 | static inline void jmp_rel(struct decode_cache *c, int rel) | ||
517 | { | ||
518 | register_address_increment(c, &c->eip, rel); | ||
519 | } | ||
452 | 520 | ||
453 | static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, | 521 | static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, |
454 | struct x86_emulate_ops *ops, | 522 | struct x86_emulate_ops *ops, |
@@ -763,7 +831,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
763 | struct decode_cache *c = &ctxt->decode; | 831 | struct decode_cache *c = &ctxt->decode; |
764 | int rc = 0; | 832 | int rc = 0; |
765 | int mode = ctxt->mode; | 833 | int mode = ctxt->mode; |
766 | int def_op_bytes, def_ad_bytes; | 834 | int def_op_bytes, def_ad_bytes, group; |
767 | 835 | ||
768 | /* Shadow copy of register state. Committed on successful emulation. */ | 836 | /* Shadow copy of register state. Committed on successful emulation. */ |
769 | 837 | ||
@@ -864,12 +932,24 @@ done_prefixes: | |||
864 | c->b = insn_fetch(u8, 1, c->eip); | 932 | c->b = insn_fetch(u8, 1, c->eip); |
865 | c->d = twobyte_table[c->b]; | 933 | c->d = twobyte_table[c->b]; |
866 | } | 934 | } |
935 | } | ||
867 | 936 | ||
868 | /* Unrecognised? */ | 937 | if (c->d & Group) { |
869 | if (c->d == 0) { | 938 | group = c->d & GroupMask; |
870 | DPRINTF("Cannot emulate %02x\n", c->b); | 939 | c->modrm = insn_fetch(u8, 1, c->eip); |
871 | return -1; | 940 | --c->eip; |
872 | } | 941 | |
942 | group = (group << 3) + ((c->modrm >> 3) & 7); | ||
943 | if ((c->d & GroupDual) && (c->modrm >> 6) == 3) | ||
944 | c->d = group2_table[group]; | ||
945 | else | ||
946 | c->d = group_table[group]; | ||
947 | } | ||
948 | |||
949 | /* Unrecognised? */ | ||
950 | if (c->d == 0) { | ||
951 | DPRINTF("Cannot emulate %02x\n", c->b); | ||
952 | return -1; | ||
873 | } | 953 | } |
874 | 954 | ||
875 | if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) | 955 | if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack)) |
@@ -924,6 +1004,7 @@ done_prefixes: | |||
924 | */ | 1004 | */ |
925 | if ((c->d & ModRM) && c->modrm_mod == 3) { | 1005 | if ((c->d & ModRM) && c->modrm_mod == 3) { |
926 | c->src.type = OP_REG; | 1006 | c->src.type = OP_REG; |
1007 | c->src.val = c->modrm_val; | ||
927 | break; | 1008 | break; |
928 | } | 1009 | } |
929 | c->src.type = OP_MEM; | 1010 | c->src.type = OP_MEM; |
@@ -967,6 +1048,7 @@ done_prefixes: | |||
967 | case DstMem: | 1048 | case DstMem: |
968 | if ((c->d & ModRM) && c->modrm_mod == 3) { | 1049 | if ((c->d & ModRM) && c->modrm_mod == 3) { |
969 | c->dst.type = OP_REG; | 1050 | c->dst.type = OP_REG; |
1051 | c->dst.val = c->dst.orig_val = c->modrm_val; | ||
970 | break; | 1052 | break; |
971 | } | 1053 | } |
972 | c->dst.type = OP_MEM; | 1054 | c->dst.type = OP_MEM; |
@@ -984,8 +1066,8 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt) | |||
984 | c->dst.type = OP_MEM; | 1066 | c->dst.type = OP_MEM; |
985 | c->dst.bytes = c->op_bytes; | 1067 | c->dst.bytes = c->op_bytes; |
986 | c->dst.val = c->src.val; | 1068 | c->dst.val = c->src.val; |
987 | register_address_increment(c->regs[VCPU_REGS_RSP], -c->op_bytes); | 1069 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); |
988 | c->dst.ptr = (void *) register_address(ctxt->ss_base, | 1070 | c->dst.ptr = (void *) register_address(c, ctxt->ss_base, |
989 | c->regs[VCPU_REGS_RSP]); | 1071 | c->regs[VCPU_REGS_RSP]); |
990 | } | 1072 | } |
991 | 1073 | ||
@@ -995,13 +1077,13 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt, | |||
995 | struct decode_cache *c = &ctxt->decode; | 1077 | struct decode_cache *c = &ctxt->decode; |
996 | int rc; | 1078 | int rc; |
997 | 1079 | ||
998 | rc = ops->read_std(register_address(ctxt->ss_base, | 1080 | rc = ops->read_std(register_address(c, ctxt->ss_base, |
999 | c->regs[VCPU_REGS_RSP]), | 1081 | c->regs[VCPU_REGS_RSP]), |
1000 | &c->dst.val, c->dst.bytes, ctxt->vcpu); | 1082 | &c->dst.val, c->dst.bytes, ctxt->vcpu); |
1001 | if (rc != 0) | 1083 | if (rc != 0) |
1002 | return rc; | 1084 | return rc; |
1003 | 1085 | ||
1004 | register_address_increment(c->regs[VCPU_REGS_RSP], c->dst.bytes); | 1086 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->dst.bytes); |
1005 | 1087 | ||
1006 | return 0; | 1088 | return 0; |
1007 | } | 1089 | } |
@@ -1043,26 +1125,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt, | |||
1043 | 1125 | ||
1044 | switch (c->modrm_reg) { | 1126 | switch (c->modrm_reg) { |
1045 | case 0 ... 1: /* test */ | 1127 | case 0 ... 1: /* test */ |
1046 | /* | ||
1047 | * Special case in Grp3: test has an immediate | ||
1048 | * source operand. | ||
1049 | */ | ||
1050 | c->src.type = OP_IMM; | ||
1051 | c->src.ptr = (unsigned long *)c->eip; | ||
1052 | c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | ||
1053 | if (c->src.bytes == 8) | ||
1054 | c->src.bytes = 4; | ||
1055 | switch (c->src.bytes) { | ||
1056 | case 1: | ||
1057 | c->src.val = insn_fetch(s8, 1, c->eip); | ||
1058 | break; | ||
1059 | case 2: | ||
1060 | c->src.val = insn_fetch(s16, 2, c->eip); | ||
1061 | break; | ||
1062 | case 4: | ||
1063 | c->src.val = insn_fetch(s32, 4, c->eip); | ||
1064 | break; | ||
1065 | } | ||
1066 | emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); | 1128 | emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags); |
1067 | break; | 1129 | break; |
1068 | case 2: /* not */ | 1130 | case 2: /* not */ |
@@ -1076,7 +1138,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt, | |||
1076 | rc = X86EMUL_UNHANDLEABLE; | 1138 | rc = X86EMUL_UNHANDLEABLE; |
1077 | break; | 1139 | break; |
1078 | } | 1140 | } |
1079 | done: | ||
1080 | return rc; | 1141 | return rc; |
1081 | } | 1142 | } |
1082 | 1143 | ||
@@ -1084,7 +1145,6 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, | |||
1084 | struct x86_emulate_ops *ops) | 1145 | struct x86_emulate_ops *ops) |
1085 | { | 1146 | { |
1086 | struct decode_cache *c = &ctxt->decode; | 1147 | struct decode_cache *c = &ctxt->decode; |
1087 | int rc; | ||
1088 | 1148 | ||
1089 | switch (c->modrm_reg) { | 1149 | switch (c->modrm_reg) { |
1090 | case 0: /* inc */ | 1150 | case 0: /* inc */ |
@@ -1094,36 +1154,11 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, | |||
1094 | emulate_1op("dec", c->dst, ctxt->eflags); | 1154 | emulate_1op("dec", c->dst, ctxt->eflags); |
1095 | break; | 1155 | break; |
1096 | case 4: /* jmp abs */ | 1156 | case 4: /* jmp abs */ |
1097 | if (c->b == 0xff) | 1157 | c->eip = c->src.val; |
1098 | c->eip = c->dst.val; | ||
1099 | else { | ||
1100 | DPRINTF("Cannot emulate %02x\n", c->b); | ||
1101 | return X86EMUL_UNHANDLEABLE; | ||
1102 | } | ||
1103 | break; | 1158 | break; |
1104 | case 6: /* push */ | 1159 | case 6: /* push */ |
1105 | 1160 | emulate_push(ctxt); | |
1106 | /* 64-bit mode: PUSH always pushes a 64-bit operand. */ | ||
1107 | |||
1108 | if (ctxt->mode == X86EMUL_MODE_PROT64) { | ||
1109 | c->dst.bytes = 8; | ||
1110 | rc = ops->read_std((unsigned long)c->dst.ptr, | ||
1111 | &c->dst.val, 8, ctxt->vcpu); | ||
1112 | if (rc != 0) | ||
1113 | return rc; | ||
1114 | } | ||
1115 | register_address_increment(c->regs[VCPU_REGS_RSP], | ||
1116 | -c->dst.bytes); | ||
1117 | rc = ops->write_emulated(register_address(ctxt->ss_base, | ||
1118 | c->regs[VCPU_REGS_RSP]), &c->dst.val, | ||
1119 | c->dst.bytes, ctxt->vcpu); | ||
1120 | if (rc != 0) | ||
1121 | return rc; | ||
1122 | c->dst.type = OP_NONE; | ||
1123 | break; | 1161 | break; |
1124 | default: | ||
1125 | DPRINTF("Cannot emulate %02x\n", c->b); | ||
1126 | return X86EMUL_UNHANDLEABLE; | ||
1127 | } | 1162 | } |
1128 | return 0; | 1163 | return 0; |
1129 | } | 1164 | } |
@@ -1361,19 +1396,19 @@ special_insn: | |||
1361 | c->dst.type = OP_MEM; | 1396 | c->dst.type = OP_MEM; |
1362 | c->dst.bytes = c->op_bytes; | 1397 | c->dst.bytes = c->op_bytes; |
1363 | c->dst.val = c->src.val; | 1398 | c->dst.val = c->src.val; |
1364 | register_address_increment(c->regs[VCPU_REGS_RSP], | 1399 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], |
1365 | -c->op_bytes); | 1400 | -c->op_bytes); |
1366 | c->dst.ptr = (void *) register_address( | 1401 | c->dst.ptr = (void *) register_address( |
1367 | ctxt->ss_base, c->regs[VCPU_REGS_RSP]); | 1402 | c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]); |
1368 | break; | 1403 | break; |
1369 | case 0x58 ... 0x5f: /* pop reg */ | 1404 | case 0x58 ... 0x5f: /* pop reg */ |
1370 | pop_instruction: | 1405 | pop_instruction: |
1371 | if ((rc = ops->read_std(register_address(ctxt->ss_base, | 1406 | if ((rc = ops->read_std(register_address(c, ctxt->ss_base, |
1372 | c->regs[VCPU_REGS_RSP]), c->dst.ptr, | 1407 | c->regs[VCPU_REGS_RSP]), c->dst.ptr, |
1373 | c->op_bytes, ctxt->vcpu)) != 0) | 1408 | c->op_bytes, ctxt->vcpu)) != 0) |
1374 | goto done; | 1409 | goto done; |
1375 | 1410 | ||
1376 | register_address_increment(c->regs[VCPU_REGS_RSP], | 1411 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], |
1377 | c->op_bytes); | 1412 | c->op_bytes); |
1378 | c->dst.type = OP_NONE; /* Disable writeback. */ | 1413 | c->dst.type = OP_NONE; /* Disable writeback. */ |
1379 | break; | 1414 | break; |
@@ -1393,9 +1428,9 @@ special_insn: | |||
1393 | 1, | 1428 | 1, |
1394 | (c->d & ByteOp) ? 1 : c->op_bytes, | 1429 | (c->d & ByteOp) ? 1 : c->op_bytes, |
1395 | c->rep_prefix ? | 1430 | c->rep_prefix ? |
1396 | address_mask(c->regs[VCPU_REGS_RCX]) : 1, | 1431 | address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, |
1397 | (ctxt->eflags & EFLG_DF), | 1432 | (ctxt->eflags & EFLG_DF), |
1398 | register_address(ctxt->es_base, | 1433 | register_address(c, ctxt->es_base, |
1399 | c->regs[VCPU_REGS_RDI]), | 1434 | c->regs[VCPU_REGS_RDI]), |
1400 | c->rep_prefix, | 1435 | c->rep_prefix, |
1401 | c->regs[VCPU_REGS_RDX]) == 0) { | 1436 | c->regs[VCPU_REGS_RDX]) == 0) { |
@@ -1409,9 +1444,9 @@ special_insn: | |||
1409 | 0, | 1444 | 0, |
1410 | (c->d & ByteOp) ? 1 : c->op_bytes, | 1445 | (c->d & ByteOp) ? 1 : c->op_bytes, |
1411 | c->rep_prefix ? | 1446 | c->rep_prefix ? |
1412 | address_mask(c->regs[VCPU_REGS_RCX]) : 1, | 1447 | address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, |
1413 | (ctxt->eflags & EFLG_DF), | 1448 | (ctxt->eflags & EFLG_DF), |
1414 | register_address(c->override_base ? | 1449 | register_address(c, c->override_base ? |
1415 | *c->override_base : | 1450 | *c->override_base : |
1416 | ctxt->ds_base, | 1451 | ctxt->ds_base, |
1417 | c->regs[VCPU_REGS_RSI]), | 1452 | c->regs[VCPU_REGS_RSI]), |
@@ -1425,7 +1460,7 @@ special_insn: | |||
1425 | int rel = insn_fetch(s8, 1, c->eip); | 1460 | int rel = insn_fetch(s8, 1, c->eip); |
1426 | 1461 | ||
1427 | if (test_cc(c->b, ctxt->eflags)) | 1462 | if (test_cc(c->b, ctxt->eflags)) |
1428 | JMP_REL(rel); | 1463 | jmp_rel(c, rel); |
1429 | break; | 1464 | break; |
1430 | } | 1465 | } |
1431 | case 0x80 ... 0x83: /* Grp1 */ | 1466 | case 0x80 ... 0x83: /* Grp1 */ |
@@ -1477,7 +1512,7 @@ special_insn: | |||
1477 | case 0x88 ... 0x8b: /* mov */ | 1512 | case 0x88 ... 0x8b: /* mov */ |
1478 | goto mov; | 1513 | goto mov; |
1479 | case 0x8d: /* lea r16/r32, m */ | 1514 | case 0x8d: /* lea r16/r32, m */ |
1480 | c->dst.val = c->modrm_val; | 1515 | c->dst.val = c->modrm_ea; |
1481 | break; | 1516 | break; |
1482 | case 0x8f: /* pop (sole member of Grp1a) */ | 1517 | case 0x8f: /* pop (sole member of Grp1a) */ |
1483 | rc = emulate_grp1a(ctxt, ops); | 1518 | rc = emulate_grp1a(ctxt, ops); |
@@ -1501,27 +1536,27 @@ special_insn: | |||
1501 | case 0xa4 ... 0xa5: /* movs */ | 1536 | case 0xa4 ... 0xa5: /* movs */ |
1502 | c->dst.type = OP_MEM; | 1537 | c->dst.type = OP_MEM; |
1503 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1538 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1504 | c->dst.ptr = (unsigned long *)register_address( | 1539 | c->dst.ptr = (unsigned long *)register_address(c, |
1505 | ctxt->es_base, | 1540 | ctxt->es_base, |
1506 | c->regs[VCPU_REGS_RDI]); | 1541 | c->regs[VCPU_REGS_RDI]); |
1507 | if ((rc = ops->read_emulated(register_address( | 1542 | if ((rc = ops->read_emulated(register_address(c, |
1508 | c->override_base ? *c->override_base : | 1543 | c->override_base ? *c->override_base : |
1509 | ctxt->ds_base, | 1544 | ctxt->ds_base, |
1510 | c->regs[VCPU_REGS_RSI]), | 1545 | c->regs[VCPU_REGS_RSI]), |
1511 | &c->dst.val, | 1546 | &c->dst.val, |
1512 | c->dst.bytes, ctxt->vcpu)) != 0) | 1547 | c->dst.bytes, ctxt->vcpu)) != 0) |
1513 | goto done; | 1548 | goto done; |
1514 | register_address_increment(c->regs[VCPU_REGS_RSI], | 1549 | register_address_increment(c, &c->regs[VCPU_REGS_RSI], |
1515 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | 1550 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes |
1516 | : c->dst.bytes); | 1551 | : c->dst.bytes); |
1517 | register_address_increment(c->regs[VCPU_REGS_RDI], | 1552 | register_address_increment(c, &c->regs[VCPU_REGS_RDI], |
1518 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | 1553 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes |
1519 | : c->dst.bytes); | 1554 | : c->dst.bytes); |
1520 | break; | 1555 | break; |
1521 | case 0xa6 ... 0xa7: /* cmps */ | 1556 | case 0xa6 ... 0xa7: /* cmps */ |
1522 | c->src.type = OP_NONE; /* Disable writeback. */ | 1557 | c->src.type = OP_NONE; /* Disable writeback. */ |
1523 | c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1558 | c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1524 | c->src.ptr = (unsigned long *)register_address( | 1559 | c->src.ptr = (unsigned long *)register_address(c, |
1525 | c->override_base ? *c->override_base : | 1560 | c->override_base ? *c->override_base : |
1526 | ctxt->ds_base, | 1561 | ctxt->ds_base, |
1527 | c->regs[VCPU_REGS_RSI]); | 1562 | c->regs[VCPU_REGS_RSI]); |
@@ -1533,7 +1568,7 @@ special_insn: | |||
1533 | 1568 | ||
1534 | c->dst.type = OP_NONE; /* Disable writeback. */ | 1569 | c->dst.type = OP_NONE; /* Disable writeback. */ |
1535 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1570 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1536 | c->dst.ptr = (unsigned long *)register_address( | 1571 | c->dst.ptr = (unsigned long *)register_address(c, |
1537 | ctxt->es_base, | 1572 | ctxt->es_base, |
1538 | c->regs[VCPU_REGS_RDI]); | 1573 | c->regs[VCPU_REGS_RDI]); |
1539 | if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, | 1574 | if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, |
@@ -1546,10 +1581,10 @@ special_insn: | |||
1546 | 1581 | ||
1547 | emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); | 1582 | emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); |
1548 | 1583 | ||
1549 | register_address_increment(c->regs[VCPU_REGS_RSI], | 1584 | register_address_increment(c, &c->regs[VCPU_REGS_RSI], |
1550 | (ctxt->eflags & EFLG_DF) ? -c->src.bytes | 1585 | (ctxt->eflags & EFLG_DF) ? -c->src.bytes |
1551 | : c->src.bytes); | 1586 | : c->src.bytes); |
1552 | register_address_increment(c->regs[VCPU_REGS_RDI], | 1587 | register_address_increment(c, &c->regs[VCPU_REGS_RDI], |
1553 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | 1588 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes |
1554 | : c->dst.bytes); | 1589 | : c->dst.bytes); |
1555 | 1590 | ||
@@ -1557,11 +1592,11 @@ special_insn: | |||
1557 | case 0xaa ... 0xab: /* stos */ | 1592 | case 0xaa ... 0xab: /* stos */ |
1558 | c->dst.type = OP_MEM; | 1593 | c->dst.type = OP_MEM; |
1559 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1594 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1560 | c->dst.ptr = (unsigned long *)register_address( | 1595 | c->dst.ptr = (unsigned long *)register_address(c, |
1561 | ctxt->es_base, | 1596 | ctxt->es_base, |
1562 | c->regs[VCPU_REGS_RDI]); | 1597 | c->regs[VCPU_REGS_RDI]); |
1563 | c->dst.val = c->regs[VCPU_REGS_RAX]; | 1598 | c->dst.val = c->regs[VCPU_REGS_RAX]; |
1564 | register_address_increment(c->regs[VCPU_REGS_RDI], | 1599 | register_address_increment(c, &c->regs[VCPU_REGS_RDI], |
1565 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | 1600 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes |
1566 | : c->dst.bytes); | 1601 | : c->dst.bytes); |
1567 | break; | 1602 | break; |
@@ -1569,7 +1604,7 @@ special_insn: | |||
1569 | c->dst.type = OP_REG; | 1604 | c->dst.type = OP_REG; |
1570 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1605 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1571 | c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; | 1606 | c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; |
1572 | if ((rc = ops->read_emulated(register_address( | 1607 | if ((rc = ops->read_emulated(register_address(c, |
1573 | c->override_base ? *c->override_base : | 1608 | c->override_base ? *c->override_base : |
1574 | ctxt->ds_base, | 1609 | ctxt->ds_base, |
1575 | c->regs[VCPU_REGS_RSI]), | 1610 | c->regs[VCPU_REGS_RSI]), |
@@ -1577,7 +1612,7 @@ special_insn: | |||
1577 | c->dst.bytes, | 1612 | c->dst.bytes, |
1578 | ctxt->vcpu)) != 0) | 1613 | ctxt->vcpu)) != 0) |
1579 | goto done; | 1614 | goto done; |
1580 | register_address_increment(c->regs[VCPU_REGS_RSI], | 1615 | register_address_increment(c, &c->regs[VCPU_REGS_RSI], |
1581 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | 1616 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes |
1582 | : c->dst.bytes); | 1617 | : c->dst.bytes); |
1583 | break; | 1618 | break; |
@@ -1616,14 +1651,14 @@ special_insn: | |||
1616 | goto cannot_emulate; | 1651 | goto cannot_emulate; |
1617 | } | 1652 | } |
1618 | c->src.val = (unsigned long) c->eip; | 1653 | c->src.val = (unsigned long) c->eip; |
1619 | JMP_REL(rel); | 1654 | jmp_rel(c, rel); |
1620 | c->op_bytes = c->ad_bytes; | 1655 | c->op_bytes = c->ad_bytes; |
1621 | emulate_push(ctxt); | 1656 | emulate_push(ctxt); |
1622 | break; | 1657 | break; |
1623 | } | 1658 | } |
1624 | case 0xe9: /* jmp rel */ | 1659 | case 0xe9: /* jmp rel */ |
1625 | case 0xeb: /* jmp rel short */ | 1660 | case 0xeb: /* jmp rel short */ |
1626 | JMP_REL(c->src.val); | 1661 | jmp_rel(c, c->src.val); |
1627 | c->dst.type = OP_NONE; /* Disable writeback. */ | 1662 | c->dst.type = OP_NONE; /* Disable writeback. */ |
1628 | break; | 1663 | break; |
1629 | case 0xf4: /* hlt */ | 1664 | case 0xf4: /* hlt */ |
@@ -1690,6 +1725,8 @@ twobyte_insn: | |||
1690 | goto done; | 1725 | goto done; |
1691 | 1726 | ||
1692 | kvm_emulate_hypercall(ctxt->vcpu); | 1727 | kvm_emulate_hypercall(ctxt->vcpu); |
1728 | /* Disable writeback. */ | ||
1729 | c->dst.type = OP_NONE; | ||
1693 | break; | 1730 | break; |
1694 | case 2: /* lgdt */ | 1731 | case 2: /* lgdt */ |
1695 | rc = read_descriptor(ctxt, ops, c->src.ptr, | 1732 | rc = read_descriptor(ctxt, ops, c->src.ptr, |
@@ -1697,6 +1734,8 @@ twobyte_insn: | |||
1697 | if (rc) | 1734 | if (rc) |
1698 | goto done; | 1735 | goto done; |
1699 | realmode_lgdt(ctxt->vcpu, size, address); | 1736 | realmode_lgdt(ctxt->vcpu, size, address); |
1737 | /* Disable writeback. */ | ||
1738 | c->dst.type = OP_NONE; | ||
1700 | break; | 1739 | break; |
1701 | case 3: /* lidt/vmmcall */ | 1740 | case 3: /* lidt/vmmcall */ |
1702 | if (c->modrm_mod == 3 && c->modrm_rm == 1) { | 1741 | if (c->modrm_mod == 3 && c->modrm_rm == 1) { |
@@ -1712,27 +1751,25 @@ twobyte_insn: | |||
1712 | goto done; | 1751 | goto done; |
1713 | realmode_lidt(ctxt->vcpu, size, address); | 1752 | realmode_lidt(ctxt->vcpu, size, address); |
1714 | } | 1753 | } |
1754 | /* Disable writeback. */ | ||
1755 | c->dst.type = OP_NONE; | ||
1715 | break; | 1756 | break; |
1716 | case 4: /* smsw */ | 1757 | case 4: /* smsw */ |
1717 | if (c->modrm_mod != 3) | 1758 | c->dst.bytes = 2; |
1718 | goto cannot_emulate; | 1759 | c->dst.val = realmode_get_cr(ctxt->vcpu, 0); |
1719 | *(u16 *)&c->regs[c->modrm_rm] | ||
1720 | = realmode_get_cr(ctxt->vcpu, 0); | ||
1721 | break; | 1760 | break; |
1722 | case 6: /* lmsw */ | 1761 | case 6: /* lmsw */ |
1723 | if (c->modrm_mod != 3) | 1762 | realmode_lmsw(ctxt->vcpu, (u16)c->src.val, |
1724 | goto cannot_emulate; | 1763 | &ctxt->eflags); |
1725 | realmode_lmsw(ctxt->vcpu, (u16)c->modrm_val, | ||
1726 | &ctxt->eflags); | ||
1727 | break; | 1764 | break; |
1728 | case 7: /* invlpg*/ | 1765 | case 7: /* invlpg*/ |
1729 | emulate_invlpg(ctxt->vcpu, memop); | 1766 | emulate_invlpg(ctxt->vcpu, memop); |
1767 | /* Disable writeback. */ | ||
1768 | c->dst.type = OP_NONE; | ||
1730 | break; | 1769 | break; |
1731 | default: | 1770 | default: |
1732 | goto cannot_emulate; | 1771 | goto cannot_emulate; |
1733 | } | 1772 | } |
1734 | /* Disable writeback. */ | ||
1735 | c->dst.type = OP_NONE; | ||
1736 | break; | 1773 | break; |
1737 | case 0x06: | 1774 | case 0x06: |
1738 | emulate_clts(ctxt->vcpu); | 1775 | emulate_clts(ctxt->vcpu); |
@@ -1823,7 +1860,7 @@ twobyte_insn: | |||
1823 | goto cannot_emulate; | 1860 | goto cannot_emulate; |
1824 | } | 1861 | } |
1825 | if (test_cc(c->b, ctxt->eflags)) | 1862 | if (test_cc(c->b, ctxt->eflags)) |
1826 | JMP_REL(rel); | 1863 | jmp_rel(c, rel); |
1827 | c->dst.type = OP_NONE; | 1864 | c->dst.type = OP_NONE; |
1828 | break; | 1865 | break; |
1829 | } | 1866 | } |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 4a4761892951..de236e419cb5 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -287,47 +287,17 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base) | |||
287 | pkmap_page_table = pte; | 287 | pkmap_page_table = pte; |
288 | } | 288 | } |
289 | 289 | ||
290 | static void __meminit free_new_highpage(struct page *page) | ||
291 | { | ||
292 | init_page_count(page); | ||
293 | __free_page(page); | ||
294 | totalhigh_pages++; | ||
295 | } | ||
296 | |||
297 | void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro) | 290 | void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro) |
298 | { | 291 | { |
299 | if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { | 292 | if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { |
300 | ClearPageReserved(page); | 293 | ClearPageReserved(page); |
301 | free_new_highpage(page); | 294 | init_page_count(page); |
295 | __free_page(page); | ||
296 | totalhigh_pages++; | ||
302 | } else | 297 | } else |
303 | SetPageReserved(page); | 298 | SetPageReserved(page); |
304 | } | 299 | } |
305 | 300 | ||
306 | static int __meminit | ||
307 | add_one_highpage_hotplug(struct page *page, unsigned long pfn) | ||
308 | { | ||
309 | free_new_highpage(page); | ||
310 | totalram_pages++; | ||
311 | #ifdef CONFIG_FLATMEM | ||
312 | max_mapnr = max(pfn, max_mapnr); | ||
313 | #endif | ||
314 | num_physpages++; | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Not currently handling the NUMA case. | ||
321 | * Assuming single node and all memory that | ||
322 | * has been added dynamically that would be | ||
323 | * onlined here is in HIGHMEM. | ||
324 | */ | ||
325 | void __meminit online_page(struct page *page) | ||
326 | { | ||
327 | ClearPageReserved(page); | ||
328 | add_one_highpage_hotplug(page, page_to_pfn(page)); | ||
329 | } | ||
330 | |||
331 | #ifndef CONFIG_NUMA | 301 | #ifndef CONFIG_NUMA |
332 | static void __init set_highmem_pages_init(int bad_ppro) | 302 | static void __init set_highmem_pages_init(int bad_ppro) |
333 | { | 303 | { |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 5fbb8652cf59..32ba13b0f818 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -620,15 +620,6 @@ void __init paging_init(void) | |||
620 | /* | 620 | /* |
621 | * Memory hotplug specific functions | 621 | * Memory hotplug specific functions |
622 | */ | 622 | */ |
623 | void online_page(struct page *page) | ||
624 | { | ||
625 | ClearPageReserved(page); | ||
626 | init_page_count(page); | ||
627 | __free_page(page); | ||
628 | totalram_pages++; | ||
629 | num_physpages++; | ||
630 | } | ||
631 | |||
632 | #ifdef CONFIG_MEMORY_HOTPLUG | 623 | #ifdef CONFIG_MEMORY_HOTPLUG |
633 | /* | 624 | /* |
634 | * Memory is added always to NORMAL zone. This means you will never get | 625 | * Memory is added always to NORMAL zone. This means you will never get |
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index d176b23110cc..804de18abcc2 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -117,8 +117,8 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size, | |||
117 | * have to convert them into an offset in a page-aligned mapping, but the | 117 | * have to convert them into an offset in a page-aligned mapping, but the |
118 | * caller shouldn't need to know that small detail. | 118 | * caller shouldn't need to know that small detail. |
119 | */ | 119 | */ |
120 | static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size, | 120 | static void __iomem *__ioremap_caller(resource_size_t phys_addr, |
121 | unsigned long prot_val) | 121 | unsigned long size, unsigned long prot_val, void *caller) |
122 | { | 122 | { |
123 | unsigned long pfn, offset, vaddr; | 123 | unsigned long pfn, offset, vaddr; |
124 | resource_size_t last_addr; | 124 | resource_size_t last_addr; |
@@ -212,7 +212,7 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size, | |||
212 | /* | 212 | /* |
213 | * Ok, go for it.. | 213 | * Ok, go for it.. |
214 | */ | 214 | */ |
215 | area = get_vm_area(size, VM_IOREMAP); | 215 | area = get_vm_area_caller(size, VM_IOREMAP, caller); |
216 | if (!area) | 216 | if (!area) |
217 | return NULL; | 217 | return NULL; |
218 | area->phys_addr = phys_addr; | 218 | area->phys_addr = phys_addr; |
@@ -255,7 +255,8 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size, | |||
255 | */ | 255 | */ |
256 | void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size) | 256 | void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size) |
257 | { | 257 | { |
258 | return __ioremap(phys_addr, size, _PAGE_CACHE_UC); | 258 | return __ioremap_caller(phys_addr, size, _PAGE_CACHE_UC, |
259 | __builtin_return_address(0)); | ||
259 | } | 260 | } |
260 | EXPORT_SYMBOL(ioremap_nocache); | 261 | EXPORT_SYMBOL(ioremap_nocache); |
261 | 262 | ||
@@ -272,7 +273,8 @@ EXPORT_SYMBOL(ioremap_nocache); | |||
272 | void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size) | 273 | void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size) |
273 | { | 274 | { |
274 | if (pat_wc_enabled) | 275 | if (pat_wc_enabled) |
275 | return __ioremap(phys_addr, size, _PAGE_CACHE_WC); | 276 | return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WC, |
277 | __builtin_return_address(0)); | ||
276 | else | 278 | else |
277 | return ioremap_nocache(phys_addr, size); | 279 | return ioremap_nocache(phys_addr, size); |
278 | } | 280 | } |
@@ -280,7 +282,8 @@ EXPORT_SYMBOL(ioremap_wc); | |||
280 | 282 | ||
281 | void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size) | 283 | void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size) |
282 | { | 284 | { |
283 | return __ioremap(phys_addr, size, _PAGE_CACHE_WB); | 285 | return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WB, |
286 | __builtin_return_address(0)); | ||
284 | } | 287 | } |
285 | EXPORT_SYMBOL(ioremap_cache); | 288 | EXPORT_SYMBOL(ioremap_cache); |
286 | 289 | ||
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index e7ca7fc48d12..277446cd30b6 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -387,8 +387,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
387 | break; | 387 | break; |
388 | } | 388 | } |
389 | 389 | ||
390 | printk(KERN_INFO "Overlap at 0x%Lx-0x%Lx\n", | 390 | pr_debug(KERN_INFO "Overlap at 0x%Lx-0x%Lx\n", |
391 | saved_ptr->start, saved_ptr->end); | 391 | saved_ptr->start, saved_ptr->end); |
392 | /* No conflict. Go ahead and add this new entry */ | 392 | /* No conflict. Go ahead and add this new entry */ |
393 | list_add(&new_entry->nd, &saved_ptr->nd); | 393 | list_add(&new_entry->nd, &saved_ptr->nd); |
394 | new_entry = NULL; | 394 | new_entry = NULL; |
@@ -510,7 +510,6 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | |||
510 | { | 510 | { |
511 | u64 offset = ((u64) pfn) << PAGE_SHIFT; | 511 | u64 offset = ((u64) pfn) << PAGE_SHIFT; |
512 | unsigned long flags = _PAGE_CACHE_UC_MINUS; | 512 | unsigned long flags = _PAGE_CACHE_UC_MINUS; |
513 | unsigned long ret_flags; | ||
514 | int retval; | 513 | int retval; |
515 | 514 | ||
516 | if (!range_is_allowed(pfn, size)) | 515 | if (!range_is_allowed(pfn, size)) |
@@ -549,14 +548,12 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | |||
549 | if (flags != _PAGE_CACHE_UC_MINUS) { | 548 | if (flags != _PAGE_CACHE_UC_MINUS) { |
550 | retval = reserve_memtype(offset, offset + size, flags, NULL); | 549 | retval = reserve_memtype(offset, offset + size, flags, NULL); |
551 | } else { | 550 | } else { |
552 | retval = reserve_memtype(offset, offset + size, -1, &ret_flags); | 551 | retval = reserve_memtype(offset, offset + size, -1, &flags); |
553 | } | 552 | } |
554 | 553 | ||
555 | if (retval < 0) | 554 | if (retval < 0) |
556 | return 0; | 555 | return 0; |
557 | 556 | ||
558 | flags = ret_flags; | ||
559 | |||
560 | if (pfn <= max_pfn_mapped && | 557 | if (pfn <= max_pfn_mapped && |
561 | ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { | 558 | ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { |
562 | free_memtype(offset, offset + size); | 559 | free_memtype(offset, offset + size); |
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32 index e9c5caf54e59..2a1516efb542 100644 --- a/arch/x86/pci/Makefile_32 +++ b/arch/x86/pci/Makefile_32 | |||
@@ -3,6 +3,7 @@ obj-y := i386.o init.o | |||
3 | obj-$(CONFIG_PCI_BIOS) += pcbios.o | 3 | obj-$(CONFIG_PCI_BIOS) += pcbios.o |
4 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o | 4 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o |
5 | obj-$(CONFIG_PCI_DIRECT) += direct.o | 5 | obj-$(CONFIG_PCI_DIRECT) += direct.o |
6 | obj-$(CONFIG_PCI_OLPC) += olpc.o | ||
6 | 7 | ||
7 | pci-y := fixup.o | 8 | pci-y := fixup.o |
8 | pci-$(CONFIG_ACPI) += acpi.o | 9 | pci-$(CONFIG_ACPI) += acpi.o |
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c index 343c36337e69..dd30c6076b5d 100644 --- a/arch/x86/pci/init.c +++ b/arch/x86/pci/init.c | |||
@@ -11,8 +11,12 @@ static __init int pci_access_init(void) | |||
11 | 11 | ||
12 | type = pci_direct_probe(); | 12 | type = pci_direct_probe(); |
13 | #endif | 13 | #endif |
14 | |||
14 | pci_mmcfg_early_init(); | 15 | pci_mmcfg_early_init(); |
15 | 16 | ||
17 | #ifdef CONFIG_PCI_OLPC | ||
18 | pci_olpc_init(); | ||
19 | #endif | ||
16 | #ifdef CONFIG_PCI_BIOS | 20 | #ifdef CONFIG_PCI_BIOS |
17 | pci_pcbios_init(); | 21 | pci_pcbios_init(); |
18 | #endif | 22 | #endif |
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c new file mode 100644 index 000000000000..5e7636558c02 --- /dev/null +++ b/arch/x86/pci/olpc.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * Low-level PCI config space access for OLPC systems who lack the VSA | ||
3 | * PCI virtualization software. | ||
4 | * | ||
5 | * Copyright © 2006 Advanced Micro Devices, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * The AMD Geode chipset (ie: GX2 processor, cs5536 I/O companion device) | ||
13 | * has some I/O functions (display, southbridge, sound, USB HCIs, etc) | ||
14 | * that more or less behave like PCI devices, but the hardware doesn't | ||
15 | * directly implement the PCI configuration space headers. AMD provides | ||
16 | * "VSA" (Virtual System Architecture) software that emulates PCI config | ||
17 | * space for these devices, by trapping I/O accesses to PCI config register | ||
18 | * (CF8/CFC) and running some code in System Management Mode interrupt state. | ||
19 | * On the OLPC platform, we don't want to use that VSA code because | ||
20 | * (a) it slows down suspend/resume, and (b) recompiling it requires special | ||
21 | * compilers that are hard to get. So instead of letting the complex VSA | ||
22 | * code simulate the PCI config registers for the on-chip devices, we | ||
23 | * just simulate them the easy way, by inserting the code into the | ||
24 | * pci_write_config and pci_read_config path. Most of the config registers | ||
25 | * are read-only anyway, so the bulk of the simulation is just table lookup. | ||
26 | */ | ||
27 | |||
28 | #include <linux/pci.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <asm/olpc.h> | ||
31 | #include <asm/geode.h> | ||
32 | #include "pci.h" | ||
33 | |||
34 | /* | ||
35 | * In the tables below, the first two line (8 longwords) are the | ||
36 | * size masks that are used when the higher level PCI code determines | ||
37 | * the size of the region by writing ~0 to a base address register | ||
38 | * and reading back the result. | ||
39 | * | ||
40 | * The following lines are the values that are read during normal | ||
41 | * PCI config access cycles, i.e. not after just having written | ||
42 | * ~0 to a base address register. | ||
43 | */ | ||
44 | |||
45 | static const uint32_t lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */ | ||
46 | 0x0, 0x0, 0x0, 0x0, | ||
47 | 0x0, 0x0, 0x0, 0x0, | ||
48 | |||
49 | 0x281022, 0x2200005, 0x6000021, 0x80f808, /* AMD Vendor ID */ | ||
50 | 0x0, 0x0, 0x0, 0x0, /* No virtual registers, hence no BAR */ | ||
51 | 0x0, 0x0, 0x0, 0x28100b, | ||
52 | 0x0, 0x0, 0x0, 0x0, | ||
53 | 0x0, 0x0, 0x0, 0x0, | ||
54 | 0x0, 0x0, 0x0, 0x0, | ||
55 | 0x0, 0x0, 0x0, 0x0, | ||
56 | }; | ||
57 | |||
58 | static const uint32_t gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */ | ||
59 | 0xfffffffd, 0x0, 0x0, 0x0, | ||
60 | 0x0, 0x0, 0x0, 0x0, | ||
61 | |||
62 | 0x28100b, 0x2200005, 0x6000021, 0x80f808, /* NSC Vendor ID */ | ||
63 | 0xac1d, 0x0, 0x0, 0x0, /* I/O BAR - base of virtual registers */ | ||
64 | 0x0, 0x0, 0x0, 0x28100b, | ||
65 | 0x0, 0x0, 0x0, 0x0, | ||
66 | 0x0, 0x0, 0x0, 0x0, | ||
67 | 0x0, 0x0, 0x0, 0x0, | ||
68 | 0x0, 0x0, 0x0, 0x0, | ||
69 | }; | ||
70 | |||
71 | static const uint32_t lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */ | ||
72 | 0xff000008, 0xffffc000, 0xffffc000, 0xffffc000, | ||
73 | 0xffffc000, 0x0, 0x0, 0x0, | ||
74 | |||
75 | 0x20811022, 0x2200003, 0x3000000, 0x0, /* AMD Vendor ID */ | ||
76 | 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */ | ||
77 | 0xfe00c000, 0x0, 0x0, 0x30100b, /* VIP */ | ||
78 | 0x0, 0x0, 0x0, 0x10e, /* INTA, IRQ14 for graphics accel */ | ||
79 | 0x0, 0x0, 0x0, 0x0, | ||
80 | 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */ | ||
81 | 0x0, 0x0, 0x0, 0x0, | ||
82 | }; | ||
83 | |||
84 | static const uint32_t gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */ | ||
85 | 0xff800008, 0xffffc000, 0xffffc000, 0xffffc000, | ||
86 | 0x0, 0x0, 0x0, 0x0, | ||
87 | |||
88 | 0x30100b, 0x2200003, 0x3000000, 0x0, /* NSC Vendor ID */ | ||
89 | 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */ | ||
90 | 0x0, 0x0, 0x0, 0x30100b, | ||
91 | 0x0, 0x0, 0x0, 0x0, | ||
92 | 0x0, 0x0, 0x0, 0x0, | ||
93 | 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */ | ||
94 | 0x0, 0x0, 0x0, 0x0, | ||
95 | }; | ||
96 | |||
97 | static const uint32_t aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */ | ||
98 | 0xffffc000, 0x0, 0x0, 0x0, | ||
99 | 0x0, 0x0, 0x0, 0x0, | ||
100 | |||
101 | 0x20821022, 0x2a00006, 0x10100000, 0x8, /* NSC Vendor ID */ | ||
102 | 0xfe010000, 0x0, 0x0, 0x0, /* AES registers */ | ||
103 | 0x0, 0x0, 0x0, 0x20821022, | ||
104 | 0x0, 0x0, 0x0, 0x0, | ||
105 | 0x0, 0x0, 0x0, 0x0, | ||
106 | 0x0, 0x0, 0x0, 0x0, | ||
107 | 0x0, 0x0, 0x0, 0x0, | ||
108 | }; | ||
109 | |||
110 | |||
111 | static const uint32_t isa_hdr[] = { /* dev f function 0 - devfn = 78 */ | ||
112 | 0xfffffff9, 0xffffff01, 0xffffffc1, 0xffffffe1, | ||
113 | 0xffffff81, 0xffffffc1, 0x0, 0x0, | ||
114 | |||
115 | 0x20901022, 0x2a00049, 0x6010003, 0x802000, | ||
116 | 0x18b1, 0x1001, 0x1801, 0x1881, /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */ | ||
117 | 0x1401, 0x1841, 0x0, 0x20901022, /* PMS-128 ACPI-64 */ | ||
118 | 0x0, 0x0, 0x0, 0x0, | ||
119 | 0x0, 0x0, 0x0, 0x0, | ||
120 | 0x0, 0x0, 0x0, 0xaa5b, /* IRQ steering */ | ||
121 | 0x0, 0x0, 0x0, 0x0, | ||
122 | }; | ||
123 | |||
124 | static const uint32_t ac97_hdr[] = { /* dev f function 3 - devfn = 7b */ | ||
125 | 0xffffff81, 0x0, 0x0, 0x0, | ||
126 | 0x0, 0x0, 0x0, 0x0, | ||
127 | |||
128 | 0x20931022, 0x2a00041, 0x4010001, 0x0, | ||
129 | 0x1481, 0x0, 0x0, 0x0, /* I/O BAR-128 */ | ||
130 | 0x0, 0x0, 0x0, 0x20931022, | ||
131 | 0x0, 0x0, 0x0, 0x205, /* IntB, IRQ5 */ | ||
132 | 0x0, 0x0, 0x0, 0x0, | ||
133 | 0x0, 0x0, 0x0, 0x0, | ||
134 | 0x0, 0x0, 0x0, 0x0, | ||
135 | }; | ||
136 | |||
137 | static const uint32_t ohci_hdr[] = { /* dev f function 4 - devfn = 7c */ | ||
138 | 0xfffff000, 0x0, 0x0, 0x0, | ||
139 | 0x0, 0x0, 0x0, 0x0, | ||
140 | |||
141 | 0x20941022, 0x2300006, 0xc031002, 0x0, | ||
142 | 0xfe01a000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */ | ||
143 | 0x0, 0x0, 0x0, 0x20941022, | ||
144 | 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */ | ||
145 | 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, | ||
146 | 44 is mask 8103 (power control) */ | ||
147 | 0x0, 0x0, 0x0, 0x0, | ||
148 | 0x0, 0x0, 0x0, 0x0, | ||
149 | }; | ||
150 | |||
151 | static const uint32_t ehci_hdr[] = { /* dev f function 4 - devfn = 7d */ | ||
152 | 0xfffff000, 0x0, 0x0, 0x0, | ||
153 | 0x0, 0x0, 0x0, 0x0, | ||
154 | |||
155 | 0x20951022, 0x2300006, 0xc032002, 0x0, | ||
156 | 0xfe01b000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */ | ||
157 | 0x0, 0x0, 0x0, 0x20951022, | ||
158 | 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */ | ||
159 | 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, 44 is | ||
160 | mask 8103 (power control) */ | ||
161 | #if 0 | ||
162 | 0x1, 0x40080000, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */ | ||
163 | #endif | ||
164 | 0x01000001, 0x0, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */ | ||
165 | 0x2020, 0x0, 0x0, 0x0, /* (EHCI page 8) 60 SBRN (R/O), | ||
166 | 61 FLADJ (R/W), PORTWAKECAP */ | ||
167 | }; | ||
168 | |||
169 | static uint32_t ff_loc = ~0; | ||
170 | static uint32_t zero_loc; | ||
171 | static int bar_probing; /* Set after a write of ~0 to a BAR */ | ||
172 | static int is_lx; | ||
173 | |||
174 | #define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */ | ||
175 | #define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */ | ||
176 | |||
177 | static int is_simulated(unsigned int bus, unsigned int devfn) | ||
178 | { | ||
179 | return (!bus && ((PCI_SLOT(devfn) == NB_SLOT) || | ||
180 | (PCI_SLOT(devfn) == SB_SLOT))); | ||
181 | } | ||
182 | |||
183 | static uint32_t *hdr_addr(const uint32_t *hdr, int reg) | ||
184 | { | ||
185 | uint32_t addr; | ||
186 | |||
187 | /* | ||
188 | * This is a little bit tricky. The header maps consist of | ||
189 | * 0x20 bytes of size masks, followed by 0x70 bytes of header data. | ||
190 | * In the normal case, when not probing a BAR's size, we want | ||
191 | * to access the header data, so we add 0x20 to the reg offset, | ||
192 | * thus skipping the size mask area. | ||
193 | * In the BAR probing case, we want to access the size mask for | ||
194 | * the BAR, so we subtract 0x10 (the config header offset for | ||
195 | * BAR0), and don't skip the size mask area. | ||
196 | */ | ||
197 | |||
198 | addr = (uint32_t)hdr + reg + (bar_probing ? -0x10 : 0x20); | ||
199 | |||
200 | bar_probing = 0; | ||
201 | return (uint32_t *)addr; | ||
202 | } | ||
203 | |||
204 | static int pci_olpc_read(unsigned int seg, unsigned int bus, | ||
205 | unsigned int devfn, int reg, int len, uint32_t *value) | ||
206 | { | ||
207 | uint32_t *addr; | ||
208 | |||
209 | /* Use the hardware mechanism for non-simulated devices */ | ||
210 | if (!is_simulated(bus, devfn)) | ||
211 | return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); | ||
212 | |||
213 | /* | ||
214 | * No device has config registers past 0x70, so we save table space | ||
215 | * by not storing entries for the nonexistent registers | ||
216 | */ | ||
217 | if (reg >= 0x70) | ||
218 | addr = &zero_loc; | ||
219 | else { | ||
220 | switch (devfn) { | ||
221 | case 0x8: | ||
222 | addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg); | ||
223 | break; | ||
224 | case 0x9: | ||
225 | addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg); | ||
226 | break; | ||
227 | case 0xa: | ||
228 | addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc; | ||
229 | break; | ||
230 | case 0x78: | ||
231 | addr = hdr_addr(isa_hdr, reg); | ||
232 | break; | ||
233 | case 0x7b: | ||
234 | addr = hdr_addr(ac97_hdr, reg); | ||
235 | break; | ||
236 | case 0x7c: | ||
237 | addr = hdr_addr(ohci_hdr, reg); | ||
238 | break; | ||
239 | case 0x7d: | ||
240 | addr = hdr_addr(ehci_hdr, reg); | ||
241 | break; | ||
242 | default: | ||
243 | addr = &ff_loc; | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | switch (len) { | ||
248 | case 1: | ||
249 | *value = *(uint8_t *)addr; | ||
250 | break; | ||
251 | case 2: | ||
252 | *value = *(uint16_t *)addr; | ||
253 | break; | ||
254 | case 4: | ||
255 | *value = *addr; | ||
256 | break; | ||
257 | default: | ||
258 | BUG(); | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int pci_olpc_write(unsigned int seg, unsigned int bus, | ||
265 | unsigned int devfn, int reg, int len, uint32_t value) | ||
266 | { | ||
267 | /* Use the hardware mechanism for non-simulated devices */ | ||
268 | if (!is_simulated(bus, devfn)) | ||
269 | return pci_direct_conf1.write(seg, bus, devfn, reg, len, value); | ||
270 | |||
271 | /* XXX we may want to extend this to simulate EHCI power management */ | ||
272 | |||
273 | /* | ||
274 | * Mostly we just discard writes, but if the write is a size probe | ||
275 | * (i.e. writing ~0 to a BAR), we remember it and arrange to return | ||
276 | * the appropriate size mask on the next read. This is cheating | ||
277 | * to some extent, because it depends on the fact that the next | ||
278 | * access after such a write will always be a read to the same BAR. | ||
279 | */ | ||
280 | |||
281 | if ((reg >= 0x10) && (reg < 0x2c)) { | ||
282 | /* write is to a BAR */ | ||
283 | if (value == ~0) | ||
284 | bar_probing = 1; | ||
285 | } else { | ||
286 | /* | ||
287 | * No warning on writes to ROM BAR, CMD, LATENCY_TIMER, | ||
288 | * CACHE_LINE_SIZE, or PM registers. | ||
289 | */ | ||
290 | if ((reg != PCI_ROM_ADDRESS) && (reg != PCI_COMMAND_MASTER) && | ||
291 | (reg != PCI_LATENCY_TIMER) && | ||
292 | (reg != PCI_CACHE_LINE_SIZE) && (reg != 0x44)) | ||
293 | printk(KERN_WARNING "OLPC PCI: Config write to devfn" | ||
294 | " %x reg %x value %x\n", devfn, reg, value); | ||
295 | } | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static struct pci_raw_ops pci_olpc_conf = { | ||
301 | .read = pci_olpc_read, | ||
302 | .write = pci_olpc_write, | ||
303 | }; | ||
304 | |||
305 | void __init pci_olpc_init(void) | ||
306 | { | ||
307 | if (!machine_is_olpc() || olpc_has_vsa()) | ||
308 | return; | ||
309 | |||
310 | printk(KERN_INFO "PCI: Using configuration type OLPC\n"); | ||
311 | raw_pci_ops = &pci_olpc_conf; | ||
312 | is_lx = is_geode_lx(); | ||
313 | } | ||
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 8ef86b5c37c8..c58805a92db5 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h | |||
@@ -98,6 +98,7 @@ extern struct pci_raw_ops pci_direct_conf1; | |||
98 | extern int pci_direct_probe(void); | 98 | extern int pci_direct_probe(void); |
99 | extern void pci_direct_init(int type); | 99 | extern void pci_direct_init(int type); |
100 | extern void pci_pcbios_init(void); | 100 | extern void pci_pcbios_init(void); |
101 | extern void pci_olpc_init(void); | ||
101 | 102 | ||
102 | /* pci-mmconfig.c */ | 103 | /* pci-mmconfig.c */ |
103 | 104 | ||
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S index 4b1620a1529e..1d3aa6b87181 100644 --- a/arch/x86/vdso/vdso.S +++ b/arch/x86/vdso/vdso.S | |||
@@ -1,2 +1,10 @@ | |||
1 | .section ".vdso","a" | 1 | #include <linux/init.h> |
2 | |||
3 | __INITDATA | ||
4 | |||
5 | .globl vdso_start, vdso_end | ||
6 | vdso_start: | ||
2 | .incbin "arch/x86/vdso/vdso.so" | 7 | .incbin "arch/x86/vdso/vdso.so" |
8 | vdso_end: | ||
9 | |||
10 | __FINIT | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 6cbcf65609ad..126766d43aea 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -387,7 +387,7 @@ static void xen_do_pin(unsigned level, unsigned long pfn) | |||
387 | 387 | ||
388 | static int pin_page(struct page *page, enum pt_level level) | 388 | static int pin_page(struct page *page, enum pt_level level) |
389 | { | 389 | { |
390 | unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags); | 390 | unsigned pgfl = TestSetPagePinned(page); |
391 | int flush; | 391 | int flush; |
392 | 392 | ||
393 | if (pgfl) | 393 | if (pgfl) |
@@ -468,7 +468,7 @@ void __init xen_mark_init_mm_pinned(void) | |||
468 | 468 | ||
469 | static int unpin_page(struct page *page, enum pt_level level) | 469 | static int unpin_page(struct page *page, enum pt_level level) |
470 | { | 470 | { |
471 | unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags); | 471 | unsigned pgfl = TestClearPagePinned(page); |
472 | 472 | ||
473 | if (pgfl && !PageHighMem(page)) { | 473 | if (pgfl && !PageHighMem(page)) { |
474 | void *pt = lowmem_page_address(page); | 474 | void *pt = lowmem_page_address(page); |
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index ef63adadf7f4..070ff8af3a21 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c | |||
@@ -19,12 +19,11 @@ | |||
19 | #include <linux/thread_info.h> | 19 | #include <linux/thread_info.h> |
20 | #include <linux/ptrace.h> | 20 | #include <linux/ptrace.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <linux/kbuild.h> | ||
22 | 23 | ||
23 | #include <asm/ptrace.h> | 24 | #include <asm/ptrace.h> |
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | 26 | ||
26 | #define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
27 | |||
28 | int main(void) | 27 | int main(void) |
29 | { | 28 | { |
30 | /* struct pt_regs */ | 29 | /* struct pt_regs */ |