]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/kvm/powerpc/cpu_info.c
Merge remote-tracking branch 'signal/for-next'
[karo-tx-linux.git] / tools / kvm / powerpc / cpu_info.c
1 /*
2  * PPC CPU identification
3  *
4  * This is a very simple "host CPU info" struct to get us going.
5  * For the little host information we need, I don't want to grub about
6  * parsing stuff in /proc/device-tree so just match host PVR to differentiate
7  * PPC970 and POWER7 (which is all that's currently supported).
8  *
9  * Qemu does something similar but this is MUCH simpler!
10  *
11  * Copyright 2012 Matt Evans <matt@ozlabs.org>, IBM Corporation.
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License version 2 as published
15  * by the Free Software Foundation.
16  */
17
18 #include <kvm/kvm.h>
19 #include <sys/ioctl.h>
20
21 #include "cpu_info.h"
22 #include "kvm/util.h"
23
24 /* POWER7 */
25
26 static struct cpu_info cpu_power7_info = {
27         .name = "POWER7",
28         .tb_freq = 512000000,
29         .d_bsize = 128,
30         .i_bsize = 128,
31         .flags = CPUINFO_FLAG_DFP | CPUINFO_FLAG_VSX | CPUINFO_FLAG_VMX,
32         .mmu_info = {
33                 .flags = KVM_PPC_PAGE_SIZES_REAL | KVM_PPC_1T_SEGMENTS,
34                 .slb_size = 32,
35         },
36 };
37
38 /* PPC970/G5 */
39
40 static struct cpu_info cpu_970_info = {
41         .name = "G5",
42         .tb_freq = 33333333,
43         .d_bsize = 128,
44         .i_bsize = 128,
45         .flags = CPUINFO_FLAG_VMX,
46 };
47
48 /* This is a default catchall for 'no match' on PVR: */
49 static struct cpu_info cpu_dummy_info = { .name = "unknown" };
50
51 static struct pvr_info host_pvr_info[] = {
52         { 0xffffffff, 0x0f000003, &cpu_power7_info },
53         { 0xffff0000, 0x003f0000, &cpu_power7_info },
54         { 0xffff0000, 0x004a0000, &cpu_power7_info },
55         { 0xffff0000, 0x00390000, &cpu_970_info },
56         { 0xffff0000, 0x003c0000, &cpu_970_info },
57         { 0xffff0000, 0x00440000, &cpu_970_info },
58         { 0xffff0000, 0x00450000, &cpu_970_info },
59 };
60
61 /* If we can't query the kernel for supported page sizes assume 4K and 16M */
62 static struct kvm_ppc_one_seg_page_size fallback_sps[] = {
63         [0] = {
64                 .page_shift = 12,
65                 .slb_enc    = 0,
66                 .enc =  {
67                         [0] = {
68                                 .page_shift = 12,
69                                 .pte_enc    = 0,
70                         },
71                 },
72         },
73         [1] = {
74                 .page_shift = 24,
75                 .slb_enc    = 0x100,
76                 .enc =  {
77                         [0] = {
78                                 .page_shift = 24,
79                                 .pte_enc    = 0,
80                         },
81                 },
82         },
83 };
84
85
86 static void setup_mmu_info(struct kvm *kvm, struct cpu_info *cpu_info)
87 {
88         static struct kvm_ppc_smmu_info *mmu_info;
89         struct kvm_ppc_one_seg_page_size *sps;
90         int i, j, k, valid;
91
92         if (!kvm__supports_extension(kvm, KVM_CAP_PPC_GET_SMMU_INFO)) {
93                 memcpy(&cpu_info->mmu_info.sps, fallback_sps, sizeof(fallback_sps));
94         } else if (ioctl(kvm->vm_fd, KVM_PPC_GET_SMMU_INFO, &cpu_info->mmu_info) < 0) {
95                         die_perror("KVM_PPC_GET_SMMU_INFO failed");
96         }
97
98         mmu_info = &cpu_info->mmu_info;
99
100         if (!(mmu_info->flags & KVM_PPC_PAGE_SIZES_REAL))
101                 /* Guest pages are not restricted by the backing page size */
102                 return;
103
104         /* Filter based on backing page size */
105
106         for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
107                 sps = &mmu_info->sps[i];
108
109                 if (!sps->page_shift)
110                         break;
111
112                 if (kvm->ram_pagesize < (1ul << sps->page_shift)) {
113                         /* Mark the whole segment size invalid */
114                         sps->page_shift = 0;
115                         continue;
116                 }
117
118                 /* Check each page size for the segment */
119                 for (j = 0, valid = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
120                         if (!sps->enc[j].page_shift)
121                                 break;
122
123                         if (kvm->ram_pagesize < (1ul << sps->enc[j].page_shift))
124                                 sps->enc[j].page_shift = 0;
125                         else
126                                 valid++;
127                 }
128
129                 if (!valid) {
130                         /* Mark the whole segment size invalid */
131                         sps->page_shift = 0;
132                         continue;
133                 }
134
135                 /* Mark any trailing entries invalid if we broke out early */
136                 for (k = j; k < KVM_PPC_PAGE_SIZES_MAX_SZ; k++)
137                         sps->enc[k].page_shift = 0;
138
139                 /* Collapse holes */
140                 for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
141                         if (sps->enc[j].page_shift)
142                                 continue;
143
144                         for (k = j + 1; k < KVM_PPC_PAGE_SIZES_MAX_SZ; k++) {
145                                 if (sps->enc[k].page_shift) {
146                                         sps->enc[j] = sps->enc[k];
147                                         sps->enc[k].page_shift = 0;
148                                         break;
149                                 }
150                         }
151                 }
152         }
153
154         /* Mark any trailing entries invalid if we broke out early */
155         for (j = i; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++)
156                 mmu_info->sps[j].page_shift = 0;
157
158         /* Collapse holes */
159         for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
160                 if (mmu_info->sps[i].page_shift)
161                         continue;
162
163                 for (j = i + 1; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
164                         if (mmu_info->sps[j].page_shift) {
165                                 mmu_info->sps[i] = mmu_info->sps[j];
166                                 mmu_info->sps[j].page_shift = 0;
167                                 break;
168                         }
169                 }
170         }
171 }
172
173 struct cpu_info *find_cpu_info(struct kvm *kvm)
174 {
175         struct cpu_info *info;
176         unsigned int i;
177         u32 pvr = kvm->arch.pvr;
178
179         for (info = NULL, i = 0; i < ARRAY_SIZE(host_pvr_info); i++) {
180                 if ((pvr & host_pvr_info[i].pvr_mask) == host_pvr_info[i].pvr) {
181                         info = host_pvr_info[i].cpu_info;
182                         break;
183                 }
184         }
185
186         /* Didn't find anything? Rut-ro. */
187         if (!info) {
188                 pr_warning("Host CPU unsupported by kvmtool\n");
189                 info = &cpu_dummy_info;
190         }
191
192         setup_mmu_info(kvm, info);
193
194         return info;
195 }