cpu_ppc64.c 21.1 KB
Newer Older
P
Prerna Saxena 已提交
1
/*
2
 * cpu_ppc64.c: CPU driver for 64-bit PowerPC CPUs
P
Prerna Saxena 已提交
3
 *
4
 * Copyright (C) 2013 Red Hat, Inc.
L
Li Zhang 已提交
5
 * Copyright (C) IBM Corporation, 2010
P
Prerna Saxena 已提交
6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
P
Prerna Saxena 已提交
20 21 22 23
 *
 * Authors:
 *      Anton Blanchard <anton@au.ibm.com>
 *      Prerna Saxena <prerna@linux.vnet.ibm.com>
L
Li Zhang 已提交
24
 *      Li Zhang <zhlcindy@linux.vnet.ibm.com>
P
Prerna Saxena 已提交
25 26 27
 */

#include <config.h>
L
Li Zhang 已提交
28
#include <stdint.h>
P
Prerna Saxena 已提交
29

30
#include "virlog.h"
31
#include "viralloc.h"
P
Prerna Saxena 已提交
32
#include "cpu.h"
33
#include "virstring.h"
L
Li Zhang 已提交
34
#include "cpu_map.h"
35
#include "virbuffer.h"
P
Prerna Saxena 已提交
36 37 38

#define VIR_FROM_THIS VIR_FROM_CPU

39
VIR_LOG_INIT("cpu.cpu_ppc64");
40

41
static const virArch archs[] = { VIR_ARCH_PPC64, VIR_ARCH_PPC64LE };
P
Prerna Saxena 已提交
42

43
struct ppc64_vendor {
L
Li Zhang 已提交
44 45 46
    char *name;
};

47
struct ppc64_model {
L
Li Zhang 已提交
48
    char *name;
49
    const struct ppc64_vendor *vendor;
50
    virCPUppc64Data data;
L
Li Zhang 已提交
51 52
};

53
struct ppc64_map {
54 55
    size_t nvendors;
    struct ppc64_vendor **vendors;
56 57
    size_t nmodels;
    struct ppc64_model **models;
L
Li Zhang 已提交
58 59
};

60 61 62 63 64 65
/* Convert a legacy CPU definition by transforming
 * model names to generation names:
 *   POWER7_v2.1  => POWER7
 *   POWER7_v2.3  => POWER7
 *   POWER7+_v2.1 => POWER7
 *   POWER8_v1.0  => POWER8 */
66 67
static int
virCPUppc64ConvertLegacy(virCPUDefPtr cpu)
68
{
69 70 71 72 73 74
    if (cpu->model &&
        (STREQ(cpu->model, "POWER7_v2.1") ||
         STREQ(cpu->model, "POWER7_v2.3") ||
         STREQ(cpu->model, "POWER7+_v2.1") ||
         STREQ(cpu->model, "POWER8_v1.0"))) {
        cpu->model[strlen("POWERx")] = 0;
75 76
    }

77
    return 0;
78 79
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
/* Some hosts can run guests in compatibility mode, but not all
 * host CPUs support this and not all combinations are valid.
 * This function performs the necessary checks */
static virCPUCompareResult
ppc64CheckCompatibilityMode(const char *host_model,
                            const char *compat_mode)
{
    int host;
    int compat;
    char *tmp;
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;

    if (!compat_mode)
        return VIR_CPU_COMPARE_IDENTICAL;

95
    /* Valid host CPUs: POWER6, POWER7, POWER8, POWER9 */
96 97 98
    if (!STRPREFIX(host_model, "POWER") ||
        !(tmp = (char *) host_model + strlen("POWER")) ||
        virStrToLong_i(tmp, NULL, 10, &host) < 0 ||
99
        host < 6 || host > 9) {
100 101 102 103 104 105
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("Host CPU does not support compatibility modes"));
        goto out;
    }

106
    /* Valid compatibility modes: power6, power7, power8, power9 */
107 108 109
    if (!STRPREFIX(compat_mode, "power") ||
        !(tmp = (char *) compat_mode + strlen("power")) ||
        virStrToLong_i(tmp, NULL, 10, &compat) < 0 ||
110
        compat < 6 || compat > 9) {
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown compatibility mode %s"),
                       compat_mode);
        goto out;
    }

    /* Version check */
    if (compat > host)
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
    else
        ret = VIR_CPU_COMPARE_IDENTICAL;

 out:
    return ret;
}

127
static void
128
ppc64DataClear(virCPUppc64Data *data)
129
{
130 131 132 133
    if (!data)
        return;

    VIR_FREE(data->pvr);
134 135
}

136 137
static int
ppc64DataCopy(virCPUppc64Data *dst, const virCPUppc64Data *src)
138
{
139
    size_t i;
140

141 142
    if (VIR_ALLOC_N(dst->pvr, src->len) < 0)
        return -1;
143

144
    dst->len = src->len;
145

146 147 148
    for (i = 0; i < src->len; i++) {
        dst->pvr[i].value = src->pvr[i].value;
        dst->pvr[i].mask = src->pvr[i].mask;
149
    }
150

151
    return 0;
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167
static void
ppc64VendorFree(struct ppc64_vendor *vendor)
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
}

static struct ppc64_vendor *
ppc64VendorFind(const struct ppc64_map *map,
                const char *name)
{
168
    size_t i;
169

170 171 172
    for (i = 0; i < map->nvendors; i++) {
        if (STREQ(map->vendors[i]->name, name))
            return map->vendors[i];
173 174 175 176
    }

    return NULL;
}
L
Li Zhang 已提交
177 178

static void
179
ppc64ModelFree(struct ppc64_model *model)
L
Li Zhang 已提交
180
{
181
    if (!model)
L
Li Zhang 已提交
182 183
        return;

184
    ppc64DataClear(&model->data);
L
Li Zhang 已提交
185 186 187 188
    VIR_FREE(model->name);
    VIR_FREE(model);
}

189 190 191 192 193
static struct ppc64_model *
ppc64ModelCopy(const struct ppc64_model *model)
{
    struct ppc64_model *copy;

194 195 196 197 198 199
    if (VIR_ALLOC(copy) < 0)
        goto error;

    if (VIR_STRDUP(copy->name, model->name) < 0)
        goto error;

200
    if (ppc64DataCopy(&copy->data, &model->data) < 0)
201
        goto error;
202 203 204 205

    copy->vendor = model->vendor;

    return copy;
206 207 208 209

 error:
    ppc64ModelFree(copy);
    return NULL;
210 211
}

212 213 214
static struct ppc64_model *
ppc64ModelFind(const struct ppc64_map *map,
               const char *name)
L
Li Zhang 已提交
215
{
216
    size_t i;
L
Li Zhang 已提交
217

218 219 220
    for (i = 0; i < map->nmodels; i++) {
        if (STREQ(map->models[i]->name, name))
            return map->models[i];
L
Li Zhang 已提交
221 222 223 224 225
    }

    return NULL;
}

226 227 228
static struct ppc64_model *
ppc64ModelFindPVR(const struct ppc64_map *map,
                  uint32_t pvr)
229
{
230
    size_t i;
231
    size_t j;
232

233 234
    for (i = 0; i < map->nmodels; i++) {
        struct ppc64_model *model = map->models[i];
235 236
        for (j = 0; j < model->data.len; j++) {
            if ((pvr & model->data.pvr[j].mask) == model->data.pvr[j].value)
237 238
                return model;
        }
239 240 241 242 243
    }

    return NULL;
}

244
static struct ppc64_model *
245 246
ppc64ModelFromCPU(const virCPUDef *cpu,
                  const struct ppc64_map *map)
247
{
248
    struct ppc64_model *model;
249

250 251 252 253 254 255
    if (!cpu->model) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("no CPU model specified"));
        return NULL;
    }

256 257 258
    if (!(model = ppc64ModelFind(map, cpu->model))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpu->model);
259 260 261
        return NULL;
    }

262
    return ppc64ModelCopy(model);
L
Li Zhang 已提交
263 264 265
}

static void
266
ppc64MapFree(struct ppc64_map *map)
L
Li Zhang 已提交
267
{
268 269
    size_t i;

270
    if (!map)
L
Li Zhang 已提交
271 272
        return;

273 274 275
    for (i = 0; i < map->nmodels; i++)
        ppc64ModelFree(map->models[i]);
    VIR_FREE(map->models);
276

277 278 279
    for (i = 0; i < map->nvendors; i++)
        ppc64VendorFree(map->vendors[i]);
    VIR_FREE(map->vendors);
280

281
    VIR_FREE(map);
282 283
}

284 285 286 287
static int
ppc64VendorParse(xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
                 const char *name,
                 void *data)
L
Li Zhang 已提交
288
{
289
    struct ppc64_map *map = data;
290
    struct ppc64_vendor *vendor;
291
    int ret = -1;
L
Li Zhang 已提交
292

293
    if (VIR_ALLOC(vendor) < 0)
294
        return -1;
L
Li Zhang 已提交
295

296
    if (VIR_STRDUP(vendor->name, name) < 0)
297
        goto cleanup;
L
Li Zhang 已提交
298

299
    if (ppc64VendorFind(map, vendor->name)) {
L
Li Zhang 已提交
300 301
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
302
        goto cleanup;
L
Li Zhang 已提交
303 304
    }

305
    if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0)
306
        goto cleanup;
307

308
    ret = 0;
L
Li Zhang 已提交
309

310
 cleanup:
311
    ppc64VendorFree(vendor);
312
    return ret;
L
Li Zhang 已提交
313 314
}

J
Jiri Denemark 已提交
315

L
Li Zhang 已提交
316
static int
J
Jiri Denemark 已提交
317
ppc64ModelParse(xmlXPathContextPtr ctxt,
318 319
                const char *name,
                void *data)
L
Li Zhang 已提交
320
{
321
    struct ppc64_map *map = data;
322
    struct ppc64_model *model;
323
    xmlNodePtr *nodes = NULL;
L
Li Zhang 已提交
324
    char *vendor = NULL;
325
    unsigned long pvr;
326 327
    size_t i;
    int n;
328
    int ret = -1;
329

330
    if (VIR_ALLOC(model) < 0)
331
        goto cleanup;
L
Li Zhang 已提交
332

333
    if (VIR_STRDUP(model->name, name) < 0)
334
        goto cleanup;
L
Li Zhang 已提交
335

336
    if (ppc64ModelFind(map, model->name)) {
337 338
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU model %s already defined"), model->name);
339
        goto cleanup;
340
    }
L
Li Zhang 已提交
341 342 343 344 345 346 347

    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
348
            goto cleanup;
L
Li Zhang 已提交
349 350
        }

351
        if (!(model->vendor = ppc64VendorFind(map, vendor))) {
L
Li Zhang 已提交
352 353 354
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
355
            goto cleanup;
L
Li Zhang 已提交
356 357 358
        }
    }

359
    if ((n = virXPathNodeSet("./pvr", ctxt, &nodes)) <= 0) {
360
        virReportError(VIR_ERR_INTERNAL_ERROR,
361
                       _("Missing PVR information for CPU model %s"),
362
                       model->name);
363
        goto cleanup;
364
    }
365

366
    if (VIR_ALLOC_N(model->data.pvr, n) < 0)
367
        goto cleanup;
368

369
    model->data.len = n;
370 371 372 373 374 375 376 377

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];

        if (virXPathULongHex("string(./@value)", ctxt, &pvr) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing or invalid PVR value in CPU model %s"),
                           model->name);
378
            goto cleanup;
379
        }
380
        model->data.pvr[i].value = pvr;
381 382 383 384 385

        if (virXPathULongHex("string(./@mask)", ctxt, &pvr) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing or invalid PVR mask in CPU model %s"),
                           model->name);
386
            goto cleanup;
387
        }
388
        model->data.pvr[i].mask = pvr;
389
    }
390

391
    if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0)
392
        goto cleanup;
393 394 395

    ret = 0;

396
 cleanup:
397
    ppc64ModelFree(model);
L
Li Zhang 已提交
398
    VIR_FREE(vendor);
399
    VIR_FREE(nodes);
400
    return ret;
L
Li Zhang 已提交
401 402
}

J
Jiri Denemark 已提交
403

404 405
static struct ppc64_map *
ppc64LoadMap(void)
L
Li Zhang 已提交
406
{
407
    struct ppc64_map *map;
L
Li Zhang 已提交
408

409
    if (VIR_ALLOC(map) < 0)
410
        goto error;
L
Li Zhang 已提交
411

412
    if (cpuMapLoad("ppc64", ppc64VendorParse, NULL, ppc64ModelParse, map) < 0)
L
Li Zhang 已提交
413 414 415 416
        goto error;

    return map;

417
 error:
418
    ppc64MapFree(map);
L
Li Zhang 已提交
419 420 421
    return NULL;
}

422
static virCPUDataPtr
423
ppc64MakeCPUData(virArch arch,
424
                 virCPUppc64Data *data)
425 426 427 428 429 430 431
{
    virCPUDataPtr cpuData;

    if (VIR_ALLOC(cpuData) < 0)
        return NULL;

    cpuData->arch = arch;
432

433
    if (ppc64DataCopy(&cpuData->data.ppc64, data) < 0)
434
        VIR_FREE(cpuData);
435 436 437 438 439

    return cpuData;
}

static virCPUCompareResult
440
ppc64Compute(virCPUDefPtr host,
441
             const virCPUDef *other,
442 443
             virCPUDataPtr *guestData,
             char **message)
444
{
445 446 447
    struct ppc64_map *map = NULL;
    struct ppc64_model *host_model = NULL;
    struct ppc64_model *guest_model = NULL;
448
    virCPUDefPtr cpu = NULL;
449
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
450 451 452
    virArch arch;
    size_t i;

453
    /* Ensure existing configurations are handled correctly */
454 455
    if (!(cpu = virCPUDefCopy(other)) ||
        virCPUppc64ConvertLegacy(cpu) < 0)
456 457
        goto cleanup;

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
    if (cpu->arch != VIR_ARCH_NONE) {
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
            if (archs[i] == cpu->arch) {
                found = true;
                break;
            }
        }

        if (!found) {
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
                            virArchToString(cpu->arch)) < 0)
475 476 477 478
                goto cleanup;

            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
            goto cleanup;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
        }
        arch = cpu->arch;
    } else {
        arch = host->arch;
    }

    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                        "CPU vendor %s"),
                        cpu->vendor) < 0)
494 495 496 497
            goto cleanup;

        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        goto cleanup;
498 499
    }

500 501 502 503 504
    if (!(map = ppc64LoadMap()))
        goto cleanup;

    /* Host CPU information */
    if (!(host_model = ppc64ModelFromCPU(host, map)))
505
        goto cleanup;
506

507 508 509 510 511 512 513 514 515 516 517 518
    if (cpu->type == VIR_CPU_TYPE_GUEST) {
        /* Guest CPU information */
        virCPUCompareResult tmp;
        switch (cpu->mode) {
        case VIR_CPU_MODE_HOST_MODEL:
            /* host-model only:
             * we need to take compatibility modes into account */
            tmp = ppc64CheckCompatibilityMode(host->model, cpu->model);
            if (tmp != VIR_CPU_COMPARE_IDENTICAL) {
                ret = tmp;
                goto cleanup;
            }
M
Marc Hartmayer 已提交
519
            ATTRIBUTE_FALLTHROUGH;
520 521 522 523

        case VIR_CPU_MODE_HOST_PASSTHROUGH:
            /* host-model and host-passthrough:
             * the guest CPU is the same as the host */
524
            guest_model = ppc64ModelCopy(host_model);
525 526 527 528 529
            break;

        case VIR_CPU_MODE_CUSTOM:
            /* custom:
             * look up guest CPU information */
530
            guest_model = ppc64ModelFromCPU(cpu, map);
531 532 533 534
            break;
        }
    } else {
        /* Other host CPU information */
535
        guest_model = ppc64ModelFromCPU(cpu, map);
536 537
    }

538 539 540
    if (!guest_model)
        goto cleanup;

541
    if (STRNEQ(guest_model->name, host_model->name)) {
542 543 544 545 546 547 548
        VIR_DEBUG("host CPU model does not match required CPU model %s",
                  guest_model->name);
        if (message &&
            virAsprintf(message,
                        _("host CPU model does not match required "
                        "CPU model %s"),
                        guest_model->name) < 0)
549
            goto cleanup;
550

551 552 553 554 555
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        goto cleanup;
    }

    if (guestData)
556
        if (!(*guestData = ppc64MakeCPUData(arch, &guest_model->data)))
557
            goto cleanup;
558 559 560

    ret = VIR_CPU_COMPARE_IDENTICAL;

561
 cleanup:
562
    virCPUDefFree(cpu);
563 564 565
    ppc64MapFree(map);
    ppc64ModelFree(host_model);
    ppc64ModelFree(guest_model);
566 567 568
    return ret;
}

L
Li Zhang 已提交
569
static virCPUCompareResult
J
Jiri Denemark 已提交
570
virCPUppc64Compare(virCPUDefPtr host,
571 572
                   virCPUDefPtr cpu,
                   bool failIncompatible)
L
Li Zhang 已提交
573
{
574 575
    virCPUCompareResult ret;
    char *message = NULL;
L
Li Zhang 已提交
576

J
Jiri Denemark 已提交
577 578 579 580 581 582 583 584 585 586 587
    if (!host || !host->model) {
        if (failIncompatible) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
                           _("unknown host CPU"));
        } else {
            VIR_WARN("unknown host CPU");
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        }
        return -1;
    }

588 589 590 591 592 593 594 595 596
    ret = ppc64Compute(host, cpu, NULL, &message);

    if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
        ret = VIR_CPU_COMPARE_ERROR;
        if (message) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
        } else {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
        }
597
    }
598 599 600
    VIR_FREE(message);

    return ret;
L
Li Zhang 已提交
601 602 603
}

static int
604 605
ppc64DriverDecode(virCPUDefPtr cpu,
                  const virCPUData *data,
606
                  virDomainCapsCPUModelsPtr models)
L
Li Zhang 已提交
607 608
{
    int ret = -1;
609 610
    struct ppc64_map *map;
    const struct ppc64_model *model;
L
Li Zhang 已提交
611

612
    if (!data || !(map = ppc64LoadMap()))
L
Li Zhang 已提交
613 614
        return -1;

615
    if (!(model = ppc64ModelFindPVR(map, data->data.ppc64.pvr[0].value))) {
616 617
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Cannot find CPU model with PVR 0x%08x"),
618
                       data->data.ppc64.pvr[0].value);
J
Jiri Denemark 已提交
619
        goto cleanup;
620
    }
L
Li Zhang 已提交
621

622
    if (!virCPUModelIsAllowed(model->name, models)) {
J
Jiri Denemark 已提交
623 624
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("CPU model %s is not supported by hypervisor"),
625
                       model->name);
J
Jiri Denemark 已提交
626
        goto cleanup;
L
Li Zhang 已提交
627 628
    }

629 630
    if (VIR_STRDUP(cpu->model, model->name) < 0 ||
        (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) {
631 632
        goto cleanup;
    }
L
Li Zhang 已提交
633 634 635

    ret = 0;

636
 cleanup:
637
    ppc64MapFree(map);
L
Li Zhang 已提交
638 639 640 641 642

    return ret;
}

static void
J
Jiri Denemark 已提交
643
virCPUppc64DataFree(virCPUDataPtr data)
L
Li Zhang 已提交
644
{
645
    if (!data)
L
Li Zhang 已提交
646 647
        return;

648
    ppc64DataClear(&data->data.ppc64);
L
Li Zhang 已提交
649 650 651
    VIR_FREE(data);
}

652 653

static int
654
virCPUppc64GetHost(virCPUDefPtr cpu,
655
                   virDomainCapsCPUModelsPtr models)
P
Prerna Saxena 已提交
656
{
657
    virCPUDataPtr cpuData = NULL;
658
    virCPUppc64Data *data;
659
    int ret = -1;
P
Prerna Saxena 已提交
660

661 662
    if (!(cpuData = virCPUDataNew(archs[0])))
        goto cleanup;
P
Prerna Saxena 已提交
663

664
    data = &cpuData->data.ppc64;
665

666
    if (VIR_ALLOC_N(data->pvr, 1) < 0)
667
        goto cleanup;
668 669 670

    data->len = 1;

671
#if defined(__powerpc__) || defined(__powerpc64__)
J
Jiri Denemark 已提交
672
    asm("mfpvr %0"
673
        : "=r" (data->pvr[0].value));
674
#endif
675
    data->pvr[0].mask = 0xfffffffful;
L
Li Zhang 已提交
676

677
    ret = ppc64DriverDecode(cpu, cpuData, models);
678

679 680 681
 cleanup:
    virCPUppc64DataFree(cpuData);
    return ret;
P
Prerna Saxena 已提交
682 683
}

684

P
Prerna Saxena 已提交
685
static int
J
Jiri Denemark 已提交
686 687
virCPUppc64Update(virCPUDefPtr guest,
                  const virCPUDef *host ATTRIBUTE_UNUSED)
P
Prerna Saxena 已提交
688
{
J
Jiri Denemark 已提交
689 690 691 692 693 694 695 696 697
    /*
     * - host-passthrough doesn't even get here
     * - host-model is used for host CPU running in a compatibility mode and
     *   it needs to remain unchanged
     * - custom doesn't support any optional features, there's nothing to
     *   update
     */

    if (guest->mode == VIR_CPU_MODE_CUSTOM)
698 699
        guest->match = VIR_CPU_MATCH_EXACT;

J
Jiri Denemark 已提交
700
    return 0;
P
Prerna Saxena 已提交
701
}
702

L
Li Zhang 已提交
703
static virCPUDefPtr
704
virCPUppc64Baseline(virCPUDefPtr *cpus,
705
                    unsigned int ncpus,
706
                    virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED,
707
                    const char **features ATTRIBUTE_UNUSED,
708
                    bool migratable ATTRIBUTE_UNUSED)
P
Prerna Saxena 已提交
709
{
710
    struct ppc64_map *map;
711 712
    const struct ppc64_model *model;
    const struct ppc64_vendor *vendor = NULL;
L
Li Zhang 已提交
713
    virCPUDefPtr cpu = NULL;
714
    size_t i;
J
Jiri Denemark 已提交
715

716
    if (!(map = ppc64LoadMap()))
J
Jiri Denemark 已提交
717
        goto error;
L
Li Zhang 已提交
718

719
    if (!(model = ppc64ModelFind(map, cpus[0]->model))) {
J
Jiri Denemark 已提交
720 721
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpus[0]->model);
L
Li Zhang 已提交
722 723 724
        goto error;
    }

J
Jiri Denemark 已提交
725
    for (i = 0; i < ncpus; i++) {
726
        const struct ppc64_vendor *vnd;
727

728 729 730 731 732 733 734 735 736 737 738
        /* Hosts running old (<= 1.2.18) versions of libvirt will report
         * strings like 'power7+' or 'power8e' instead of proper CPU model
         * names in the capabilities XML; moreover, they lack information
         * about some proper CPU models like 'POWER8'.
         * This implies two things:
         *   1) baseline among such hosts never worked
         *   2) while a few models, eg. 'POWER8_v1.0', could work on both
         *      old and new versions of libvirt, the information we have
         *      here is not enough to pick such a model
         * Hence we just compare models by name to decide whether or not
         * two hosts are compatible */
J
Jiri Denemark 已提交
739 740 741 742 743
        if (STRNEQ(cpus[i]->model, model->name)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("CPUs are incompatible"));
            goto error;
        }
L
Li Zhang 已提交
744

J
Jiri Denemark 已提交
745 746 747
        if (!cpus[i]->vendor)
            continue;

748
        if (!(vnd = ppc64VendorFind(map, cpus[i]->vendor))) {
J
Jiri Denemark 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Unknown CPU vendor %s"), cpus[i]->vendor);
            goto error;
        }

        if (model->vendor) {
            if (model->vendor != vnd) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("CPU vendor %s of model %s differs from "
                                 "vendor %s"),
                               model->vendor->name, model->name,
                               vnd->name);
                goto error;
            }
        } else if (vendor) {
            if (vendor != vnd) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("CPU vendors do not match"));
                goto error;
            }
        } else {
            vendor = vnd;
        }
L
Li Zhang 已提交
772 773
    }

J
Jiri Denemark 已提交
774
    if (VIR_ALLOC(cpu) < 0 ||
775
        VIR_STRDUP(cpu->model, model->name) < 0)
776
        goto error;
L
Li Zhang 已提交
777

778 779
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto error;
J
Jiri Denemark 已提交
780 781 782

    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
783
    cpu->fallback = VIR_CPU_FALLBACK_FORBID;
L
Li Zhang 已提交
784

785
 cleanup:
786
    ppc64MapFree(map);
P
Prerna Saxena 已提交
787

L
Li Zhang 已提交
788
    return cpu;
J
Jiri Denemark 已提交
789

790
 error:
L
Li Zhang 已提交
791 792 793
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
P
Prerna Saxena 已提交
794 795
}

796
static int
J
Jiri Denemark 已提交
797
virCPUppc64DriverGetModels(char ***models)
798
{
799
    struct ppc64_map *map;
800 801
    size_t i;
    int ret = -1;
802

803
    if (!(map = ppc64LoadMap()))
804 805
        goto error;

806 807 808
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
809

810 811
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
812 813
                goto error;
        }
814 815
    }

816 817
    ret = map->nmodels;

818
 cleanup:
819
    ppc64MapFree(map);
820
    return ret;
821 822

 error:
823
    if (models) {
824
        virStringListFree(*models);
825 826
        *models = NULL;
    }
827 828 829
    goto cleanup;
}

830
struct cpuArchDriver cpuDriverPPC64 = {
831 832 833
    .name       = "ppc64",
    .arch       = archs,
    .narch      = ARRAY_CARDINALITY(archs),
J
Jiri Denemark 已提交
834
    .compare    = virCPUppc64Compare,
835
    .decode     = ppc64DriverDecode,
P
Prerna Saxena 已提交
836
    .encode     = NULL,
J
Jiri Denemark 已提交
837
    .dataFree   = virCPUppc64DataFree,
838
    .getHost    = virCPUppc64GetHost,
839
    .baseline   = virCPUppc64Baseline,
J
Jiri Denemark 已提交
840
    .update     = virCPUppc64Update,
J
Jiri Denemark 已提交
841
    .getModels  = virCPUppc64DriverGetModels,
842
    .convertLegacy = virCPUppc64ConvertLegacy,
P
Prerna Saxena 已提交
843
};