163e158a0SMatt Evans /*
263e158a0SMatt Evans * PPC64 (SPAPR) platform support
363e158a0SMatt Evans *
463e158a0SMatt Evans * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
563e158a0SMatt Evans *
6d391177aSMatt Evans * Portions of FDT setup borrowed from QEMU, copyright 2010 David Gibson, IBM
7d391177aSMatt Evans * Corporation.
8d391177aSMatt Evans *
963e158a0SMatt Evans * This program is free software; you can redistribute it and/or modify it
1063e158a0SMatt Evans * under the terms of the GNU General Public License version 2 as published
1163e158a0SMatt Evans * by the Free Software Foundation.
1263e158a0SMatt Evans */
1363e158a0SMatt Evans
141299331aSWill Deacon #include "kvm/fdt.h"
1563e158a0SMatt Evans #include "kvm/kvm.h"
1663e158a0SMatt Evans #include "kvm/util.h"
17d391177aSMatt Evans #include "cpu_info.h"
1863e158a0SMatt Evans
19be76823fSMatt Evans #include "spapr.h"
207295767dSMatt Evans #include "spapr_hvcons.h"
21c481cfd5SMatt Evans #include "spapr_pci.h"
22be76823fSMatt Evans
2363e158a0SMatt Evans #include <linux/kvm.h>
2463e158a0SMatt Evans
2563e158a0SMatt Evans #include <sys/types.h>
2663e158a0SMatt Evans #include <sys/ioctl.h>
2763e158a0SMatt Evans #include <sys/mman.h>
2863e158a0SMatt Evans #include <stdbool.h>
2963e158a0SMatt Evans #include <stdlib.h>
3063e158a0SMatt Evans #include <string.h>
3163e158a0SMatt Evans #include <unistd.h>
3263e158a0SMatt Evans #include <stdio.h>
3363e158a0SMatt Evans #include <fcntl.h>
3463e158a0SMatt Evans #include <asm/unistd.h>
3563e158a0SMatt Evans #include <errno.h>
3663e158a0SMatt Evans
3763e158a0SMatt Evans #include <linux/byteorder.h>
38d391177aSMatt Evans
39d391177aSMatt Evans #define HPT_ORDER 24
4063e158a0SMatt Evans
4163e158a0SMatt Evans #define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/"
4263e158a0SMatt Evans
4363e158a0SMatt Evans static char kern_cmdline[2048];
4463e158a0SMatt Evans
4563e158a0SMatt Evans struct kvm_ext kvm_req_ext[] = {
46f17e5a37SMatt Evans { DEFINE_KVM_EXT(KVM_CAP_PPC_UNSET_IRQ) },
47f17e5a37SMatt Evans { DEFINE_KVM_EXT(KVM_CAP_PPC_IRQ_LEVEL) },
4863e158a0SMatt Evans { 0, 0 }
4963e158a0SMatt Evans };
5063e158a0SMatt Evans
kvm__arch_default_ram_address(void)51*3f7e48f6SAlexandru Elisei u64 kvm__arch_default_ram_address(void)
52*3f7e48f6SAlexandru Elisei {
53*3f7e48f6SAlexandru Elisei return 0;
54*3f7e48f6SAlexandru Elisei }
55*3f7e48f6SAlexandru Elisei
kvm__arch_validate_cfg(struct kvm * kvm)56abe3f28aSAlexandru Elisei void kvm__arch_validate_cfg(struct kvm *kvm)
57abe3f28aSAlexandru Elisei {
58abe3f28aSAlexandru Elisei }
59abe3f28aSAlexandru Elisei
mfpvr(void)60d391177aSMatt Evans static uint32_t mfpvr(void)
61d391177aSMatt Evans {
62d391177aSMatt Evans uint32_t r;
63d391177aSMatt Evans asm volatile ("mfpvr %0" : "=r"(r));
64d391177aSMatt Evans return r;
65d391177aSMatt Evans }
66d391177aSMatt Evans
kvm__arch_cpu_supports_vm(void)6763e158a0SMatt Evans bool kvm__arch_cpu_supports_vm(void)
6863e158a0SMatt Evans {
6963e158a0SMatt Evans return true;
7063e158a0SMatt Evans }
7163e158a0SMatt Evans
kvm__init_ram(struct kvm * kvm)7263e158a0SMatt Evans void kvm__init_ram(struct kvm *kvm)
7363e158a0SMatt Evans {
7463e158a0SMatt Evans u64 phys_start, phys_size;
7563e158a0SMatt Evans void *host_mem;
7663e158a0SMatt Evans
7763e158a0SMatt Evans phys_start = 0;
7863e158a0SMatt Evans phys_size = kvm->ram_size;
7963e158a0SMatt Evans host_mem = kvm->ram_start;
8063e158a0SMatt Evans
8163e158a0SMatt Evans /*
8263e158a0SMatt Evans * We put MMIO at PPC_MMIO_START, high up. Make sure that this doesn't
8363e158a0SMatt Evans * crash into the end of RAM -- on PPC64 at least, this is so high
8463e158a0SMatt Evans * (63TB!) that this is unlikely.
8563e158a0SMatt Evans */
8663e158a0SMatt Evans if (phys_size >= PPC_MMIO_START)
8763e158a0SMatt Evans die("Too much memory (%lld, what a nice problem): "
8863e158a0SMatt Evans "overlaps MMIO!\n",
8963e158a0SMatt Evans phys_size);
9063e158a0SMatt Evans
918f46c736SJean-Philippe Brucker kvm__register_ram(kvm, phys_start, phys_size, host_mem);
9263e158a0SMatt Evans }
9363e158a0SMatt Evans
kvm__arch_set_cmdline(char * cmdline,bool video)9463e158a0SMatt Evans void kvm__arch_set_cmdline(char *cmdline, bool video)
9563e158a0SMatt Evans {
9663e158a0SMatt Evans /* We don't need anything unusual in here. */
9763e158a0SMatt Evans }
9863e158a0SMatt Evans
9963e158a0SMatt Evans /* Architecture-specific KVM init */
kvm__arch_init(struct kvm * kvm)1005e9c654eSJulien Grall void kvm__arch_init(struct kvm *kvm)
10163e158a0SMatt Evans {
1025e9c654eSJulien Grall const char *hugetlbfs_path = kvm->cfg.hugetlbfs_path;
10363e158a0SMatt Evans int cap_ppc_rma;
104df129a0aSMatt Evans unsigned long hpt;
10563e158a0SMatt Evans
1065e9c654eSJulien Grall kvm->ram_size = kvm->cfg.ram_size;
10763e158a0SMatt Evans
1088cd50b93SMichael Ellerman /* Map "default" hugetblfs path to the standard 16M mount point */
1098cd50b93SMichael Ellerman if (hugetlbfs_path && !strcmp(hugetlbfs_path, "default"))
11063e158a0SMatt Evans hugetlbfs_path = HUGETLBFS_PATH;
1118cd50b93SMichael Ellerman
1123ebd8e0bSMichael Ellerman kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, kvm->ram_size);
1138cd50b93SMichael Ellerman
11463e158a0SMatt Evans if (kvm->ram_start == MAP_FAILED)
11563e158a0SMatt Evans die("Couldn't map %lld bytes for RAM (%d)\n",
11663e158a0SMatt Evans kvm->ram_size, errno);
11763e158a0SMatt Evans
11863e158a0SMatt Evans /* FDT goes at top of memory, RTAS just below */
11942ac24f9SSasha Levin kvm->arch.fdt_gra = kvm->ram_size - FDT_MAX_SIZE;
12063e158a0SMatt Evans /* FIXME: Not all PPC systems have RTAS */
12142ac24f9SSasha Levin kvm->arch.rtas_gra = kvm->arch.fdt_gra - RTAS_MAX_SIZE;
12263e158a0SMatt Evans madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
12363e158a0SMatt Evans
124df129a0aSMatt Evans /* FIXME: SPAPR-PR specific; allocate a guest HPT. */
125df129a0aSMatt Evans if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER)))
126df129a0aSMatt Evans die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER));
127df129a0aSMatt Evans
12842ac24f9SSasha Levin kvm->arch.sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18);
129df129a0aSMatt Evans
13042ac24f9SSasha Levin kvm->arch.pvr = mfpvr();
131d391177aSMatt Evans
13263e158a0SMatt Evans /* FIXME: This is book3s-specific */
13363e158a0SMatt Evans cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA);
13463e158a0SMatt Evans if (cap_ppc_rma == 2)
13563e158a0SMatt Evans die("Need contiguous RMA allocation on this hardware, "
13663e158a0SMatt Evans "which is not yet supported.");
137be76823fSMatt Evans
138be76823fSMatt Evans /* Do these before FDT setup, IRQ setup, etc. */
139be76823fSMatt Evans /* FIXME: SPAPR-specific */
140be76823fSMatt Evans hypercall_init();
141be76823fSMatt Evans register_core_rtas();
1427295767dSMatt Evans /* Now that hypercalls are initialised, register a couple for the console: */
1437295767dSMatt Evans spapr_hvcons_init();
144c481cfd5SMatt Evans spapr_create_phb(kvm, "pci", SPAPR_PCI_BUID,
145c481cfd5SMatt Evans SPAPR_PCI_MEM_WIN_ADDR,
146c481cfd5SMatt Evans SPAPR_PCI_MEM_WIN_SIZE,
147c481cfd5SMatt Evans SPAPR_PCI_IO_WIN_ADDR,
148c481cfd5SMatt Evans SPAPR_PCI_IO_WIN_SIZE);
14963e158a0SMatt Evans }
15063e158a0SMatt Evans
kvm__arch_delete_ram(struct kvm * kvm)151e56e2de7SLai Jiangshan void kvm__arch_delete_ram(struct kvm *kvm)
152e56e2de7SLai Jiangshan {
153e56e2de7SLai Jiangshan munmap(kvm->ram_start, kvm->ram_size);
154e56e2de7SLai Jiangshan }
155e56e2de7SLai Jiangshan
kvm__irq_trigger(struct kvm * kvm,int irq)15663e158a0SMatt Evans void kvm__irq_trigger(struct kvm *kvm, int irq)
15763e158a0SMatt Evans {
15863e158a0SMatt Evans kvm__irq_line(kvm, irq, 1);
15963e158a0SMatt Evans kvm__irq_line(kvm, irq, 0);
16063e158a0SMatt Evans }
16163e158a0SMatt Evans
kvm__arch_read_term(struct kvm * kvm)16212c406a8SJonathan Austin void kvm__arch_read_term(struct kvm *kvm)
1637295767dSMatt Evans {
1647295767dSMatt Evans /* FIXME: Should register callbacks to platform-specific polls */
1657295767dSMatt Evans spapr_hvcons_poll(kvm);
1667295767dSMatt Evans }
1677295767dSMatt Evans
kvm__arch_load_kernel_image(struct kvm * kvm,int fd_kernel,int fd_initrd,const char * kernel_cmdline)168004f7684SAndre Przywara bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
169004f7684SAndre Przywara const char *kernel_cmdline)
17063e158a0SMatt Evans {
17163e158a0SMatt Evans void *p;
17263e158a0SMatt Evans void *k_start;
173d0fb441dSAndre Przywara ssize_t filesize;
17463e158a0SMatt Evans
17563e158a0SMatt Evans p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR);
17663e158a0SMatt Evans
177d0fb441dSAndre Przywara filesize = read_file(fd_kernel, p, INITRD_LOAD_ADDR - KERNEL_LOAD_ADDR);
178d0fb441dSAndre Przywara if (filesize < 0) {
179d0fb441dSAndre Przywara if (errno == ENOMEM)
180d0fb441dSAndre Przywara die("Kernel overlaps initrd!");
18163e158a0SMatt Evans
182d0fb441dSAndre Przywara die_perror("kernel read");
183d0fb441dSAndre Przywara }
184d0fb441dSAndre Przywara pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR,
185d0fb441dSAndre Przywara filesize);
18663e158a0SMatt Evans if (fd_initrd != -1) {
18763e158a0SMatt Evans if (p-k_start > INITRD_LOAD_ADDR)
18863e158a0SMatt Evans die("Kernel overlaps initrd!");
18963e158a0SMatt Evans
19063e158a0SMatt Evans /* Round up kernel size to 8byte alignment, and load initrd right after. */
191d0fb441dSAndre Przywara p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR);
19263e158a0SMatt Evans
193d0fb441dSAndre Przywara filesize = read_file(fd_initrd, p,
194d0fb441dSAndre Przywara (kvm->ram_start + kvm->ram_size) - p);
195d0fb441dSAndre Przywara if (filesize < 0) {
196d0fb441dSAndre Przywara if (errno == ENOMEM)
19763e158a0SMatt Evans die("initrd too big to contain in guest RAM.\n");
198d0fb441dSAndre Przywara die_perror("initrd read");
199d0fb441dSAndre Przywara }
20063e158a0SMatt Evans
20163e158a0SMatt Evans pr_info("Loaded initrd to 0x%x (%ld bytes)",
202d0fb441dSAndre Przywara INITRD_LOAD_ADDR, filesize);
20342ac24f9SSasha Levin kvm->arch.initrd_gra = INITRD_LOAD_ADDR;
204d0fb441dSAndre Przywara kvm->arch.initrd_size = filesize;
20563e158a0SMatt Evans } else {
20642ac24f9SSasha Levin kvm->arch.initrd_size = 0;
20763e158a0SMatt Evans }
20863e158a0SMatt Evans strncpy(kern_cmdline, kernel_cmdline, 2048);
20963e158a0SMatt Evans kern_cmdline[2047] = '\0';
21063e158a0SMatt Evans
21163e158a0SMatt Evans return true;
21263e158a0SMatt Evans }
21363e158a0SMatt Evans
214de494ec5SMichael Ellerman struct fdt_prop {
215de494ec5SMichael Ellerman void *value;
216de494ec5SMichael Ellerman int size;
217de494ec5SMichael Ellerman };
218de494ec5SMichael Ellerman
generate_segment_page_sizes(struct kvm_ppc_smmu_info * info,struct fdt_prop * prop)219de494ec5SMichael Ellerman static void generate_segment_page_sizes(struct kvm_ppc_smmu_info *info, struct fdt_prop *prop)
220de494ec5SMichael Ellerman {
221de494ec5SMichael Ellerman struct kvm_ppc_one_seg_page_size *sps;
222de494ec5SMichael Ellerman int i, j, size;
223de494ec5SMichael Ellerman u32 *p;
224de494ec5SMichael Ellerman
225de494ec5SMichael Ellerman for (size = 0, i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
226de494ec5SMichael Ellerman sps = &info->sps[i];
227de494ec5SMichael Ellerman
228de494ec5SMichael Ellerman if (sps->page_shift == 0)
229de494ec5SMichael Ellerman break;
230de494ec5SMichael Ellerman
231de494ec5SMichael Ellerman /* page shift, slb enc & count */
232de494ec5SMichael Ellerman size += 3;
233de494ec5SMichael Ellerman
234de494ec5SMichael Ellerman for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
235de494ec5SMichael Ellerman if (info->sps[i].enc[j].page_shift == 0)
236de494ec5SMichael Ellerman break;
237de494ec5SMichael Ellerman
238de494ec5SMichael Ellerman /* page shift & pte enc */
239de494ec5SMichael Ellerman size += 2;
240de494ec5SMichael Ellerman }
241de494ec5SMichael Ellerman }
242de494ec5SMichael Ellerman
243de494ec5SMichael Ellerman if (!size) {
244de494ec5SMichael Ellerman prop->value = NULL;
245de494ec5SMichael Ellerman prop->size = 0;
246de494ec5SMichael Ellerman return;
247de494ec5SMichael Ellerman }
248de494ec5SMichael Ellerman
249de494ec5SMichael Ellerman /* Convert size to bytes */
250de494ec5SMichael Ellerman prop->size = size * sizeof(u32);
251de494ec5SMichael Ellerman
252de494ec5SMichael Ellerman prop->value = malloc(prop->size);
253de494ec5SMichael Ellerman if (!prop->value)
254de494ec5SMichael Ellerman die_perror("malloc failed");
255de494ec5SMichael Ellerman
256de494ec5SMichael Ellerman p = (u32 *)prop->value;
257de494ec5SMichael Ellerman for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
258de494ec5SMichael Ellerman sps = &info->sps[i];
259de494ec5SMichael Ellerman
260de494ec5SMichael Ellerman if (sps->page_shift == 0)
261de494ec5SMichael Ellerman break;
262de494ec5SMichael Ellerman
26362a15bd1SBalbir Singh *p++ = cpu_to_be32(sps->page_shift);
26462a15bd1SBalbir Singh *p++ = cpu_to_be32(sps->slb_enc);
265de494ec5SMichael Ellerman
266de494ec5SMichael Ellerman for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++)
267de494ec5SMichael Ellerman if (!info->sps[i].enc[j].page_shift)
268de494ec5SMichael Ellerman break;
269de494ec5SMichael Ellerman
27062a15bd1SBalbir Singh *p++ = cpu_to_be32(j); /* count of enc */
271de494ec5SMichael Ellerman
272de494ec5SMichael Ellerman for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
273de494ec5SMichael Ellerman if (!info->sps[i].enc[j].page_shift)
274de494ec5SMichael Ellerman break;
275de494ec5SMichael Ellerman
27662a15bd1SBalbir Singh *p++ = cpu_to_be32(info->sps[i].enc[j].page_shift);
27762a15bd1SBalbir Singh *p++ = cpu_to_be32(info->sps[i].enc[j].pte_enc);
278de494ec5SMichael Ellerman }
279de494ec5SMichael Ellerman }
280de494ec5SMichael Ellerman }
281de494ec5SMichael Ellerman
282d391177aSMatt Evans #define SMT_THREADS 4
283d391177aSMatt Evans
284d391177aSMatt Evans /*
285d391177aSMatt Evans * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy,
286d391177aSMatt Evans * and whilst most PPC targets will require CPU/memory nodes, others like RTAS
287d391177aSMatt Evans * should eventually be added separately.
288d391177aSMatt Evans */
setup_fdt(struct kvm * kvm)289fc935584SMichael Ellerman static int setup_fdt(struct kvm *kvm)
29063e158a0SMatt Evans {
291d391177aSMatt Evans uint64_t mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) };
292d391177aSMatt Evans int smp_cpus = kvm->nrcpus;
293f17e5a37SMatt Evans uint32_t int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
294d391177aSMatt Evans char hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
295d391177aSMatt Evans "hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
296015785d4SBalbir Singh "hcall-splpar\0hcall-bulk\0hcall-set-mode";
297d391177aSMatt Evans int i, j;
298d391177aSMatt Evans char cpu_name[30];
299d391177aSMatt Evans u8 staging_fdt[FDT_MAX_SIZE];
3004a75c603SMichael Ellerman struct cpu_info *cpu_info = find_cpu_info(kvm);
301de494ec5SMichael Ellerman struct fdt_prop segment_page_sizes;
30262a15bd1SBalbir Singh u32 segment_sizes_1T[] = {cpu_to_be32(0x1c), cpu_to_be32(0x28), 0xffffffff, 0xffffffff};
30363e158a0SMatt Evans
30442ac24f9SSasha Levin /* Generate an appropriate DT at kvm->arch.fdt_gra */
30542ac24f9SSasha Levin void *fdt_dest = guest_flat_to_host(kvm, kvm->arch.fdt_gra);
306d391177aSMatt Evans void *fdt = staging_fdt;
307d391177aSMatt Evans
308d391177aSMatt Evans _FDT(fdt_create(fdt, FDT_MAX_SIZE));
309d391177aSMatt Evans _FDT(fdt_finish_reservemap(fdt));
310d391177aSMatt Evans
311d391177aSMatt Evans _FDT(fdt_begin_node(fdt, ""));
312d391177aSMatt Evans
313d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "chrp"));
314d391177aSMatt Evans _FDT(fdt_property_string(fdt, "model", "IBM pSeries (kvmtool)"));
315d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
316d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
317d391177aSMatt Evans
318be76823fSMatt Evans /* RTAS */
319be76823fSMatt Evans _FDT(fdt_begin_node(fdt, "rtas"));
320be76823fSMatt Evans /* This is what the kernel uses to switch 'We're an LPAR'! */
321be76823fSMatt Evans _FDT(fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop_kvm,
322be76823fSMatt Evans sizeof(hypertas_prop_kvm)));
32342ac24f9SSasha Levin _FDT(fdt_property_cell(fdt, "linux,rtas-base", kvm->arch.rtas_gra));
32442ac24f9SSasha Levin _FDT(fdt_property_cell(fdt, "linux,rtas-entry", kvm->arch.rtas_gra));
32542ac24f9SSasha Levin _FDT(fdt_property_cell(fdt, "rtas-size", kvm->arch.rtas_size));
326be76823fSMatt Evans /* Now add properties for all RTAS tokens: */
327be76823fSMatt Evans if (spapr_rtas_fdt_setup(kvm, fdt))
328be76823fSMatt Evans die("Couldn't create RTAS FDT properties\n");
329be76823fSMatt Evans
330be76823fSMatt Evans _FDT(fdt_end_node(fdt));
331be76823fSMatt Evans
332d391177aSMatt Evans /* /chosen */
333d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "chosen"));
334d391177aSMatt Evans /* cmdline */
335d391177aSMatt Evans _FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
336d391177aSMatt Evans /* Initrd */
33742ac24f9SSasha Levin if (kvm->arch.initrd_size != 0) {
33842ac24f9SSasha Levin uint32_t ird_st_prop = cpu_to_be32(kvm->arch.initrd_gra);
33942ac24f9SSasha Levin uint32_t ird_end_prop = cpu_to_be32(kvm->arch.initrd_gra +
34042ac24f9SSasha Levin kvm->arch.initrd_size);
341d391177aSMatt Evans _FDT(fdt_property(fdt, "linux,initrd-start",
342d391177aSMatt Evans &ird_st_prop, sizeof(ird_st_prop)));
343d391177aSMatt Evans _FDT(fdt_property(fdt, "linux,initrd-end",
344d391177aSMatt Evans &ird_end_prop, sizeof(ird_end_prop)));
345d391177aSMatt Evans }
3467295767dSMatt Evans
3477295767dSMatt Evans /*
3487295767dSMatt Evans * stdout-path: This is assuming we're using the HV console. Also, the
3497295767dSMatt Evans * address is hardwired until we do a VIO bus.
3507295767dSMatt Evans */
3517295767dSMatt Evans _FDT(fdt_property_string(fdt, "linux,stdout-path",
3527295767dSMatt Evans "/vdevice/vty@30000000"));
353d391177aSMatt Evans _FDT(fdt_end_node(fdt));
354d391177aSMatt Evans
355d391177aSMatt Evans /*
356d391177aSMatt Evans * Memory: We don't alloc. a separate RMA yet. If we ever need to
357d391177aSMatt Evans * (CAP_PPC_RMA == 2) then have one memory node for 0->RMAsize, and
358d391177aSMatt Evans * another RMAsize->endOfMem.
359d391177aSMatt Evans */
360d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "memory@0"));
361d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "memory"));
362d391177aSMatt Evans _FDT(fdt_property(fdt, "reg", mem_reg_property,
363d391177aSMatt Evans sizeof(mem_reg_property)));
364d391177aSMatt Evans _FDT(fdt_end_node(fdt));
365d391177aSMatt Evans
366de494ec5SMichael Ellerman generate_segment_page_sizes(&cpu_info->mmu_info, &segment_page_sizes);
367de494ec5SMichael Ellerman
368d391177aSMatt Evans /* CPUs */
369d391177aSMatt Evans _FDT(fdt_begin_node(fdt, "cpus"));
370d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
371d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
372d391177aSMatt Evans
373d391177aSMatt Evans for (i = 0; i < smp_cpus; i += SMT_THREADS) {
37462a15bd1SBalbir Singh int32_t pft_size_prop[] = { 0, cpu_to_be32(HPT_ORDER) };
375d391177aSMatt Evans uint32_t servers_prop[SMT_THREADS];
376d391177aSMatt Evans uint32_t gservers_prop[SMT_THREADS * 2];
377d391177aSMatt Evans int threads = (smp_cpus - i) >= SMT_THREADS ? SMT_THREADS :
378d391177aSMatt Evans smp_cpus - i;
379d391177aSMatt Evans
380d391177aSMatt Evans sprintf(cpu_name, "PowerPC,%s@%d", cpu_info->name, i);
381d391177aSMatt Evans _FDT(fdt_begin_node(fdt, cpu_name));
382d391177aSMatt Evans sprintf(cpu_name, "PowerPC,%s", cpu_info->name);
383d391177aSMatt Evans _FDT(fdt_property_string(fdt, "name", cpu_name));
384d391177aSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "cpu"));
385d391177aSMatt Evans
386d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "reg", i));
38742ac24f9SSasha Levin _FDT(fdt_property_cell(fdt, "cpu-version", kvm->arch.pvr));
388d391177aSMatt Evans
389d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "dcache-block-size", cpu_info->d_bsize));
390d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "icache-block-size", cpu_info->i_bsize));
391d391177aSMatt Evans
392bf4bc902SMichael Ellerman if (cpu_info->tb_freq)
393d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "timebase-frequency", cpu_info->tb_freq));
394bf4bc902SMichael Ellerman
395d391177aSMatt Evans /* Lies, but safeish lies! */
396d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "clock-frequency", 0xddbab200));
397d391177aSMatt Evans
398cb90966cSMichael Ellerman if (cpu_info->mmu_info.slb_size)
399cb90966cSMichael Ellerman _FDT(fdt_property_cell(fdt, "ibm,slb-size", cpu_info->mmu_info.slb_size));
400cb90966cSMichael Ellerman
401d391177aSMatt Evans /*
402d391177aSMatt Evans * HPT size is hardwired; KVM currently fixes it at 16MB but the
403d391177aSMatt Evans * moment that changes we'll need to read it out of the kernel.
404d391177aSMatt Evans */
405d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,pft-size", pft_size_prop,
406d391177aSMatt Evans sizeof(pft_size_prop)));
407d391177aSMatt Evans
408d391177aSMatt Evans _FDT(fdt_property_string(fdt, "status", "okay"));
409d391177aSMatt Evans _FDT(fdt_property(fdt, "64-bit", NULL, 0));
410d391177aSMatt Evans /* A server for each thread in this core */
411d391177aSMatt Evans for (j = 0; j < SMT_THREADS; j++) {
412d391177aSMatt Evans servers_prop[j] = cpu_to_be32(i+j);
413d391177aSMatt Evans /*
414d391177aSMatt Evans * Hack borrowed from QEMU, direct the group queues back
415d391177aSMatt Evans * to cpu 0:
416d391177aSMatt Evans */
417d391177aSMatt Evans gservers_prop[j*2] = cpu_to_be32(i+j);
418d391177aSMatt Evans gservers_prop[j*2 + 1] = 0;
419d391177aSMatt Evans }
420d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,ppc-interrupt-server#s",
421d391177aSMatt Evans servers_prop, threads * sizeof(uint32_t)));
422d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
423d391177aSMatt Evans gservers_prop,
424d391177aSMatt Evans threads * 2 * sizeof(uint32_t)));
425de494ec5SMichael Ellerman
426de494ec5SMichael Ellerman if (segment_page_sizes.value)
427d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,segment-page-sizes",
428de494ec5SMichael Ellerman segment_page_sizes.value,
429de494ec5SMichael Ellerman segment_page_sizes.size));
430de494ec5SMichael Ellerman
43138baf777SMichael Ellerman if (cpu_info->mmu_info.flags & KVM_PPC_1T_SEGMENTS)
432d391177aSMatt Evans _FDT(fdt_property(fdt, "ibm,processor-segment-sizes",
43338baf777SMichael Ellerman segment_sizes_1T, sizeof(segment_sizes_1T)));
43438baf777SMichael Ellerman
435d391177aSMatt Evans /* VSX / DFP options: */
436d391177aSMatt Evans if (cpu_info->flags & CPUINFO_FLAG_VMX)
437d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "ibm,vmx",
438d391177aSMatt Evans (cpu_info->flags &
439d391177aSMatt Evans CPUINFO_FLAG_VSX) ? 2 : 1));
440d391177aSMatt Evans if (cpu_info->flags & CPUINFO_FLAG_DFP)
441d391177aSMatt Evans _FDT(fdt_property_cell(fdt, "ibm,dfp", 0x1));
442d391177aSMatt Evans _FDT(fdt_end_node(fdt));
443d391177aSMatt Evans }
444d391177aSMatt Evans _FDT(fdt_end_node(fdt));
445d391177aSMatt Evans
446f17e5a37SMatt Evans /* IRQ controller */
447f17e5a37SMatt Evans _FDT(fdt_begin_node(fdt, "interrupt-controller@0"));
448f17e5a37SMatt Evans
449f17e5a37SMatt Evans _FDT(fdt_property_string(fdt, "device_type",
450f17e5a37SMatt Evans "PowerPC-External-Interrupt-Presentation"));
451f17e5a37SMatt Evans _FDT(fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"));
452f17e5a37SMatt Evans _FDT(fdt_property_cell(fdt, "reg", 0));
453f17e5a37SMatt Evans _FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
454f17e5a37SMatt Evans _FDT(fdt_property(fdt, "ibm,interrupt-server-ranges",
455f17e5a37SMatt Evans int_server_ranges_prop,
456f17e5a37SMatt Evans sizeof(int_server_ranges_prop)));
457f17e5a37SMatt Evans _FDT(fdt_property_cell(fdt, "#interrupt-cells", 2));
458f17e5a37SMatt Evans _FDT(fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP));
459f17e5a37SMatt Evans _FDT(fdt_property_cell(fdt, "phandle", PHANDLE_XICP));
460f17e5a37SMatt Evans _FDT(fdt_end_node(fdt));
461f17e5a37SMatt Evans
4627295767dSMatt Evans /*
4637295767dSMatt Evans * VIO: See comment in linux,stdout-path; we don't yet represent a VIO
4647295767dSMatt Evans * bus/address allocation so addresses are hardwired here.
4657295767dSMatt Evans */
4667295767dSMatt Evans _FDT(fdt_begin_node(fdt, "vdevice"));
4677295767dSMatt Evans _FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
4687295767dSMatt Evans _FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
4697295767dSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "vdevice"));
4707295767dSMatt Evans _FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice"));
4717295767dSMatt Evans _FDT(fdt_begin_node(fdt, "vty@30000000"));
4727295767dSMatt Evans _FDT(fdt_property_string(fdt, "name", "vty"));
4737295767dSMatt Evans _FDT(fdt_property_string(fdt, "device_type", "serial"));
4747295767dSMatt Evans _FDT(fdt_property_string(fdt, "compatible", "hvterm1"));
4757295767dSMatt Evans _FDT(fdt_property_cell(fdt, "reg", 0x30000000));
4767295767dSMatt Evans _FDT(fdt_end_node(fdt));
4777295767dSMatt Evans _FDT(fdt_end_node(fdt));
4787295767dSMatt Evans
479d391177aSMatt Evans /* Finalise: */
480d391177aSMatt Evans _FDT(fdt_end_node(fdt)); /* Root node */
481d391177aSMatt Evans _FDT(fdt_finish(fdt));
482d391177aSMatt Evans
483d391177aSMatt Evans _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
484c481cfd5SMatt Evans
485c481cfd5SMatt Evans /* PCI */
486c481cfd5SMatt Evans if (spapr_populate_pci_devices(kvm, PHANDLE_XICP, fdt_dest))
487c481cfd5SMatt Evans die("Fail populating PCI device nodes");
488c481cfd5SMatt Evans
48942ac24f9SSasha Levin _FDT(fdt_add_mem_rsv(fdt_dest, kvm->arch.rtas_gra, kvm->arch.rtas_size));
490d391177aSMatt Evans _FDT(fdt_pack(fdt_dest));
491de494ec5SMichael Ellerman
492de494ec5SMichael Ellerman free(segment_page_sizes.value);
493fc935584SMichael Ellerman
494fc935584SMichael Ellerman return 0;
49563e158a0SMatt Evans }
496fc935584SMichael Ellerman firmware_init(setup_fdt);
49763e158a0SMatt Evans
49863e158a0SMatt Evans /**
49963e158a0SMatt Evans * kvm__arch_setup_firmware
50063e158a0SMatt Evans */
kvm__arch_setup_firmware(struct kvm * kvm)501f7f9d02bSCyrill Gorcunov int kvm__arch_setup_firmware(struct kvm *kvm)
50263e158a0SMatt Evans {
503be76823fSMatt Evans /*
504be76823fSMatt Evans * Set up RTAS stub. All it is is a single hypercall:
505be76823fSMatt Evans * 0: 7c 64 1b 78 mr r4,r3
506be76823fSMatt Evans * 4: 3c 60 00 00 lis r3,0
507be76823fSMatt Evans * 8: 60 63 f0 00 ori r3,r3,61440
508be76823fSMatt Evans * c: 44 00 00 22 sc 1
509be76823fSMatt Evans * 10: 4e 80 00 20 blr
510be76823fSMatt Evans */
51142ac24f9SSasha Levin uint32_t *rtas = guest_flat_to_host(kvm, kvm->arch.rtas_gra);
512be76823fSMatt Evans
51362a15bd1SBalbir Singh rtas[0] = cpu_to_be32(0x7c641b78);
51462a15bd1SBalbir Singh rtas[1] = cpu_to_be32(0x3c600000);
51562a15bd1SBalbir Singh rtas[2] = cpu_to_be32(0x6063f000);
51662a15bd1SBalbir Singh rtas[3] = cpu_to_be32(0x44000022);
51762a15bd1SBalbir Singh rtas[4] = cpu_to_be32(0x4e800020);
51842ac24f9SSasha Levin kvm->arch.rtas_size = 20;
519be76823fSMatt Evans
520be76823fSMatt Evans pr_info("Set up %ld bytes of RTAS at 0x%lx\n",
52142ac24f9SSasha Levin kvm->arch.rtas_size, kvm->arch.rtas_gra);
52263e158a0SMatt Evans
52363e158a0SMatt Evans /* Load SLOF */
52463e158a0SMatt Evans
525f7f9d02bSCyrill Gorcunov return 0;
52663e158a0SMatt Evans }
5271add9f73SSasha Levin
kvm__arch_free_firmware(struct kvm * kvm)5281add9f73SSasha Levin int kvm__arch_free_firmware(struct kvm *kvm)
5291add9f73SSasha Levin {
5301add9f73SSasha Levin return 0;
5311add9f73SSasha Levin }
532