virpci.c 91.8 KB
Newer Older
1
/*
2 3
 * virpci.c: helper APIs for managing host PCI devices
 *
4
 * Copyright (C) 2009-2015 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24 25
 *
 * Authors:
 *     Mark McLoughlin <markmc@redhat.com>
 */

#include <config.h>

26
#include "virpci.h"
27
#include "virnetdev.h"
28 29 30 31 32 33 34 35 36 37

#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
38
#include <stdlib.h>
39

40
#include "dirname.h"
41
#include "virlog.h"
42
#include "viralloc.h"
43
#include "vircommand.h"
44
#include "virerror.h"
E
Eric Blake 已提交
45
#include "virfile.h"
46
#include "virkmod.h"
47 48
#include "virstring.h"
#include "virutil.h"
49

50 51
VIR_LOG_INIT("util.pci");

52 53 54 55
#define PCI_SYSFS "/sys/bus/pci/"
#define PCI_ID_LEN 10   /* "XXXX XXXX" */
#define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */

56
VIR_ENUM_IMPL(virPCIELinkSpeed, VIR_PCIE_LINK_SPEED_LAST,
57
              "", "2.5", "5", "8", "16")
58

59 60 61 62 63 64 65
VIR_ENUM_IMPL(virPCIStubDriver, VIR_PCI_STUB_DRIVER_LAST,
              "none",
              "pciback", /* XEN */
              "pci-stub", /* KVM */
              "vfio-pci", /* VFIO */
);

66 67 68 69 70 71
VIR_ENUM_IMPL(virPCIHeader, VIR_PCI_HEADER_LAST,
              "endpoint",
              "pci-bridge",
              "cardbus-bridge",
);

72
struct _virPCIDevice {
73
    virPCIDeviceAddress address;
74 75 76

    char          name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
    char          id[PCI_ID_LEN];     /* product vendor */
E
Eric Blake 已提交
77
    char          *path;
C
Chunyan Liu 已提交
78 79 80 81

    /* The driver:domain which uses the device */
    char          *used_by_drvname;
    char          *used_by_domname;
82

83 84
    unsigned int  pcie_cap_pos;
    unsigned int  pci_pm_cap_pos;
85 86
    bool          has_flr;
    bool          has_pm_reset;
87
    bool          managed;
88 89

    virPCIStubDriver stubDriver;
90 91

    /* used by reattach function */
92 93 94
    bool          unbind_from_stub;
    bool          remove_slot;
    bool          reprobe;
95 96
};

97
struct _virPCIDeviceList {
98 99
    virObjectLockable parent;

100
    size_t count;
101
    virPCIDevicePtr *devs;
102 103 104
};


105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
/* For virReportOOMError()  and virReportSystemError() */
#define VIR_FROM_THIS VIR_FROM_NONE

/* Specifications referenced in comments:
 *  PCI30  - PCI Local Bus Specification 3.0
 *  PCIe20 - PCI Express Base Specification 2.0
 *  BR12   - PCI-to-PCI Bridge Architecture Specification 1.2
 *  PM12   - PCI Bus Power Management Interface Specification 1.2
 *  ECN_AF - Advanced Capabilities for Conventional PCI ECN
 */

/* Type 0 config space header length; PCI30 Section 6.1 Configuration Space Organization */
#define PCI_CONF_LEN            0x100
#define PCI_CONF_HEADER_LEN     0x40

/* PCI30 6.2.1 */
#define PCI_HEADER_TYPE         0x0e    /* Header type */
122 123 124
#define PCI_HEADER_TYPE_BRIDGE 0x1
#define PCI_HEADER_TYPE_MASK   0x7f
#define PCI_HEADER_TYPE_MULTI  0x80
125 126 127 128 129 130 131 132 133

/* PCI30 6.2.1  Device Identification */
#define PCI_CLASS_DEVICE        0x0a    /* Device class */

/* Class Code for bridge; PCI30 D.7  Base Class 06h */
#define PCI_CLASS_BRIDGE_PCI    0x0604

/* PCI30 6.2.3  Device Status */
#define PCI_STATUS              0x06    /* 16 bits */
134
#define PCI_STATUS_CAP_LIST    0x10    /* Support Capability List */
135 136 137

/* PCI30 6.7  Capabilities List */
#define PCI_CAPABILITY_LIST     0x34    /* Offset of first capability list entry */
138
#define PCI_CAP_FLAGS           2       /* Capability defined flags (16 bits) */
139 140 141 142 143 144 145 146 147 148

/* PM12 3.2.1  Capability Identifier */
#define PCI_CAP_ID_PM           0x01    /* Power Management */
/* PCI30 H Capability IDs */
#define PCI_CAP_ID_EXP          0x10    /* PCI Express */
/* ECN_AF 6.x.1.1  Capability ID for AF */
#define PCI_CAP_ID_AF           0x13    /* Advanced Features */

/* PCIe20 7.8.3  Device Capabilities Register (Offset 04h) */
#define PCI_EXP_DEVCAP          0x4     /* Device capabilities */
149 150
#define PCI_EXP_DEVCAP_FLR     (1<<28)  /* Function Level Reset */
#define PCI_EXP_LNKCAP          0xc     /* Link Capabilities */
151
#define PCI_EXP_LNKCAP_SPEED    0x0000f /* Maximum Link Speed */
152 153 154 155
#define PCI_EXP_LNKCAP_WIDTH    0x003f0 /* Maximum Link Width */
#define PCI_EXP_LNKSTA          0x12    /* Link Status */
#define PCI_EXP_LNKSTA_SPEED    0x000f  /* Negotiated Link Speed */
#define PCI_EXP_LNKSTA_WIDTH    0x03f0  /* Negotiated Link Width */
156 157 158 159 160 161 162

/* Header type 1 BR12 3.2 PCI-to-PCI Bridge Configuration Space Header Format */
#define PCI_PRIMARY_BUS         0x18    /* BR12 3.2.5.2 Primary bus number */
#define PCI_SECONDARY_BUS       0x19    /* BR12 3.2.5.3 Secondary bus number */
#define PCI_SUBORDINATE_BUS     0x1a    /* BR12 3.2.5.4 Highest bus number behind the bridge */
#define PCI_BRIDGE_CONTROL      0x3e
/* BR12 3.2.5.18  Bridge Control Register */
163
#define PCI_BRIDGE_CTL_RESET   0x40    /* Secondary bus reset */
164 165 166

/* PM12 3.2.4  Power Management Control/Status (Offset = 4) */
#define PCI_PM_CTRL                4    /* PM control and status register */
167 168 169 170
#define PCI_PM_CTRL_STATE_MASK    0x3  /* Current power state (D0 to D3) */
#define PCI_PM_CTRL_STATE_D0      0x0  /* D0 state */
#define PCI_PM_CTRL_STATE_D3hot   0x3  /* D3 state */
#define PCI_PM_CTRL_NO_SOFT_RESET 0x8  /* No reset for D3hot->D0 */
171 172 173

/* ECN_AF 6.x.1  Advanced Features Capability Structure */
#define PCI_AF_CAP              0x3     /* Advanced features capabilities */
174
#define PCI_AF_CAP_FLR         0x2     /* Function Level Reset */
175

J
Jiri Denemark 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
#define PCI_EXP_FLAGS           0x2
#define PCI_EXP_FLAGS_TYPE      0x00f0
#define PCI_EXP_TYPE_DOWNSTREAM 0x6

#define PCI_EXT_CAP_BASE          0x100
#define PCI_EXT_CAP_LIMIT         0x1000
#define PCI_EXT_CAP_ID_MASK       0x0000ffff
#define PCI_EXT_CAP_OFFSET_SHIFT  20
#define PCI_EXT_CAP_OFFSET_MASK   0x00000ffc

#define PCI_EXT_CAP_ID_ACS      0x000d
#define PCI_EXT_ACS_CTRL        0x06

#define PCI_EXT_CAP_ACS_SV      0x01
#define PCI_EXT_CAP_ACS_RR      0x04
#define PCI_EXT_CAP_ACS_CR      0x08
#define PCI_EXT_CAP_ACS_UF      0x10
193 194 195
#define PCI_EXT_CAP_ACS_ENABLED (PCI_EXT_CAP_ACS_SV | \
                                 PCI_EXT_CAP_ACS_RR | \
                                 PCI_EXT_CAP_ACS_CR | \
J
Jiri Denemark 已提交
196 197
                                 PCI_EXT_CAP_ACS_UF)

198 199 200
#define PCI_EXP_TYPE_ROOT_INT_EP 0x9    /* Root Complex Integrated Endpoint */
#define PCI_EXP_TYPE_ROOT_EC 0xa        /* Root Complex Event Collector */

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
static virClassPtr virPCIDeviceListClass;

static void virPCIDeviceListDispose(void *obj);

static int virPCIOnceInit(void)
{
    if (!(virPCIDeviceListClass = virClassNew(virClassForObjectLockable(),
                                              "virPCIDeviceList",
                                              sizeof(virPCIDeviceList),
                                              virPCIDeviceListDispose)))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virPCI)

L
Laine Stump 已提交
218

219 220
static char *
virPCIDriverDir(const char *driver)
L
Laine Stump 已提交
221
{
222
    char *buffer;
L
Laine Stump 已提交
223

224 225
    ignore_value(virAsprintf(&buffer, PCI_SYSFS "drivers/%s", driver));
    return buffer;
L
Laine Stump 已提交
226 227 228
}


229 230
static char *
virPCIDriverFile(const char *driver, const char *file)
L
Laine Stump 已提交
231
{
232
    char *buffer;
L
Laine Stump 已提交
233

234 235
    ignore_value(virAsprintf(&buffer, PCI_SYSFS "drivers/%s/%s", driver, file));
    return buffer;
L
Laine Stump 已提交
236 237 238
}


239 240
static char *
virPCIFile(const char *device, const char *file)
L
Laine Stump 已提交
241
{
242
    char *buffer;
L
Laine Stump 已提交
243

244 245
    ignore_value(virAsprintf(&buffer, PCI_SYSFS "devices/%s/%s", device, file));
    return buffer;
L
Laine Stump 已提交
246 247 248 249 250 251 252 253 254 255
}


/* virPCIDeviceGetDriverPathAndName - put the path to the driver
 * directory of the driver in use for this device in @path and the
 * name of the driver in @name. Both could be NULL if it's not bound
 * to any driver.
 *
 * Return 0 for success, -1 for error.
 */
256
int
L
Laine Stump 已提交
257 258 259 260 261 262 263
virPCIDeviceGetDriverPathAndName(virPCIDevicePtr dev, char **path, char **name)
{
    int ret = -1;
    char *drvlink = NULL;

    *path = *name = NULL;
    /* drvlink = "/sys/bus/pci/dddd:bb:ss.ff/driver" */
264
    if (!(drvlink = virPCIFile(dev->name, "driver")))
L
Laine Stump 已提交
265 266
        goto cleanup;

267 268 269 270 271
    if (!virFileExists(drvlink)) {
        ret = 0;
        goto cleanup;
    }

L
Laine Stump 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    if (virFileIsLink(drvlink) != 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid device %s driver file %s is not a symlink"),
                       dev->name, drvlink);
        goto cleanup;
    }
    if (virFileResolveLink(drvlink, path) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to resolve device %s driver symlink %s"),
                       dev->name, drvlink);
        goto cleanup;
    }
    /* path = "/sys/bus/pci/drivers/${drivername}" */

    if (VIR_STRDUP(*name, last_component(*path)) < 0)
        goto cleanup;
    /* name = "${drivername}" */

    ret = 0;
291
 cleanup:
L
Laine Stump 已提交
292 293 294 295 296 297 298 299 300
    VIR_FREE(drvlink);
    if (ret < 0) {
        VIR_FREE(*path);
        VIR_FREE(*name);
    }
    return ret;
}


301
static int
302
virPCIDeviceConfigOpen(virPCIDevicePtr dev, bool fatal)
303 304 305 306
{
    int fd;

    fd = open(dev->path, O_RDWR);
307

308
    if (fd < 0) {
309 310 311 312 313 314 315 316 317
        if (fatal) {
            virReportSystemError(errno,
                                 _("Failed to open config space file '%s'"),
                                 dev->path);
        } else {
            char ebuf[1024];
            VIR_WARN("Failed to open config space file '%s': %s",
                     dev->path, virStrerror(errno, ebuf, sizeof(ebuf)));
        }
318 319
        return -1;
    }
320

321
    VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path);
322
    return fd;
323 324
}

325
static void
326
virPCIDeviceConfigClose(virPCIDevicePtr dev, int cfgfd)
327
{
328 329 330 331 332
    if (VIR_CLOSE(cfgfd) < 0) {
        char ebuf[1024];
        VIR_WARN("Failed to close config space file '%s': %s",
                 dev->path, virStrerror(errno, ebuf, sizeof(ebuf)));
    }
333 334
}

335

336
static int
337 338
virPCIDeviceRead(virPCIDevicePtr dev,
                 int cfgfd,
339
                 unsigned int pos,
340
                 uint8_t *buf,
341
                 unsigned int buflen)
342 343 344
{
    memset(buf, 0, buflen);

345 346
    if (lseek(cfgfd, pos, SEEK_SET) != pos ||
        saferead(cfgfd, buf, buflen) != buflen) {
347
        char ebuf[1024];
348
        VIR_WARN("Failed to read from '%s' : %s", dev->path,
349 350 351 352 353 354 355
                 virStrerror(errno, ebuf, sizeof(ebuf)));
        return -1;
    }
    return 0;
}

static uint8_t
356
virPCIDeviceRead8(virPCIDevicePtr dev, int cfgfd, unsigned int pos)
357 358
{
    uint8_t buf;
359
    virPCIDeviceRead(dev, cfgfd, pos, &buf, sizeof(buf));
360 361 362 363
    return buf;
}

static uint16_t
364
virPCIDeviceRead16(virPCIDevicePtr dev, int cfgfd, unsigned int pos)
365 366
{
    uint8_t buf[2];
367
    virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
368 369 370 371
    return (buf[0] << 0) | (buf[1] << 8);
}

static uint32_t
372
virPCIDeviceRead32(virPCIDevicePtr dev, int cfgfd, unsigned int pos)
373 374
{
    uint8_t buf[4];
375
    virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
376 377 378
    return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}

379 380 381 382 383 384 385 386
static int
virPCIDeviceReadClass(virPCIDevicePtr dev, uint16_t *device_class)
{
    char *path = NULL;
    char *id_str = NULL;
    int ret = -1;
    unsigned int value;

387
    if (!(path = virPCIFile(dev->name, "class")))
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
        return ret;

    /* class string is '0xNNNNNN\n' ... i.e. 9 bytes */
    if (virFileReadAll(path, 9, &id_str) < 0)
        goto cleanup;

    id_str[8] = '\0';
    if (virStrToLong_ui(id_str, NULL, 16, &value) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unusual value in %s/devices/%s/class: %s"),
                       PCI_SYSFS, dev->name, id_str);
        goto cleanup;
    }

    *device_class = (value >> 8) & 0xFFFF;
    ret = 0;
404
 cleanup:
405 406 407 408 409
    VIR_FREE(id_str);
    VIR_FREE(path);
    return ret;
}

410
static int
411 412
virPCIDeviceWrite(virPCIDevicePtr dev,
                  int cfgfd,
413
                  unsigned int pos,
414
                  uint8_t *buf,
415
                  unsigned int buflen)
416
{
417 418
    if (lseek(cfgfd, pos, SEEK_SET) != pos ||
        safewrite(cfgfd, buf, buflen) != buflen) {
419
        char ebuf[1024];
420
        VIR_WARN("Failed to write to '%s' : %s", dev->path,
421 422 423 424 425 426 427
                 virStrerror(errno, ebuf, sizeof(ebuf)));
        return -1;
    }
    return 0;
}

static void
428
virPCIDeviceWrite16(virPCIDevicePtr dev, int cfgfd, unsigned int pos, uint16_t val)
429 430
{
    uint8_t buf[2] = { (val >> 0), (val >> 8) };
431
    virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
432 433 434
}

static void
435
virPCIDeviceWrite32(virPCIDevicePtr dev, int cfgfd, unsigned int pos, uint32_t val)
436
{
437
    uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) };
438
    virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
439 440
}

E
Eric Blake 已提交
441 442
typedef int (*virPCIDeviceIterPredicate)(virPCIDevicePtr, virPCIDevicePtr,
                                         void *);
443 444 445 446 447 448 449

/* Iterate over available PCI devices calling @predicate
 * to compare each one to @dev.
 * Return -1 on error since we don't want to assume it is
 * safe to reset if there is an error.
 */
static int
450 451 452 453
virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate,
                        virPCIDevicePtr dev,
                        virPCIDevicePtr *matched,
                        void *data)
454 455 456
{
    DIR *dir;
    struct dirent *entry;
457
    int ret = 0;
458
    int rc;
459 460 461 462 463

    *matched = NULL;

    VIR_DEBUG("%s %s: iterating over " PCI_SYSFS "devices", dev->id, dev->name);

J
Ján Tomko 已提交
464
    if (virDirOpen(&dir, PCI_SYSFS "devices") < 0)
465 466
        return -1;

E
Eric Blake 已提交
467
    while ((ret = virDirRead(dir, &entry, PCI_SYSFS "devices")) > 0) {
468
        unsigned int domain, bus, slot, function;
469
        virPCIDevicePtr check;
470
        char *tmp;
471

472 473 474 475 476 477 478 479 480
        /* expected format: <domain>:<bus>:<slot>.<function> */
        if (/* domain */
            virStrToLong_ui(entry->d_name, &tmp, 16, &domain) < 0 || *tmp != ':' ||
            /* bus */
            virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' ||
            /* slot */
            virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' ||
            /* function */
            virStrToLong_ui(tmp + 1, NULL, 16, &function) < 0) {
481 482 483 484
            VIR_WARN("Unusual entry in " PCI_SYSFS "devices: %s", entry->d_name);
            continue;
        }

485
        check = virPCIDeviceNew(domain, bus, slot, function);
486
        if (!check) {
487 488 489
            ret = -1;
            break;
        }
490

491 492 493
        rc = predicate(dev, check, data);
        if (rc < 0) {
            /* the predicate returned an error, bail */
494
            virPCIDeviceFree(check);
495 496
            ret = -1;
            break;
497
        } else if (rc == 1) {
498 499
            VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
            *matched = check;
500
            ret = 1;
501 502
            break;
        }
503

504
        virPCIDeviceFree(check);
505
    }
J
Ján Tomko 已提交
506
    VIR_DIR_CLOSE(dir);
507
    return ret;
508 509 510
}

static uint8_t
511 512 513
virPCIDeviceFindCapabilityOffset(virPCIDevicePtr dev,
                                 int cfgfd,
                                 unsigned int capability)
514 515 516 517
{
    uint16_t status;
    uint8_t pos;

518
    status = virPCIDeviceRead16(dev, cfgfd, PCI_STATUS);
519 520 521
    if (!(status & PCI_STATUS_CAP_LIST))
        return 0;

522
    pos = virPCIDeviceRead8(dev, cfgfd, PCI_CAPABILITY_LIST);
523 524 525 526 527 528 529 530 531

    /* Zero indicates last capability, capabilities can't
     * be in the config space header and 0xff is returned
     * by the kernel if we don't have access to this region
     *
     * Note: we're not handling loops or extended
     * capabilities here.
     */
    while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
532
        uint8_t capid = virPCIDeviceRead8(dev, cfgfd, pos);
533 534 535 536 537 538
        if (capid == capability) {
            VIR_DEBUG("%s %s: found cap 0x%.2x at 0x%.2x",
                      dev->id, dev->name, capability, pos);
            return pos;
        }

539
        pos = virPCIDeviceRead8(dev, cfgfd, pos + 1);
540 541 542 543 544 545 546
    }

    VIR_DEBUG("%s %s: failed to find cap 0x%.2x", dev->id, dev->name, capability);

    return 0;
}

J
Jiri Denemark 已提交
547
static unsigned int
548 549
virPCIDeviceFindExtendedCapabilityOffset(virPCIDevicePtr dev,
                                         int cfgfd,
550
                                         unsigned int capability)
J
Jiri Denemark 已提交
551 552 553 554 555 556 557 558 559 560
{
    int ttl;
    unsigned int pos;
    uint32_t header;

    /* minimum 8 bytes per capability */
    ttl = (PCI_EXT_CAP_LIMIT - PCI_EXT_CAP_BASE) / 8;
    pos = PCI_EXT_CAP_BASE;

    while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) {
561
        header = virPCIDeviceRead32(dev, cfgfd, pos);
J
Jiri Denemark 已提交
562 563 564 565 566 567 568 569 570 571 572

        if ((header & PCI_EXT_CAP_ID_MASK) == capability)
            return pos;

        pos = (header >> PCI_EXT_CAP_OFFSET_SHIFT) & PCI_EXT_CAP_OFFSET_MASK;
        ttl--;
    }

    return 0;
}

573 574 575 576
/* detects whether this device has FLR.  Returns 0 if the device does
 * not have FLR, 1 if it does, and -1 on error
 */
static int
577
virPCIDeviceDetectFunctionLevelReset(virPCIDevicePtr dev, int cfgfd)
578
{
M
Mark McLoughlin 已提交
579
    uint32_t caps;
580
    uint8_t pos;
581 582
    char *path;
    int found;
583 584 585 586 587 588 589 590

    /* The PCIe Function Level Reset capability allows
     * individual device functions to be reset without
     * affecting any other functions on the device or
     * any other devices on the bus. This is only common
     * on SR-IOV NICs at the moment.
     */
    if (dev->pcie_cap_pos) {
591
        caps = virPCIDeviceRead32(dev, cfgfd, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
592 593 594 595 596 597 598 599 600 601
        if (caps & PCI_EXP_DEVCAP_FLR) {
            VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
            return 1;
        }
    }

    /* The PCI AF Function Level Reset capability is
     * the same thing, except for conventional PCI
     * devices. This is not common yet.
     */
602
    pos = virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_AF);
603
    if (pos) {
604
        caps = virPCIDeviceRead16(dev, cfgfd, pos + PCI_AF_CAP);
605 606 607 608 609 610
        if (caps & PCI_AF_CAP_FLR) {
            VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
            return 1;
        }
    }

611 612 613 614 615 616
    /* there are some buggy devices that do support FLR, but forget to
     * advertise that fact in their capabilities.  However, FLR is *required*
     * to be present for virtual functions (VFs), so if we see that this
     * device is a VF, we just assume FLR works
     */

617
    if (virAsprintf(&path, PCI_SYSFS "devices/%s/physfn", dev->name) < 0)
618 619 620 621 622 623 624 625 626 627
        return -1;

    found = virFileExists(path);
    VIR_FREE(path);
    if (found) {
        VIR_DEBUG("%s %s: buggy device didn't advertise FLR, but is a VF; forcing flr on",
                  dev->id, dev->name);
        return 1;
    }

628 629 630 631 632 633 634 635 636
    VIR_DEBUG("%s %s: no FLR capability found", dev->id, dev->name);

    return 0;
}

/* Require the device has the PCI Power Management capability
 * and that a D3hot->D0 transition will results in a full
 * internal reset, not just a soft reset.
 */
637
static unsigned int
638
virPCIDeviceDetectPowerManagementReset(virPCIDevicePtr dev, int cfgfd)
639 640 641 642 643
{
    if (dev->pci_pm_cap_pos) {
        uint32_t ctl;

        /* require the NO_SOFT_RESET bit is clear */
644
        ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
645 646 647 648 649 650 651 652 653 654 655
        if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
            VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
            return 1;
        }
    }

    VIR_DEBUG("%s %s: no PM reset capability found", dev->id, dev->name);

    return 0;
}

656
/* Any active devices on the same domain/bus ? */
657
static int
658
virPCIDeviceSharesBusWithActive(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
659
{
660
    virPCIDeviceList *inactiveDevs = data;
661

662
    /* Different domain, different bus, or simply identical device */
663 664 665 666
    if (dev->address.domain != check->address.domain ||
        dev->address.bus != check->address.bus ||
        (dev->address.slot == check->address.slot &&
         dev->address.function == check->address.function))
667 668
        return 0;

669
    /* same bus, but inactive, i.e. about to be assigned to guest */
670
    if (inactiveDevs && virPCIDeviceListFind(inactiveDevs, check))
671
        return 0;
672

673
    return 1;
674 675
}

676 677 678
static virPCIDevicePtr
virPCIDeviceBusContainsActiveDevices(virPCIDevicePtr dev,
                                     virPCIDeviceList *inactiveDevs)
679
{
680 681 682
    virPCIDevicePtr active = NULL;
    if (virPCIDeviceIterDevices(virPCIDeviceSharesBusWithActive,
                                dev, &active, inactiveDevs) < 0)
683 684 685 686 687
        return NULL;
    return active;
}

/* Is @check the parent of @dev ? */
688
static int
689
virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
690 691 692
{
    uint16_t device_class;
    uint8_t header_type, secondary, subordinate;
693
    virPCIDevicePtr *best = data;
694 695
    int ret = 0;
    int fd;
696

697
    if (dev->address.domain != check->address.domain)
698 699
        return 0;

700
    if ((fd = virPCIDeviceConfigOpen(check, false)) < 0)
701 702
        return 0;

703
    /* Is it a bridge? */
704 705
    ret = virPCIDeviceReadClass(check, &device_class);
    if (ret < 0 || device_class != PCI_CLASS_BRIDGE_PCI)
706
        goto cleanup;
707 708

    /* Is it a plane? */
709
    header_type = virPCIDeviceRead8(check, fd, PCI_HEADER_TYPE);
710
    if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
711
        goto cleanup;
712

713 714
    secondary   = virPCIDeviceRead8(check, fd, PCI_SECONDARY_BUS);
    subordinate = virPCIDeviceRead8(check, fd, PCI_SUBORDINATE_BUS);
715

716
    VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
717

718 719 720
    /* if the secondary bus exactly equals the device's bus, then we found
     * the direct parent.  No further work is necessary
     */
721
    if (dev->address.bus == secondary) {
722 723 724
        ret = 1;
        goto cleanup;
    }
725

726
    /* otherwise, SRIOV allows VFs to be on different buses than their PFs.
727 728 729
     * In this case, what we need to do is look for the "best" match; i.e.
     * the most restrictive match that still satisfies all of the conditions.
     */
730
    if (dev->address.bus > secondary && dev->address.bus <= subordinate) {
731
        if (*best == NULL) {
732 733 734 735
            *best = virPCIDeviceNew(check->address.domain,
                                    check->address.bus,
                                    check->address.slot,
                                    check->address.function);
736 737 738 739 740
            if (*best == NULL) {
                ret = -1;
                goto cleanup;
            }
        } else {
741 742 743 744
            /* OK, we had already recorded a previous "best" match for the
             * parent.  See if the current device is more restrictive than the
             * best, and if so, make it the new best
             */
745 746 747
            int bestfd;
            uint8_t best_secondary;

748
            if ((bestfd = virPCIDeviceConfigOpen(*best, false)) < 0)
749
                goto cleanup;
750 751
            best_secondary = virPCIDeviceRead8(*best, bestfd, PCI_SECONDARY_BUS);
            virPCIDeviceConfigClose(*best, bestfd);
752 753

            if (secondary > best_secondary) {
754
                virPCIDeviceFree(*best);
755 756 757 758
                *best = virPCIDeviceNew(check->address.domain,
                                        check->address.bus,
                                        check->address.slot,
                                        check->address.function);
759 760 761 762
                if (*best == NULL) {
                    ret = -1;
                    goto cleanup;
                }
763 764 765 766
            }
        }
    }

767
 cleanup:
768
    virPCIDeviceConfigClose(check, fd);
769
    return ret;
770 771
}

772
static int
773
virPCIDeviceGetParent(virPCIDevicePtr dev, virPCIDevicePtr *parent)
774
{
775
    virPCIDevicePtr best = NULL;
776 777 778
    int ret;

    *parent = NULL;
779
    ret = virPCIDeviceIterDevices(virPCIDeviceIsParent, dev, parent, &best);
780
    if (ret == 1)
781
        virPCIDeviceFree(best);
782 783 784
    else if (ret == 0)
        *parent = best;
    return ret;
785 786 787 788 789 790
}

/* Secondary Bus Reset is our sledgehammer - it resets all
 * devices behind a bus.
 */
static int
791 792 793
virPCIDeviceTrySecondaryBusReset(virPCIDevicePtr dev,
                                 int cfgfd,
                                 virPCIDeviceList *inactiveDevs)
794
{
795
    virPCIDevicePtr parent, conflict;
796 797 798
    uint8_t config_space[PCI_CONF_LEN];
    uint16_t ctl;
    int ret = -1;
799
    int parentfd;
800

801 802 803
    /* Refuse to do a secondary bus reset if there are other
     * devices/functions behind the bus are used by the host
     * or other guests.
804
     */
805
    if ((conflict = virPCIDeviceBusContainsActiveDevices(dev, inactiveDevs))) {
806
        virReportError(VIR_ERR_INTERNAL_ERROR,
807 808
                       _("Active %s devices on bus with %s, not doing bus reset"),
                       conflict->name, dev->name);
W
Wang Rui 已提交
809
        virPCIDeviceFree(conflict);
810 811 812 813
        return -1;
    }

    /* Find the parent bus */
814
    if (virPCIDeviceGetParent(dev, &parent) < 0)
815
        return -1;
816
    if (!parent) {
817
        virReportError(VIR_ERR_INTERNAL_ERROR,
818 819
                       _("Failed to find parent device for %s"),
                       dev->name);
820 821
        return -1;
    }
822
    if ((parentfd = virPCIDeviceConfigOpen(parent, true)) < 0)
823
        goto out;
824 825 826 827 828 829 830

    VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);

    /* Save and restore the device's config space; we only do this
     * for the supplied device since we refuse to do a reset if there
     * are multiple devices/functions
     */
831
    if (virPCIDeviceRead(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
832
        virReportError(VIR_ERR_INTERNAL_ERROR,
833
                       _("Failed to read PCI config space for %s"),
834
                       dev->name);
835 836 837 838 839 840
        goto out;
    }

    /* Read the control register, set the reset flag, wait 200ms,
     * unset the reset flag and wait 200ms.
     */
841
    ctl = virPCIDeviceRead16(dev, cfgfd, PCI_BRIDGE_CONTROL);
842

843 844
    virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL,
                        ctl | PCI_BRIDGE_CTL_RESET);
845 846 847

    usleep(200 * 1000); /* sleep 200ms */

848
    virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, ctl);
849 850 851

    usleep(200 * 1000); /* sleep 200ms */

852
    if (virPCIDeviceWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
853
        virReportError(VIR_ERR_INTERNAL_ERROR,
854 855 856 857
                       _("Failed to restore PCI config space for %s"),
                       dev->name);
        goto out;
    }
858
    ret = 0;
859

860
 out:
861 862
    virPCIDeviceConfigClose(parent, parentfd);
    virPCIDeviceFree(parent);
863 864 865 866 867 868 869 870
    return ret;
}

/* Power management reset attempts to reset a device using a
 * D-state transition from D3hot to D0. Note, in detect_pm_reset()
 * above we require the device supports a full internal reset.
 */
static int
871
virPCIDeviceTryPowerManagementReset(virPCIDevicePtr dev, int cfgfd)
872 873 874 875 876 877 878 879
{
    uint8_t config_space[PCI_CONF_LEN];
    uint32_t ctl;

    if (!dev->pci_pm_cap_pos)
        return -1;

    /* Save and restore the device's config space. */
880
    if (virPCIDeviceRead(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
881
        virReportError(VIR_ERR_INTERNAL_ERROR,
882
                       _("Failed to read PCI config space for %s"),
883
                       dev->name);
884 885 886 887 888
        return -1;
    }

    VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);

889
    ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
890 891
    ctl &= ~PCI_PM_CTRL_STATE_MASK;

892 893
    virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
                        ctl | PCI_PM_CTRL_STATE_D3hot);
894 895 896

    usleep(10 * 1000); /* sleep 10ms */

897 898
    virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
                        ctl | PCI_PM_CTRL_STATE_D0);
899 900 901

    usleep(10 * 1000); /* sleep 10ms */

902
    if (virPCIDeviceWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
903
        virReportError(VIR_ERR_INTERNAL_ERROR,
904 905 906 907
                       _("Failed to restore PCI config space for %s"),
                       dev->name);
        return -1;
    }
908 909 910 911 912

    return 0;
}

static int
913
virPCIDeviceInit(virPCIDevicePtr dev, int cfgfd)
914
{
915 916
    int flr;

917 918 919
    dev->pcie_cap_pos   = virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP);
    dev->pci_pm_cap_pos = virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM);
    flr = virPCIDeviceDetectFunctionLevelReset(dev, cfgfd);
920
    if (flr < 0)
921
        return flr;
922 923
    dev->has_flr        = !!flr;
    dev->has_pm_reset   = !!virPCIDeviceDetectPowerManagementReset(dev, cfgfd);
924

925 926 927 928
    return 0;
}

int
929 930 931
virPCIDeviceReset(virPCIDevicePtr dev,
                  virPCIDeviceList *activeDevs,
                  virPCIDeviceList *inactiveDevs)
932
{
933 934
    char *drvPath = NULL;
    char *drvName = NULL;
935
    int ret = -1;
936
    int fd = -1;
937 938 939 940 941 942 943 944 945 946 947 948
    int hdrType = -1;

    if (virPCIGetHeaderType(dev, &hdrType) < 0)
        return -1;

    if (hdrType != VIR_PCI_HEADER_ENDPOINT) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid attempt to reset PCI device %s. "
                         "Only PCI endpoint devices can be reset"),
                       dev->name);
        return -1;
    }
949

950
    if (activeDevs && virPCIDeviceListFind(activeDevs, dev)) {
951
        virReportError(VIR_ERR_INTERNAL_ERROR,
952 953 954 955
                       _("Not resetting active device %s"), dev->name);
        return -1;
    }

956 957 958 959 960 961 962 963
    /* If the device is currently bound to vfio-pci, ignore all
     * requests to reset it, since the vfio-pci driver will always
     * reset it whenever appropriate, so doing it ourselves would just
     * be redundant.
     */
    if (virPCIDeviceGetDriverPathAndName(dev, &drvPath, &drvName) < 0)
        goto cleanup;

964
    if (virPCIStubDriverTypeFromString(drvName) == VIR_PCI_STUB_DRIVER_VFIO) {
965 966 967 968 969 970 971
        VIR_DEBUG("Device %s is bound to vfio-pci - skip reset",
                  dev->name);
        ret = 0;
        goto cleanup;
    }
    VIR_DEBUG("Resetting device %s", dev->name);

972
    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
973
        goto cleanup;
974

975
    if (virPCIDeviceInit(dev, fd) < 0)
976 977
        goto cleanup;

978 979 980
    /* KVM will perform FLR when starting and stopping
     * a guest, so there is no need for us to do it here.
     */
981 982 983 984
    if (dev->has_flr) {
        ret = 0;
        goto cleanup;
    }
985

986 987 988 989 990
    /* If the device supports PCI power management reset,
     * that's the next best thing because it only resets
     * the function, not the whole device.
     */
    if (dev->has_pm_reset)
991
        ret = virPCIDeviceTryPowerManagementReset(dev, fd);
992

993
    /* Bus reset is not an option with the root bus */
994
    if (ret < 0 && dev->address.bus != 0)
995
        ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
996

997 998
    if (ret < 0) {
        virErrorPtr err = virGetLastError();
999
        virReportError(VIR_ERR_INTERNAL_ERROR,
1000 1001
                       _("Unable to reset PCI device %s: %s"),
                       dev->name,
1002 1003
                       err ? err->message :
                       _("no FLR, PM reset or bus reset available"));
1004 1005
    }

1006
 cleanup:
1007 1008
    VIR_FREE(drvPath);
    VIR_FREE(drvName);
1009
    virPCIDeviceConfigClose(dev, fd);
1010 1011 1012
    return ret;
}

1013

1014
static int
1015
virPCIProbeStubDriver(virPCIStubDriver driver)
1016
{
1017
    const char *drvname = NULL;
1018
    char *drvpath = NULL;
1019
    bool probed = false;
1020

1021 1022 1023 1024 1025 1026 1027 1028
    if (driver == VIR_PCI_STUB_DRIVER_NONE ||
        !(drvname = virPCIStubDriverTypeToString(driver))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("Attempting to use unknown stub driver"));
        return -1;
    }

1029
 recheck:
1030
    if ((drvpath = virPCIDriverDir(drvname)) && virFileExists(drvpath)) {
1031
        /* driver already loaded, return */
1032
        VIR_FREE(drvpath);
1033
        return 0;
1034 1035 1036
    }

    VIR_FREE(drvpath);
1037 1038

    if (!probed) {
1039
        char *errbuf = NULL;
1040
        probed = true;
1041 1042
        if ((errbuf = virKModLoad(drvname, true))) {
            VIR_WARN("failed to load driver %s: %s", drvname, errbuf);
1043 1044
            VIR_FREE(errbuf);
            goto cleanup;
1045
        }
1046 1047

        goto recheck;
1048 1049
    }

1050
 cleanup:
1051 1052 1053
    /* If we know failure was because of blacklist, let's report that;
     * otherwise, report a more generic failure message
     */
1054
    if (virKModIsBlacklisted(drvname)) {
1055 1056 1057
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to load PCI stub module %s: "
                         "administratively prohibited"),
1058
                       drvname);
1059 1060 1061
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to load PCI stub module %s"),
1062
                       drvname);
1063 1064
    }

1065
    return -1;
1066 1067
}

1068
int
1069
virPCIDeviceUnbind(virPCIDevicePtr dev)
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
{
    char *path = NULL;
    char *drvpath = NULL;
    char *driver = NULL;
    int ret = -1;

    if (virPCIDeviceGetDriverPathAndName(dev, &drvpath, &driver) < 0)
        goto cleanup;

    if (!driver) {
        /* The device is not bound to any driver */
        ret = 0;
        goto cleanup;
    }

1085
    if (!(path = virPCIFile(dev->name, "driver/unbind")))
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
        goto cleanup;

    if (virFileExists(path)) {
        if (virFileWriteStr(path, dev->name, 0) < 0) {
            virReportSystemError(errno,
                                 _("Failed to unbind PCI device '%s' from %s"),
                                 dev->name, driver);
            goto cleanup;
        }
    }

    ret = 0;
1098
 cleanup:
1099 1100 1101 1102 1103 1104
    VIR_FREE(path);
    VIR_FREE(drvpath);
    VIR_FREE(driver);
    return ret;
}

1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129

/**
 * virPCIDeviceRebind:
 *  @dev: virPCIDevice object describing the device to rebind
 *
 * unbind a device from its driver, then immediately rebind it.
 *
 * Returns 0 on success, -1 on failure
 */
int virPCIDeviceRebind(virPCIDevicePtr dev)
{
    if (virPCIDeviceUnbind(dev) < 0)
        return -1;

    if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) {
        virReportSystemError(errno,
                             _("Failed to trigger a probe for PCI device '%s'"),
                             dev->name);
        return -1;
    }

    return 0;
}


1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
/*
 * Bind a PCI device to a driver using driver_override sysfs interface.
 * E.g.
 *
 *  echo driver-name > /sys/bus/pci/devices/0000:03:00.0/driver_override
 *  echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
 *  echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
 *
 * An empty driverName will cause the device to be bound to its
 * preferred driver.
 */
1141
static int
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
virPCIDeviceBindWithDriverOverride(virPCIDevicePtr dev,
                                   const char *driverName)
{
    int ret = -1;
    char *path;

    if (!(path = virPCIFile(dev->name, "driver_override")))
        return -1;

    if (virFileWriteStr(path, driverName, 0) < 0) {
        virReportSystemError(errno,
                             _("Failed to add driver '%s' to driver_override "
                               " interface of PCI device '%s'"),
                             driverName, dev->name);
        goto cleanup;
    }

1159
    if (virPCIDeviceRebind(dev) < 0)
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
        goto cleanup;

    ret = 0;

 cleanup:
    VIR_FREE(path);
    return ret;
}

static int
virPCIDeviceUnbindFromStubWithNewid(virPCIDevicePtr dev)
1171 1172 1173 1174
{
    int result = -1;
    char *drvdir = NULL;
    char *path = NULL;
1175
    char *driver = NULL;
1176

1177 1178 1179
    /* If the device is currently bound to one of the "well known"
     * stub drivers, then unbind it, otherwise ignore it.
     */
L
Laine Stump 已提交
1180
    if (virPCIDeviceGetDriverPathAndName(dev, &drvdir, &driver) < 0)
1181
        goto cleanup;
E
Eric Blake 已提交
1182

1183 1184
    if (!driver) {
        /* The device is not bound to any driver and we are almost done. */
1185
        VIR_DEBUG("PCI device %s is not bound to any driver", dev->name);
1186 1187 1188
        goto reprobe;
    }

1189 1190
    if (!dev->unbind_from_stub) {
        VIR_DEBUG("Unbind from stub skipped for PCI device %s", dev->name);
1191
        goto remove_slot;
1192
    }
1193

1194
    /* If the device isn't bound to a known stub, skip the unbind. */
1195
    if (virPCIStubDriverTypeFromString(driver) < 0 ||
1196 1197 1198
        virPCIStubDriverTypeFromString(driver) == VIR_PCI_STUB_DRIVER_NONE) {
        VIR_DEBUG("Unbind from stub skipped for PCI device %s because of "
                  "unknown stub driver", dev->name);
1199
        goto remove_slot;
1200
    }
1201

1202 1203
    VIR_DEBUG("Unbinding PCI device %s from stub driver %s",
              dev->name, driver);
1204

1205
    if (virPCIDeviceUnbind(dev) < 0)
1206
        goto cleanup;
1207
    dev->unbind_from_stub = false;
1208

1209
 remove_slot:
1210 1211
    if (!dev->remove_slot) {
        VIR_DEBUG("Slot removal skipped for PCI device %s", dev->name);
1212
        goto reprobe;
1213 1214 1215
    }

    VIR_DEBUG("Removing slot for PCI device %s", dev->name);
1216 1217

    /* Xen's pciback.ko wants you to use remove_slot on the specific device */
1218
    if (!(path = virPCIDriverFile(driver, "remove_slot")))
1219 1220 1221 1222
        goto cleanup;

    if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
        virReportSystemError(errno,
1223
                             _("Failed to remove slot for PCI device '%s' from %s"),
1224 1225 1226
                             dev->name, driver);
        goto cleanup;
    }
1227
    dev->remove_slot = false;
1228

1229
 reprobe:
1230
    if (!dev->reprobe) {
1231
        VIR_DEBUG("Reprobe skipped for PCI device %s", dev->name);
1232 1233 1234
        result = 0;
        goto cleanup;
    }
1235

1236 1237
    VIR_DEBUG("Reprobing for PCI device %s", dev->name);

1238 1239 1240 1241 1242
    /* Trigger a re-probe of the device is not in the stub's dynamic
     * ID table. If the stub is available, but 'remove_id' isn't
     * available, then re-probing would just cause the device to be
     * re-bound to the stub.
     */
1243 1244
    VIR_FREE(path);
    if (driver && !(path = virPCIDriverFile(driver, "remove_id")))
1245 1246
        goto cleanup;

1247
    if (!driver || !virFileExists(drvdir) || virFileExists(path)) {
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
        if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) {
            virReportSystemError(errno,
                                 _("Failed to trigger a re-probe for PCI device '%s'"),
                                 dev->name);
            goto cleanup;
        }
    }

    result = 0;

1258
 cleanup:
1259
    /* do not do it again */
1260 1261 1262
    dev->unbind_from_stub = false;
    dev->remove_slot = false;
    dev->reprobe = false;
1263

1264 1265
    VIR_FREE(drvdir);
    VIR_FREE(path);
1266
    VIR_FREE(driver);
1267 1268 1269 1270

    return result;
}

1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
static int
virPCIDeviceUnbindFromStubWithOverride(virPCIDevicePtr dev)
{
    if (!dev->unbind_from_stub) {
        VIR_DEBUG("Unbind from stub skipped for PCI device %s", dev->name);
        return 0;
    }

    return virPCIDeviceBindWithDriverOverride(dev, "\n");
}
1281 1282

static int
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
virPCIDeviceUnbindFromStub(virPCIDevicePtr dev)
{
    int ret;
    char *path;

    /*
     * Prefer using the device's driver_override interface, falling back
     * to the unpleasant new_id interface.
     */
    if (!(path = virPCIFile(dev->name, "driver_override")))
        return -1;

    if (virFileExists(path))
        ret = virPCIDeviceUnbindFromStubWithOverride(dev);
    else
        ret = virPCIDeviceUnbindFromStubWithNewid(dev);

    VIR_FREE(path);
    return ret;
}

static int
virPCIDeviceBindToStubWithNewid(virPCIDevicePtr dev)
1306
{
1307
    int result = -1;
E
Eric Blake 已提交
1308
    bool reprobe = false;
1309 1310 1311
    char *stubDriverPath = NULL;
    char *driverLink = NULL;
    char *path = NULL; /* reused for different purposes */
1312
    const char *stubDriverName = NULL;
J
Jiri Denemark 已提交
1313
    virErrorPtr err = NULL;
1314

1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
    /* Check the device is configured to use one of the known stub drivers */
    if (dev->stubDriver == VIR_PCI_STUB_DRIVER_NONE) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No stub driver configured for PCI device %s"),
                       dev->name);
        return -1;
    } else if (!(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriver))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown stub driver configured for PCI device %s"),
                       dev->name);
        return -1;
    }

1328
    if (!(stubDriverPath = virPCIDriverDir(stubDriverName))  ||
1329
        !(driverLink = virPCIFile(dev->name, "driver")))
1330 1331
        goto cleanup;

1332 1333 1334 1335 1336
    if (virFileExists(driverLink)) {
        if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
            /* The device is already bound to the correct driver */
            VIR_DEBUG("Device %s is already bound to %s",
                      dev->name, stubDriverName);
1337 1338 1339
            result = 0;
            goto cleanup;
        }
1340
        reprobe = true;
1341
    }
1342 1343 1344 1345 1346 1347 1348 1349 1350

    /* Add the PCI device ID to the stub's dynamic ID table;
     * this is needed to allow us to bind the device to the stub.
     * Note: if the device is not currently bound to any driver,
     * stub will immediately be bound to the device. Also, note
     * that if a new device with this ID is hotplugged, or if a probe
     * is triggered for such a device, it will also be immediately
     * bound by the stub.
     */
1351
    if (!(path = virPCIDriverFile(stubDriverName, "new_id")))
1352
        goto cleanup;
1353

1354
    if (virFileWriteStr(path, dev->id, 0) < 0) {
1355
        virReportSystemError(errno,
1356
                             _("Failed to add PCI device ID '%s' to %s"),
1357
                             dev->id, stubDriverName);
1358
        goto cleanup;
1359 1360
    }

1361
    /* check whether the device is bound to pci-stub when we write dev->id to
1362
     * ${stubDriver}/new_id.
1363
     */
1364
    if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
1365 1366
        dev->unbind_from_stub = true;
        dev->remove_slot = true;
J
Jiri Denemark 已提交
1367
        result = 0;
1368 1369 1370
        goto remove_id;
    }

1371
    if (virPCIDeviceUnbind(dev) < 0)
J
Jiri Denemark 已提交
1372
        goto remove_id;
1373

1374 1375 1376
    /* If the device was bound to a driver we'll need to reprobe later */
    dev->reprobe = reprobe;

1377 1378
    /* If the device isn't already bound to pci-stub, try binding it now.
     */
1379
    if (!virFileLinkPointsTo(driverLink, stubDriverPath)) {
1380
        /* Xen's pciback.ko wants you to use new_slot first */
1381 1382
        VIR_FREE(path);
        if (!(path = virPCIDriverFile(stubDriverName, "new_slot")))
1383
            goto remove_id;
1384

1385
        if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
1386
            virReportSystemError(errno,
1387 1388 1389
                                 _("Failed to add slot for "
                                   "PCI device '%s' to %s"),
                                 dev->name, stubDriverName);
1390
            goto remove_id;
1391
        }
1392
        dev->remove_slot = true;
1393

1394 1395
        VIR_FREE(path);
        if (!(path = virPCIDriverFile(stubDriverName, "bind")))
1396
            goto remove_id;
1397

1398
        if (virFileWriteStr(path, dev->name, 0) < 0) {
1399
            virReportSystemError(errno,
1400
                                 _("Failed to bind PCI device '%s' to %s"),
1401
                                 dev->name, stubDriverName);
1402
            goto remove_id;
1403
        }
1404
        dev->unbind_from_stub = true;
1405 1406
    }

J
Jiri Denemark 已提交
1407 1408
    result = 0;

1409
 remove_id:
J
Jiri Denemark 已提交
1410 1411
    err = virSaveLastError();

1412 1413 1414
    /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
     * ID table so that 'drivers_probe' works below.
     */
1415 1416
    VIR_FREE(path);
    if (!(path = virPCIDriverFile(stubDriverName, "remove_id"))) {
E
Eric Blake 已提交
1417
        /* We do not remove PCI ID from pci-stub, and we cannot reprobe it */
1418 1419
        if (dev->reprobe) {
            VIR_WARN("Could not remove PCI ID '%s' from %s, and the device "
1420
                     "cannot be probed again.", dev->id, stubDriverName);
1421
        }
1422
        dev->reprobe = false;
J
Jiri Denemark 已提交
1423
        result = -1;
1424 1425 1426
        goto cleanup;
    }

1427
    if (virFileExists(path) && virFileWriteStr(path, dev->id, 0) < 0) {
1428
        virReportSystemError(errno,
1429
                             _("Failed to remove PCI ID '%s' from %s"),
1430
                             dev->id, stubDriverName);
1431

E
Eric Blake 已提交
1432
        /* remove PCI ID from pci-stub failed, and we cannot reprobe it */
1433 1434
        if (dev->reprobe) {
            VIR_WARN("Failed to remove PCI ID '%s' from %s, and the device "
1435
                     "cannot be probed again.", dev->id, stubDriverName);
1436
        }
1437
        dev->reprobe = false;
J
Jiri Denemark 已提交
1438
        result = -1;
1439
        goto cleanup;
1440 1441
    }

1442
 cleanup:
1443 1444
    VIR_FREE(stubDriverPath);
    VIR_FREE(driverLink);
1445 1446
    VIR_FREE(path);

1447
    if (result < 0)
J
Jiri Denemark 已提交
1448 1449 1450 1451 1452
        virPCIDeviceUnbindFromStub(dev);

    if (err)
        virSetError(err);
    virFreeError(err);
1453

1454
    return result;
1455 1456
}

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
static int
virPCIDeviceBindToStubWithOverride(virPCIDevicePtr dev)
{
    int ret = -1;
    const char *stubDriverName;
    char *stubDriverPath = NULL;
    char *driverLink = NULL;

    /* Check the device is configured to use one of the known stub drivers */
    if (dev->stubDriver == VIR_PCI_STUB_DRIVER_NONE) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No stub driver configured for PCI device %s"),
                       dev->name);
        return -1;
    } else if (!(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriver))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown stub driver configured for PCI device %s"),
                       dev->name);
        return -1;
    }

    if (!(stubDriverPath = virPCIDriverDir(stubDriverName))  ||
        !(driverLink = virPCIFile(dev->name, "driver")))
        goto cleanup;

    if (virFileExists(driverLink)) {
        if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
            /* The device is already bound to the correct driver */
            VIR_DEBUG("Device %s is already bound to %s",
                      dev->name, stubDriverName);
            ret = 0;
            goto cleanup;
        }
    }

    if (virPCIDeviceBindWithDriverOverride(dev, stubDriverName) < 0)
        goto cleanup;

    dev->unbind_from_stub = true;
    ret = 0;

 cleanup:
    VIR_FREE(stubDriverPath);
    VIR_FREE(driverLink);
    return ret;
}

static int
virPCIDeviceBindToStub(virPCIDevicePtr dev)
{
    int ret;
    char *path;

    /*
     * Prefer using the device's driver_override interface, falling back
     * to the unpleasant new_id interface.
     */
    if (!(path = virPCIFile(dev->name, "driver_override")))
        return -1;

    if (virFileExists(path))
        ret = virPCIDeviceBindToStubWithOverride(dev);
    else
        ret = virPCIDeviceBindToStubWithNewid(dev);

    VIR_FREE(path);
    return ret;
}

1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
/* virPCIDeviceDetach:
 *
 * Detach this device from the host driver, attach it to the stub
 * driver (previously set with virPCIDeviceSetStubDriver(), and add *a
 * copy* of the object to the inactiveDevs list (if provided). This
 * function will *never* consume dev, so the caller should free it.
 *
 * Returns 0 on success, -1 on failure (will fail if the device is
 * already in the activeDevs list, but will be a NOP if the device is
 * already bound to the stub).
 *
 * GENERAL NOTE: activeDevs should be a list of all PCI devices
 * currently in use by a domain. inactiveDevs is a list of all PCI
 * devices that libvirt has detached from the host driver + attached
 * to the stub driver, but hasn't yet assigned to a domain. Any device
 * that is still attached to its host driver should not be on either
 * list.
 */
1544
int
1545 1546
virPCIDeviceDetach(virPCIDevicePtr dev,
                   virPCIDeviceList *activeDevs,
1547
                   virPCIDeviceList *inactiveDevs)
1548
{
1549
    if (virPCIProbeStubDriver(dev->stubDriver) < 0)
1550 1551
        return -1;

1552
    if (activeDevs && virPCIDeviceListFind(activeDevs, dev)) {
1553
        virReportError(VIR_ERR_INTERNAL_ERROR,
1554 1555 1556 1557
                       _("Not detaching active device %s"), dev->name);
        return -1;
    }

1558
    if (virPCIDeviceBindToStub(dev) < 0)
1559 1560
        return -1;

1561 1562 1563
    /* Add *a copy of* the dev into list inactiveDevs, if
     * it's not already there.
     */
1564 1565 1566 1567
    if (inactiveDevs && !virPCIDeviceListFind(inactiveDevs, dev)) {
        VIR_DEBUG("Adding PCI device %s to inactive list", dev->name);
        if (virPCIDeviceListAddCopy(inactiveDevs, dev) < 0)
            return -1;
1568 1569 1570
    }

    return 0;
1571 1572 1573
}

int
1574 1575
virPCIDeviceReattach(virPCIDevicePtr dev,
                     virPCIDeviceListPtr activeDevs,
1576
                     virPCIDeviceListPtr inactiveDevs)
1577
{
1578
    if (activeDevs && virPCIDeviceListFind(activeDevs, dev)) {
1579
        virReportError(VIR_ERR_INTERNAL_ERROR,
1580 1581 1582 1583
                       _("Not reattaching active device %s"), dev->name);
        return -1;
    }

1584
    if (virPCIDeviceUnbindFromStub(dev) < 0)
1585 1586 1587
        return -1;

    /* Steal the dev from list inactiveDevs */
1588 1589
    if (inactiveDevs) {
        VIR_DEBUG("Removing PCI device %s from inactive list", dev->name);
1590
        virPCIDeviceListDel(inactiveDevs, dev);
1591
    }
1592 1593

    return 0;
1594 1595
}

1596 1597 1598 1599 1600
/* Certain hypervisors (like qemu/kvm) map the PCI bar(s) on
 * the host when doing device passthrough.  This can lead to a race
 * condition where the hypervisor is still cleaning up the device while
 * libvirt is trying to re-attach it to the host device driver.  To avoid
 * this situation, we look through /proc/iomem, and if the hypervisor is
E
Eric Blake 已提交
1601 1602
 * still holding on to the bar (denoted by the string in the matcher
 * variable), then we can wait around a bit for that to clear up.
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
 *
 * A typical /proc/iomem looks like this (snipped for brevity):
 * 00010000-0008efff : System RAM
 * 0008f000-0008ffff : reserved
 * ...
 * 00100000-cc9fcfff : System RAM
 *   00200000-00483d3b : Kernel code
 *   00483d3c-005c88df : Kernel data
 * cc9fd000-ccc71fff : ACPI Non-volatile Storage
 * ...
 * d0200000-d02fffff : PCI Bus #05
 *   d0200000-d021ffff : 0000:05:00.0
 *     d0200000-d021ffff : e1000e
 *   d0220000-d023ffff : 0000:05:00.0
 *     d0220000-d023ffff : e1000e
 * ...
 * f0000000-f0003fff : 0000:00:1b.0
 *   f0000000-f0003fff : kvm_assigned_device
 *
 * Returns 0 if we are clear to continue, and 1 if the hypervisor is still
E
Eric Blake 已提交
1623
 * holding on to the resource.
1624 1625
 */
int
1626
virPCIDeviceWaitForCleanup(virPCIDevicePtr dev, const char *matcher)
1627 1628 1629
{
    FILE *fp;
    char line[160];
1630
    char *tmp;
1631
    unsigned long long start, end;
1632
    unsigned int domain, bus, slot, function;
1633
    bool in_matching_device;
1634 1635 1636 1637 1638 1639 1640 1641 1642
    int ret;
    size_t match_depth;

    fp = fopen("/proc/iomem", "r");
    if (!fp) {
        /* If we failed to open iomem, we just basically ignore the error.  The
         * unbind might succeed anyway, and besides, it's very likely we have
         * no way to report the error
         */
1643
        VIR_DEBUG("Failed to open /proc/iomem, trying to continue anyway");
1644 1645 1646 1647
        return 0;
    }

    ret = 0;
1648
    in_matching_device = false;
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
    match_depth = 0;
    while (fgets(line, sizeof(line), fp) != 0) {
        /* the logic here is a bit confusing.  For each line, we look to
         * see if it matches the domain:bus:slot.function we were given.
         * If this line matches the DBSF, then any subsequent lines indented
         * by 2 spaces are the PCI regions for this device.  It's also
         * possible that none of the PCI regions are currently mapped, in
         * which case we have no indented regions.  This code handles all
         * of these situations
         */
        if (in_matching_device && (strspn(line, " ") == (match_depth + 2))) {
1660 1661 1662 1663 1664 1665
            /* expected format: <start>-<end> : <suffix> */
            if (/* start */
                virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' ||
                /* end */
                virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 ||
                (tmp = STRSKIP(tmp, " : ")) == NULL)
1666 1667
                continue;

1668
            if (STRPREFIX(tmp, matcher)) {
1669 1670 1671
                ret = 1;
                break;
            }
1672
        } else {
1673
            in_matching_device = false;
1674

1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
            /* expected format: <start>-<end> : <domain>:<bus>:<slot>.<function> */
            if (/* start */
                virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' ||
                /* end */
                virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 ||
                (tmp = STRSKIP(tmp, " : ")) == NULL ||
                /* domain */
                virStrToLong_ui(tmp, &tmp, 16, &domain) < 0 || *tmp != ':' ||
                /* bus */
                virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' ||
                /* slot */
                virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' ||
                /* function */
                virStrToLong_ui(tmp + 1, &tmp, 16, &function) < 0 || *tmp != '\n')
1689 1690
                continue;

1691 1692
            if (domain != dev->address.domain || bus != dev->address.bus ||
                slot != dev->address.slot || function != dev->address.function)
1693
                continue;
1694
            in_matching_device = true;
1695 1696 1697 1698
            match_depth = strspn(line, " ");
        }
    }

E
Eric Blake 已提交
1699
    VIR_FORCE_FCLOSE(fp);
1700 1701 1702 1703

    return ret;
}

1704
static char *
1705
virPCIDeviceReadID(virPCIDevicePtr dev, const char *id_name)
1706
{
1707
    char *path = NULL;
1708 1709
    char *id_str;

1710
    if (!(path = virPCIFile(dev->name, id_name)))
1711
        return NULL;
1712 1713

    /* ID string is '0xNNNN\n' ... i.e. 7 bytes */
1714 1715
    if (virFileReadAll(path, 7, &id_str) < 0) {
        VIR_FREE(path);
1716
        return NULL;
1717 1718 1719
    }

    VIR_FREE(path);
1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732

    /* Check for 0x suffix */
    if (id_str[0] != '0' || id_str[1] != 'x') {
        VIR_FREE(id_str);
        return NULL;
    }

    /* Chop off the newline; we know the string is 7 bytes */
    id_str[6] = '\0';

    return id_str;
}

1733
int
1734 1735 1736 1737
virPCIGetAddrString(unsigned int domain,
                    unsigned int bus,
                    unsigned int slot,
                    unsigned int function,
1738
                    char **pciConfigAddr)
1739
{
1740
    virPCIDevicePtr dev = NULL;
1741 1742
    int ret = -1;

1743
    dev = virPCIDeviceNew(domain, bus, slot, function);
1744
    if (dev != NULL) {
1745
        if (VIR_STRDUP(*pciConfigAddr, dev->name) < 0)
1746 1747 1748 1749
            goto cleanup;
        ret = 0;
    }

1750
 cleanup:
1751
    virPCIDeviceFree(dev);
1752 1753 1754
    return ret;
}

1755
virPCIDevicePtr
1756 1757 1758 1759
virPCIDeviceNew(unsigned int domain,
                unsigned int bus,
                unsigned int slot,
                unsigned int function)
1760
{
1761
    virPCIDevicePtr dev;
E
Eric Blake 已提交
1762 1763
    char *vendor = NULL;
    char *product = NULL;
1764

1765
    if (VIR_ALLOC(dev) < 0)
1766 1767
        return NULL;

1768 1769 1770 1771
    dev->address.domain = domain;
    dev->address.bus = bus;
    dev->address.slot = slot;
    dev->address.function = function;
1772

E
Eric Blake 已提交
1773
    if (snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x",
1774
                 domain, bus, slot, function) >= sizeof(dev->name)) {
1775
        virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
1776
                       _("dev->name buffer overflow: %.4x:%.2x:%.2x.%.1x"),
1777
                       domain, bus, slot, function);
E
Eric Blake 已提交
1778
        goto error;
E
Eric Blake 已提交
1779 1780
    }
    if (virAsprintf(&dev->path, PCI_SYSFS "devices/%s/config",
1781
                    dev->name) < 0)
E
Eric Blake 已提交
1782
        goto error;
1783

1784
    if (!virFileExists(dev->path)) {
1785 1786 1787
        virReportSystemError(errno,
                             _("Device %s not found: could not access %s"),
                             dev->name, dev->path);
E
Eric Blake 已提交
1788
        goto error;
1789 1790
    }

1791 1792
    vendor  = virPCIDeviceReadID(dev, "vendor");
    product = virPCIDeviceReadID(dev, "device");
1793 1794

    if (!vendor || !product) {
1795
        virReportError(VIR_ERR_INTERNAL_ERROR,
1796 1797
                       _("Failed to read product/vendor ID for %s"),
                       dev->name);
E
Eric Blake 已提交
1798
        goto error;
1799 1800 1801
    }

    /* strings contain '0x' prefix */
E
Eric Blake 已提交
1802 1803
    if (snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2],
                 &product[2]) >= sizeof(dev->id)) {
1804
        virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
1805 1806
                       _("dev->id buffer overflow: %s %s"),
                       &vendor[2], &product[2]);
E
Eric Blake 已提交
1807
        goto error;
E
Eric Blake 已提交
1808
    }
1809 1810 1811

    VIR_DEBUG("%s %s: initialized", dev->id, dev->name);

1812
 cleanup:
E
Eric Blake 已提交
1813 1814
    VIR_FREE(product);
    VIR_FREE(vendor);
1815
    return dev;
E
Eric Blake 已提交
1816

1817
 error:
1818
    virPCIDeviceFree(dev);
E
Eric Blake 已提交
1819 1820
    dev = NULL;
    goto cleanup;
1821 1822
}

L
Laine Stump 已提交
1823 1824 1825 1826 1827 1828

virPCIDevicePtr
virPCIDeviceCopy(virPCIDevicePtr dev)
{
    virPCIDevicePtr copy;

1829
    if (VIR_ALLOC(copy) < 0)
L
Laine Stump 已提交
1830 1831 1832 1833
        return NULL;

    /* shallow copy to take care of most attributes */
    *copy = *dev;
1834
    copy->path = NULL;
C
Chunyan Liu 已提交
1835
    copy->used_by_drvname = copy->used_by_domname = NULL;
L
Laine Stump 已提交
1836
    if (VIR_STRDUP(copy->path, dev->path) < 0 ||
C
Chunyan Liu 已提交
1837 1838
        VIR_STRDUP(copy->used_by_drvname, dev->used_by_drvname) < 0 ||
        VIR_STRDUP(copy->used_by_domname, dev->used_by_domname) < 0) {
L
Laine Stump 已提交
1839 1840 1841 1842
        goto error;
    }
    return copy;

1843
 error:
L
Laine Stump 已提交
1844 1845 1846 1847 1848
    virPCIDeviceFree(copy);
    return NULL;
}


1849
void
1850
virPCIDeviceFree(virPCIDevicePtr dev)
1851
{
1852 1853
    if (!dev)
        return;
1854
    VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
E
Eric Blake 已提交
1855
    VIR_FREE(dev->path);
C
Chunyan Liu 已提交
1856 1857
    VIR_FREE(dev->used_by_drvname);
    VIR_FREE(dev->used_by_domname);
1858 1859
    VIR_FREE(dev);
}
1860

1861 1862 1863 1864 1865
/**
 * virPCIDeviceGetAddress:
 * @dev: device to get address from
 *
 * Take a PCI device on input and return its PCI address. The
1866
 * returned object is owned by the device and must not be freed.
1867
 *
1868
 * Returns: a pointer to the address, which can never be NULL.
1869 1870 1871 1872
 */
virPCIDeviceAddressPtr
virPCIDeviceGetAddress(virPCIDevicePtr dev)
{
1873
    return &(dev->address);
1874 1875
}

1876
const char *
1877
virPCIDeviceGetName(virPCIDevicePtr dev)
1878 1879 1880 1881
{
    return dev->name;
}

1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893
/**
 * virPCIDeviceGetConfigPath:
 *
 * Returns a pointer to a string containing the path of @dev's PCI
 * config file.
 */
const char *
virPCIDeviceGetConfigPath(virPCIDevicePtr dev)
{
    return dev->path;
}

1894
void virPCIDeviceSetManaged(virPCIDevicePtr dev, bool managed)
1895
{
1896
    dev->managed = managed;
1897 1898
}

1899
bool
1900
virPCIDeviceGetManaged(virPCIDevicePtr dev)
1901 1902 1903 1904
{
    return dev->managed;
}

1905 1906
void
virPCIDeviceSetStubDriver(virPCIDevicePtr dev, virPCIStubDriver driver)
1907
{
1908
    dev->stubDriver = driver;
1909 1910
}

1911
virPCIStubDriver
1912 1913 1914 1915 1916
virPCIDeviceGetStubDriver(virPCIDevicePtr dev)
{
    return dev->stubDriver;
}

1917
bool
1918
virPCIDeviceGetUnbindFromStub(virPCIDevicePtr dev)
1919 1920 1921 1922 1923
{
    return dev->unbind_from_stub;
}

void
1924
virPCIDeviceSetUnbindFromStub(virPCIDevicePtr dev, bool unbind)
1925
{
1926
    dev->unbind_from_stub = unbind;
1927 1928
}

1929
bool
1930
virPCIDeviceGetRemoveSlot(virPCIDevicePtr dev)
1931 1932 1933 1934 1935
{
    return dev->remove_slot;
}

void
1936
virPCIDeviceSetRemoveSlot(virPCIDevicePtr dev, bool remove_slot)
1937
{
1938
    dev->remove_slot = remove_slot;
1939 1940
}

1941
bool
1942
virPCIDeviceGetReprobe(virPCIDevicePtr dev)
1943 1944 1945 1946 1947
{
    return dev->reprobe;
}

void
1948
virPCIDeviceSetReprobe(virPCIDevicePtr dev, bool reprobe)
1949
{
1950
    dev->reprobe = reprobe;
1951 1952
}

C
Chunyan Liu 已提交
1953 1954 1955 1956
int
virPCIDeviceSetUsedBy(virPCIDevicePtr dev,
                      const char *drv_name,
                      const char *dom_name)
1957
{
C
Chunyan Liu 已提交
1958 1959 1960 1961 1962 1963 1964 1965
    VIR_FREE(dev->used_by_drvname);
    VIR_FREE(dev->used_by_domname);
    if (VIR_STRDUP(dev->used_by_drvname, drv_name) < 0)
        return -1;
    if (VIR_STRDUP(dev->used_by_domname, dom_name) < 0)
        return -1;

    return 0;
1966 1967
}

C
Chunyan Liu 已提交
1968 1969 1970 1971
void
virPCIDeviceGetUsedBy(virPCIDevicePtr dev,
                      const char **drv_name,
                      const char **dom_name)
1972
{
C
Chunyan Liu 已提交
1973 1974
    *drv_name = dev->used_by_drvname;
    *dom_name = dev->used_by_domname;
1975 1976
}

1977 1978
virPCIDeviceListPtr
virPCIDeviceListNew(void)
1979
{
1980
    virPCIDeviceListPtr list;
1981

1982 1983 1984 1985
    if (virPCIInitialize() < 0)
        return NULL;

    if (!(list = virObjectLockableNew(virPCIDeviceListClass)))
1986 1987 1988 1989 1990
        return NULL;

    return list;
}

1991 1992
static void
virPCIDeviceListDispose(void *obj)
1993
{
1994
    virPCIDeviceListPtr list = obj;
1995
    size_t i;
1996 1997

    for (i = 0; i < list->count; i++) {
1998
        virPCIDeviceFree(list->devs[i]);
1999 2000 2001 2002 2003 2004 2005 2006
        list->devs[i] = NULL;
    }

    list->count = 0;
    VIR_FREE(list->devs);
}

int
2007 2008
virPCIDeviceListAdd(virPCIDeviceListPtr list,
                    virPCIDevicePtr dev)
2009
{
2010
    if (virPCIDeviceListFind(list, dev)) {
2011
        virReportError(VIR_ERR_INTERNAL_ERROR,
2012 2013 2014
                       _("Device %s is already in use"), dev->name);
        return -1;
    }
2015
    return VIR_APPEND_ELEMENT(list->devs, list->count, dev);
2016 2017
}

L
Laine Stump 已提交
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034

/* virPCIDeviceListAddCopy - add a *copy* of the device to this list */
int
virPCIDeviceListAddCopy(virPCIDeviceListPtr list, virPCIDevicePtr dev)
{
    virPCIDevicePtr copy = virPCIDeviceCopy(dev);

    if (!copy)
        return -1;
    if (virPCIDeviceListAdd(list, copy) < 0) {
        virPCIDeviceFree(copy);
        return -1;
    }
    return 0;
}


2035 2036 2037
virPCIDevicePtr
virPCIDeviceListGet(virPCIDeviceListPtr list,
                    int idx)
2038 2039 2040 2041 2042 2043 2044 2045 2046
{
    if (idx >= list->count)
        return NULL;
    if (idx < 0)
        return NULL;

    return list->devs[idx];
}

2047
size_t
2048
virPCIDeviceListCount(virPCIDeviceListPtr list)
2049
{
2050 2051 2052
    return list->count;
}

2053 2054 2055
virPCIDevicePtr
virPCIDeviceListStealIndex(virPCIDeviceListPtr list,
                           int idx)
2056
{
2057
    virPCIDevicePtr ret;
2058

2059 2060
    if (idx < 0 || idx >= list->count)
        return NULL;
2061

2062
    ret = list->devs[idx];
2063
    VIR_DELETE_ELEMENT(list->devs, idx, list->count);
2064 2065 2066
    return ret;
}

2067 2068 2069
virPCIDevicePtr
virPCIDeviceListSteal(virPCIDeviceListPtr list,
                      virPCIDevicePtr dev)
2070
{
2071
    return virPCIDeviceListStealIndex(list, virPCIDeviceListFindIndex(list, dev));
2072 2073
}

2074
void
2075 2076
virPCIDeviceListDel(virPCIDeviceListPtr list,
                    virPCIDevicePtr dev)
2077
{
2078
    virPCIDevicePtr ret = virPCIDeviceListSteal(list, dev);
2079
    virPCIDeviceFree(ret);
2080 2081
}

2082
int
2083
virPCIDeviceListFindIndex(virPCIDeviceListPtr list, virPCIDevicePtr dev)
2084
{
2085
    size_t i;
2086

2087 2088 2089 2090 2091 2092
    for (i = 0; i < list->count; i++) {
        virPCIDevicePtr other = list->devs[i];
        if (other->address.domain   == dev->address.domain &&
            other->address.bus      == dev->address.bus    &&
            other->address.slot     == dev->address.slot   &&
            other->address.function == dev->address.function)
2093
            return i;
2094
    }
2095 2096 2097
    return -1;
}

L
Laine Stump 已提交
2098 2099 2100 2101 2102 2103 2104 2105

virPCIDevicePtr
virPCIDeviceListFindByIDs(virPCIDeviceListPtr list,
                          unsigned int domain,
                          unsigned int bus,
                          unsigned int slot,
                          unsigned int function)
{
2106
    size_t i;
L
Laine Stump 已提交
2107 2108

    for (i = 0; i < list->count; i++) {
2109 2110 2111 2112 2113
        virPCIDevicePtr other = list->devs[i];
        if (other->address.domain   == domain &&
            other->address.bus      == bus    &&
            other->address.slot     == slot   &&
            other->address.function == function)
L
Laine Stump 已提交
2114 2115 2116 2117 2118 2119
            return list->devs[i];
    }
    return NULL;
}


2120 2121
virPCIDevicePtr
virPCIDeviceListFind(virPCIDeviceListPtr list, virPCIDevicePtr dev)
2122
{
2123
    int idx;
2124

2125 2126
    if ((idx = virPCIDeviceListFindIndex(list, dev)) >= 0)
        return list->devs[idx];
2127 2128
    else
        return NULL;
2129
}
2130 2131


2132 2133 2134
int virPCIDeviceFileIterate(virPCIDevicePtr dev,
                            virPCIDeviceFileActor actor,
                            void *opaque)
2135 2136 2137 2138 2139 2140
{
    char *pcidir = NULL;
    char *file = NULL;
    DIR *dir = NULL;
    int ret = -1;
    struct dirent *ent;
E
Eric Blake 已提交
2141
    int direrr;
2142 2143

    if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
2144 2145
                    dev->address.domain, dev->address.bus,
                    dev->address.slot, dev->address.function) < 0)
2146 2147
        goto cleanup;

J
Ján Tomko 已提交
2148
    if (virDirOpen(&dir, pcidir) < 0)
2149 2150
        goto cleanup;

E
Eric Blake 已提交
2151
    while ((direrr = virDirRead(dir, &ent, pcidir)) > 0) {
2152
        /* Device assignment requires:
A
Alex Williamson 已提交
2153
         *   $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN,
2154
         *   $PCIDIR/rom, $PCIDIR/reset, $PCIDIR/vendor, $PCIDIR/device
2155 2156 2157
         */
        if (STREQ(ent->d_name, "config") ||
            STRPREFIX(ent->d_name, "resource") ||
A
Alex Williamson 已提交
2158
            STREQ(ent->d_name, "rom") ||
2159 2160
            STREQ(ent->d_name, "vendor") ||
            STREQ(ent->d_name, "device") ||
A
Alex Williamson 已提交
2161
            STREQ(ent->d_name, "reset")) {
2162
            if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0)
2163
                goto cleanup;
2164
            if ((actor)(dev, file, opaque) < 0)
2165 2166 2167 2168 2169
                goto cleanup;

            VIR_FREE(file);
        }
    }
E
Eric Blake 已提交
2170 2171
    if (direrr < 0)
        goto cleanup;
2172 2173 2174

    ret = 0;

2175
 cleanup:
J
Ján Tomko 已提交
2176
    VIR_DIR_CLOSE(dir);
2177 2178 2179 2180
    VIR_FREE(file);
    VIR_FREE(pcidir);
    return ret;
}
J
Jiri Denemark 已提交
2181

L
Laine Stump 已提交
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196

/* virPCIDeviceAddressIOMMUGroupIterate:
 *   Call @actor for all devices in the same iommu_group as orig
 *   (including orig itself) Even if there is no iommu_group for the
 *   device, call @actor once for orig.
 */
int
virPCIDeviceAddressIOMMUGroupIterate(virPCIDeviceAddressPtr orig,
                                     virPCIDeviceAddressActor actor,
                                     void *opaque)
{
    char *groupPath = NULL;
    DIR *groupDir = NULL;
    int ret = -1;
    struct dirent *ent;
E
Eric Blake 已提交
2197
    int direrr;
L
Laine Stump 已提交
2198 2199 2200

    if (virAsprintf(&groupPath,
                    PCI_SYSFS "devices/%04x:%02x:%02x.%x/iommu_group/devices",
2201
                    orig->domain, orig->bus, orig->slot, orig->function) < 0)
L
Laine Stump 已提交
2202 2203
        goto cleanup;

J
Ján Tomko 已提交
2204
    if (virDirOpenQuiet(&groupDir, groupPath) < 0) {
L
Laine Stump 已提交
2205 2206 2207 2208 2209
        /* just process the original device, nothing more */
        ret = (actor)(orig, opaque);
        goto cleanup;
    }

E
Eric Blake 已提交
2210
    while ((direrr = virDirRead(groupDir, &ent, groupPath)) > 0) {
L
Laine Stump 已提交
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222
        virPCIDeviceAddress newDev;

        if (virPCIDeviceAddressParse(ent->d_name, &newDev) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Found invalid device link '%s' in '%s'"),
                           ent->d_name, groupPath);
            goto cleanup;
        }

        if ((actor)(&newDev, opaque) < 0)
            goto cleanup;
    }
E
Eric Blake 已提交
2223
    if (direrr < 0)
L
Laine Stump 已提交
2224 2225 2226 2227
        goto cleanup;

    ret = 0;

2228
 cleanup:
L
Laine Stump 已提交
2229
    VIR_FREE(groupPath);
J
Ján Tomko 已提交
2230
    VIR_DIR_CLOSE(groupDir);
L
Laine Stump 已提交
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
    return ret;
}


static int
virPCIDeviceGetIOMMUGroupAddOne(virPCIDeviceAddressPtr newDevAddr, void *opaque)
{
    int ret = -1;
    virPCIDeviceListPtr groupList = opaque;
    virPCIDevicePtr newDev;

    if (!(newDev = virPCIDeviceNew(newDevAddr->domain, newDevAddr->bus,
                                   newDevAddr->slot, newDevAddr->function)))
        goto cleanup;

    if (virPCIDeviceListAdd(groupList, newDev) < 0)
        goto cleanup;

    newDev = NULL; /* it's now on the list */
    ret = 0;
2251
 cleanup:
L
Laine Stump 已提交
2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
    virPCIDeviceFree(newDev);
    return ret;
}


/*
 * virPCIDeviceGetIOMMUGroupList - return a virPCIDeviceList containing
 * all of the devices in the same iommu_group as @dev.
 *
 * Return the new list, or NULL on failure
 */
virPCIDeviceListPtr
virPCIDeviceGetIOMMUGroupList(virPCIDevicePtr dev)
{
    virPCIDeviceListPtr groupList = virPCIDeviceListNew();

    if (!groupList)
        goto error;

2271
    if (virPCIDeviceAddressIOMMUGroupIterate(&(dev->address),
L
Laine Stump 已提交
2272 2273 2274 2275 2276 2277
                                             virPCIDeviceGetIOMMUGroupAddOne,
                                             groupList) < 0)
        goto error;

    return groupList;

2278
 error:
L
Laine Stump 已提交
2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
    virObjectUnref(groupList);
    return NULL;
}


typedef struct {
    virPCIDeviceAddressPtr **iommuGroupDevices;
    size_t *nIommuGroupDevices;
} virPCIDeviceAddressList;
typedef virPCIDeviceAddressList *virPCIDeviceAddressListPtr;

static int
virPCIGetIOMMUGroupAddressesAddOne(virPCIDeviceAddressPtr newDevAddr, void *opaque)
{
    int ret = -1;
    virPCIDeviceAddressListPtr addrList = opaque;
    virPCIDeviceAddressPtr copyAddr;

    /* make a copy to insert onto the list */
    if (VIR_ALLOC(copyAddr) < 0)
        goto cleanup;

    *copyAddr = *newDevAddr;

2303 2304
    if (VIR_APPEND_ELEMENT(*addrList->iommuGroupDevices,
                           *addrList->nIommuGroupDevices, copyAddr) < 0)
L
Laine Stump 已提交
2305 2306 2307
        goto cleanup;

    ret = 0;
2308
 cleanup:
L
Laine Stump 已提交
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
    VIR_FREE(copyAddr);
    return ret;
}


/*
 * virPCIDeviceAddressGetIOMMUGroupAddresses - return a
 * virPCIDeviceList containing all of the devices in the same
 * iommu_group as @dev.
 *
 * Return the new list, or NULL on failure
 */
int
virPCIDeviceAddressGetIOMMUGroupAddresses(virPCIDeviceAddressPtr devAddr,
                                          virPCIDeviceAddressPtr **iommuGroupDevices,
                                          size_t *nIommuGroupDevices)
{
    int ret = -1;
    virPCIDeviceAddressList addrList = { iommuGroupDevices,
                                         nIommuGroupDevices };

    if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
                                             virPCIGetIOMMUGroupAddressesAddOne,
                                             &addrList) < 0)
        goto cleanup;

    ret = 0;
2336
 cleanup:
L
Laine Stump 已提交
2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
    return ret;
}


/* virPCIDeviceAddressGetIOMMUGroupNum - return the group number of
 * this PCI device's iommu_group, or -2 if there is no iommu_group for
 * the device (or -1 if there was any other error)
 */
int
virPCIDeviceAddressGetIOMMUGroupNum(virPCIDeviceAddressPtr addr)
{
    char *devName = NULL;
    char *devPath = NULL;
    char *groupPath = NULL;
    const char *groupNumStr;
    unsigned int groupNum;
    int ret = -1;

    if (virAsprintf(&devName, "%.4x:%.2x:%.2x.%.1x", addr->domain,
2356
                    addr->bus, addr->slot, addr->function) < 0)
L
Laine Stump 已提交
2357 2358
        goto cleanup;

2359
    if (!(devPath = virPCIFile(devName, "iommu_group")))
L
Laine Stump 已提交
2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
        goto cleanup;
    if (virFileIsLink(devPath) != 1) {
        ret = -2;
        goto cleanup;
    }
    if (virFileResolveLink(devPath, &groupPath) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to resolve device %s iommu_group symlink %s"),
                       devName, devPath);
        goto cleanup;
    }

    groupNumStr = last_component(groupPath);
    if (virStrToLong_ui(groupNumStr, NULL, 10, &groupNum) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("device %s iommu_group symlink %s has "
                         "invalid group number %s"),
                       devName, groupPath, groupNumStr);
        ret = -1;
        goto cleanup;
    }

    ret = groupNum;
2383
 cleanup:
L
Laine Stump 已提交
2384 2385 2386 2387 2388 2389 2390
    VIR_FREE(devName);
    VIR_FREE(devPath);
    VIR_FREE(groupPath);
    return ret;
}


2391 2392
/* virPCIDeviceGetIOMMUGroupDev - return the name of the device used
 * to control this PCI device's group (e.g. "/dev/vfio/15")
2393 2394
 */
char *
2395
virPCIDeviceGetIOMMUGroupDev(virPCIDevicePtr dev)
2396 2397 2398 2399 2400
{
    char *devPath = NULL;
    char *groupPath = NULL;
    char *groupDev = NULL;

2401
    if (!(devPath = virPCIFile(dev->name, "iommu_group")))
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
        goto cleanup;
    if (virFileIsLink(devPath) != 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid device %s iommu_group file %s is not a symlink"),
                       dev->name, devPath);
        goto cleanup;
    }
    if (virFileResolveLink(devPath, &groupPath) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to resolve device %s iommu_group symlink %s"),
                       dev->name, devPath);
        goto cleanup;
    }
    if (virAsprintf(&groupDev, "/dev/vfio/%s",
2416
                    last_component(groupPath)) < 0)
2417
        goto cleanup;
2418
 cleanup:
2419 2420 2421 2422 2423
    VIR_FREE(devPath);
    VIR_FREE(groupPath);
    return groupDev;
}

J
Jiri Denemark 已提交
2424
static int
2425
virPCIDeviceDownstreamLacksACS(virPCIDevicePtr dev)
J
Jiri Denemark 已提交
2426 2427 2428 2429
{
    uint16_t flags;
    uint16_t ctrl;
    unsigned int pos;
2430 2431
    int fd;
    int ret = 0;
2432
    uint16_t device_class;
J
Jiri Denemark 已提交
2433

2434
    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
J
Jiri Denemark 已提交
2435 2436
        return -1;

2437
    if (virPCIDeviceInit(dev, fd) < 0) {
2438 2439 2440 2441
        ret = -1;
        goto cleanup;
    }

2442 2443 2444
    if (virPCIDeviceReadClass(dev, &device_class) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
2445
    pos = dev->pcie_cap_pos;
2446
    if (!pos || device_class != PCI_CLASS_BRIDGE_PCI)
2447
        goto cleanup;
J
Jiri Denemark 已提交
2448

2449
    flags = virPCIDeviceRead16(dev, fd, pos + PCI_EXP_FLAGS);
J
Jiri Denemark 已提交
2450
    if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM)
2451
        goto cleanup;
J
Jiri Denemark 已提交
2452

2453
    pos = virPCIDeviceFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS);
J
Jiri Denemark 已提交
2454 2455
    if (!pos) {
        VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name);
2456 2457
        ret = 1;
        goto cleanup;
J
Jiri Denemark 已提交
2458 2459
    }

2460
    ctrl = virPCIDeviceRead16(dev, fd, pos + PCI_EXT_ACS_CTRL);
J
Jiri Denemark 已提交
2461 2462 2463
    if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) {
        VIR_DEBUG("%s %s: downstream port has ACS disabled",
                  dev->id, dev->name);
2464 2465
        ret = 1;
        goto cleanup;
J
Jiri Denemark 已提交
2466 2467
    }

2468
 cleanup:
2469
    virPCIDeviceConfigClose(dev, fd);
2470
    return ret;
J
Jiri Denemark 已提交
2471 2472 2473
}

static int
2474
virPCIDeviceIsBehindSwitchLackingACS(virPCIDevicePtr dev)
J
Jiri Denemark 已提交
2475
{
2476
    virPCIDevicePtr parent;
J
Jiri Denemark 已提交
2477

2478
    if (virPCIDeviceGetParent(dev, &parent) < 0)
2479
        return -1;
2480 2481 2482 2483 2484
    if (!parent) {
        /* if we have no parent, and this is the root bus, ACS doesn't come
         * into play since devices on the root bus can't P2P without going
         * through the root IOMMU.
         */
2485
        if (dev->address.bus == 0) {
2486
            return 0;
2487
        } else {
2488
            virReportError(VIR_ERR_INTERNAL_ERROR,
2489 2490 2491 2492
                           _("Failed to find parent device for %s"),
                           dev->name);
            return -1;
        }
J
Jiri Denemark 已提交
2493 2494 2495 2496 2497 2498 2499
    }

    /* XXX we should rather fail when we can't find device's parent and
     * stop the loop when we get to root instead of just stopping when no
     * parent can be found
     */
    do {
2500
        virPCIDevicePtr tmp;
J
Jiri Denemark 已提交
2501
        int acs;
2502
        int ret;
J
Jiri Denemark 已提交
2503

2504
        acs = virPCIDeviceDownstreamLacksACS(parent);
J
Jiri Denemark 已提交
2505 2506

        if (acs) {
2507
            virPCIDeviceFree(parent);
J
Jiri Denemark 已提交
2508 2509 2510 2511 2512 2513 2514
            if (acs < 0)
                return -1;
            else
                return 1;
        }

        tmp = parent;
2515 2516
        ret = virPCIDeviceGetParent(parent, &parent);
        virPCIDeviceFree(tmp);
2517 2518
        if (ret < 0)
            return -1;
J
Jiri Denemark 已提交
2519 2520 2521 2522 2523
    } while (parent);

    return 0;
}

2524 2525
int virPCIDeviceIsAssignable(virPCIDevicePtr dev,
                             int strict_acs_check)
J
Jiri Denemark 已提交
2526 2527 2528 2529 2530 2531 2532 2533
{
    int ret;

    /* XXX This could be a great place to actually check that a non-managed
     * device isn't in use, e.g. by checking that device is either un-bound
     * or bound to a stub driver.
     */

2534
    ret = virPCIDeviceIsBehindSwitchLackingACS(dev);
J
Jiri Denemark 已提交
2535 2536 2537 2538 2539 2540 2541 2542
    if (ret < 0)
        return 0;

    if (ret) {
        if (!strict_acs_check) {
            VIR_DEBUG("%s %s: strict ACS check disabled; device assignment allowed",
                      dev->id, dev->name);
        } else {
2543
            virReportError(VIR_ERR_INTERNAL_ERROR,
J
Jiri Denemark 已提交
2544 2545 2546 2547 2548 2549 2550 2551 2552
                           _("Device %s is behind a switch lacking ACS and "
                             "cannot be assigned"),
                           dev->name);
            return 0;
        }
    }

    return 1;
}
2553 2554 2555 2556 2557 2558 2559 2560 2561 2562

static int
logStrToLong_ui(char const *s,
                char **end_ptr,
                int base,
                unsigned int *result)
{
    int ret = 0;

    ret = virStrToLong_ui(s, end_ptr, base, result);
2563
    if (ret != 0)
2564 2565 2566 2567
        VIR_ERROR(_("Failed to convert '%s' to unsigned int"), s);
    return ret;
}

2568 2569
int
virPCIDeviceAddressParse(char *address,
2570
                         virPCIDeviceAddressPtr bdf)
2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596
{
    char *p = NULL;
    int ret = -1;

    if ((address == NULL) || (logStrToLong_ui(address, &p, 16,
                                              &bdf->domain) == -1)) {
        goto out;
    }

    if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16,
                                        &bdf->bus) == -1)) {
        goto out;
    }

    if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16,
                                        &bdf->slot) == -1)) {
        goto out;
    }

    if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16,
                                        &bdf->function) == -1)) {
        goto out;
    }

    ret = 0;

2597
 out:
2598 2599 2600
    return ret;
}

2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
#ifdef __linux__

/*
 * returns true if equal
 */
static bool
virPCIDeviceAddressIsEqual(virPCIDeviceAddressPtr bdf1,
                           virPCIDeviceAddressPtr bdf2)
{
    return ((bdf1->domain == bdf2->domain) &&
            (bdf1->bus == bdf2->bus) &&
            (bdf1->slot == bdf2->slot) &&
            (bdf1->function == bdf2->function));
}

2616
virPCIDeviceAddressPtr
2617
virPCIGetDeviceAddressFromSysfsLink(const char *device_link)
2618
{
2619
    virPCIDeviceAddressPtr bdf = NULL;
2620 2621 2622 2623
    char *config_address = NULL;
    char *device_path = NULL;

    if (!virFileExists(device_link)) {
2624
        VIR_DEBUG("'%s' does not exist", device_link);
2625
        return NULL;
2626 2627
    }

2628
    device_path = canonicalize_file_name(device_link);
2629
    if (device_path == NULL) {
2630 2631 2632
        virReportSystemError(errno,
                             _("Failed to resolve device link '%s'"),
                             device_link);
2633
        return NULL;
2634 2635
    }

2636
    config_address = last_component(device_path);
2637
    if (VIR_ALLOC(bdf) < 0)
2638 2639
        goto out;

2640
    if (virPCIDeviceAddressParse(config_address, bdf) < 0) {
2641
        virReportError(VIR_ERR_INTERNAL_ERROR,
2642 2643
                       _("Failed to parse PCI config address '%s'"),
                       config_address);
2644
        VIR_FREE(bdf);
2645 2646 2647
        goto out;
    }

2648
 out:
2649 2650
    VIR_FREE(device_path);

2651
    return bdf;
2652 2653
}

2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666
/**
 * virPCIGetPhysicalFunction:
 * @vf_sysfs_path: sysfs path for the virtual function
 * @pf: where to store the physical function's address
 *
 * Given @vf_sysfs_path, this function will store the pointer
 * to a newly-allocated virPCIDeviceAddress in @pf.
 *
 * @pf might be NULL if @vf_sysfs_path does not point to a
 * virtual function. If it's not NULL, then it should be
 * freed by the caller when no longer needed.
 *
 * Returns: >=0 on success, <0 on failure
2667 2668
 */
int
2669
virPCIGetPhysicalFunction(const char *vf_sysfs_path,
2670
                          virPCIDeviceAddressPtr *pf)
2671 2672 2673
{
    char *device_link = NULL;

2674 2675
    *pf = NULL;

2676 2677
    if (virBuildPath(&device_link, vf_sysfs_path, "physfn") == -1) {
        virReportOOMError();
2678
        return -1;
2679 2680
    }

2681
    if ((*pf = virPCIGetDeviceAddressFromSysfsLink(device_link))) {
2682 2683 2684
        VIR_DEBUG("PF for VF device '%s': %.4x:%.2x:%.2x.%.1x", vf_sysfs_path,
                  (*pf)->domain, (*pf)->bus, (*pf)->slot, (*pf)->function);
    }
2685 2686
    VIR_FREE(device_link);

2687
    return 0;
2688 2689
}

2690

2691 2692 2693 2694
/*
 * Returns virtual functions of a physical function
 */
int
2695 2696
virPCIGetVirtualFunctions(const char *sysfs_path,
                          virPCIDeviceAddressPtr **virtual_functions,
2697 2698
                          size_t *num_virtual_functions,
                          unsigned int *max_virtual_functions)
2699 2700
{
    int ret = -1;
2701
    size_t i;
2702
    char *device_link = NULL;
2703
    virPCIDeviceAddressPtr config_addr = NULL;
2704
    char *totalvfs_file = NULL, *totalvfs_str = NULL;
2705

2706 2707
    *virtual_functions = NULL;
    *num_virtual_functions = 0;
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723
    *max_virtual_functions = 0;

    if (virAsprintf(&totalvfs_file, "%s/sriov_totalvfs", sysfs_path) < 0)
       goto error;
    if (virFileExists(totalvfs_file)) {
        char *end = NULL; /* so that terminating \n doesn't create error */

        if (virFileReadAll(totalvfs_file, 16, &totalvfs_str) < 0)
            goto error;
        if (virStrToLong_ui(totalvfs_str, &end, 10, max_virtual_functions) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unrecognized value in %s: %s"),
                           totalvfs_file, totalvfs_str);
            goto error;
        }
    }
2724

2725 2726 2727 2728
    do {
        /* look for virtfn%d links until one isn't found */
        if (virAsprintf(&device_link, "%s/virtfn%zu", sysfs_path, *num_virtual_functions) < 0)
            goto error;
2729

2730 2731
        if (!virFileExists(device_link))
            break;
2732

2733
        if (!(config_addr = virPCIGetDeviceAddressFromSysfsLink(device_link))) {
2734 2735 2736 2737 2738
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to get SRIOV function from device link '%s'"),
                           device_link);
            goto error;
        }
2739

2740 2741
        if (VIR_APPEND_ELEMENT(*virtual_functions, *num_virtual_functions,
                               config_addr) < 0)
2742 2743
            goto error;
        VIR_FREE(device_link);
2744

2745
    } while (1);
2746

2747 2748
    VIR_DEBUG("Found %zu virtual functions for %s",
              *num_virtual_functions, sysfs_path);
2749
    ret = 0;
2750
 cleanup:
2751
    VIR_FREE(device_link);
2752
    VIR_FREE(config_addr);
2753 2754
    VIR_FREE(totalvfs_file);
    VIR_FREE(totalvfs_str);
2755
    return ret;
2756

2757
 error:
2758 2759 2760
    for (i = 0; i < *num_virtual_functions; i++)
        VIR_FREE((*virtual_functions)[i]);
    VIR_FREE(*virtual_functions);
2761
    *num_virtual_functions = 0;
2762
    goto cleanup;
2763
}
2764

2765

2766 2767 2768 2769
/*
 * Returns 1 if vf device is a virtual function, 0 if not, -1 on error
 */
int
2770
virPCIIsVirtualFunction(const char *vf_sysfs_device_link)
2771 2772 2773 2774 2775
{
    char *vf_sysfs_physfn_link = NULL;
    int ret = -1;

    if (virAsprintf(&vf_sysfs_physfn_link, "%s/physfn",
2776
                    vf_sysfs_device_link) < 0)
2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789
        return ret;

    ret = virFileExists(vf_sysfs_physfn_link);

    VIR_FREE(vf_sysfs_physfn_link);

    return ret;
}

/*
 * Returns the sriov virtual function index of vf given its pf
 */
int
2790 2791 2792
virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
                              const char *vf_sysfs_device_link,
                              int *vf_index)
2793
{
2794 2795
    int ret = -1;
    size_t i;
2796
    size_t num_virt_fns = 0;
2797
    unsigned int max_virt_fns = 0;
2798 2799
    virPCIDeviceAddressPtr vf_bdf = NULL;
    virPCIDeviceAddressPtr *virt_fns = NULL;
2800

2801
    if (!(vf_bdf = virPCIGetDeviceAddressFromSysfsLink(vf_sysfs_device_link)))
2802 2803
        return ret;

2804
    if (virPCIGetVirtualFunctions(pf_sysfs_device_link, &virt_fns,
2805
                                  &num_virt_fns, &max_virt_fns) < 0) {
2806
        virReportError(VIR_ERR_INTERNAL_ERROR,
2807
                       _("Error getting physical function's '%s' "
2808
                         "virtual_functions"), pf_sysfs_device_link);
2809 2810 2811 2812
        goto out;
    }

    for (i = 0; i < num_virt_fns; i++) {
2813 2814 2815 2816 2817
        if (virPCIDeviceAddressIsEqual(vf_bdf, virt_fns[i])) {
            *vf_index = i;
            ret = 0;
            break;
        }
2818 2819
    }

2820
 out:
2821 2822 2823

    /* free virtual functions */
    for (i = 0; i < num_virt_fns; i++)
2824
        VIR_FREE(virt_fns[i]);
2825

A
ajia@redhat.com 已提交
2826
    VIR_FREE(virt_fns);
2827 2828 2829 2830 2831
    VIR_FREE(vf_bdf);

    return ret;
}

2832 2833 2834 2835 2836
/*
 * Returns a path to the PCI sysfs file given the BDF of the PCI function
 */

int
2837
virPCIGetSysfsFile(char *virPCIDeviceName, char **pci_sysfs_device_link)
2838
{
2839 2840 2841 2842
    if (virAsprintf(pci_sysfs_device_link, PCI_SYSFS "devices/%s",
                    virPCIDeviceName) < 0)
        return -1;
    return 0;
2843 2844
}

R
Roopa Prabhu 已提交
2845
int
2846
virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
2847
                                char **pci_sysfs_device_link)
R
Roopa Prabhu 已提交
2848
{
2849
    if (virAsprintf(pci_sysfs_device_link,
2850 2851 2852
                    PCI_SYSFS "devices/%04x:%02x:%02x.%x",
                    addr->domain, addr->bus,
                    addr->slot, addr->function) < 0)
2853 2854
        return -1;
    return 0;
R
Roopa Prabhu 已提交
2855 2856
}

2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867
/**
 * virPCIGetNetName:
 * @device_link_sysfs_path: sysfs path to the PCI device
 * @idx: used to choose which netdev when there are several
 *       (ignored if physPortID is set)
 * @physPortID: match this string in the netdev's phys_port_id
 *       (or NULL to ignore and use idx instead)
 * @netname: used to return the name of the netdev
 *       (set to NULL (but returns success) if there is no netdev)
 *
 * Returns 0 on success, -1 on error (error has been logged)
2868 2869
 */
int
2870 2871 2872 2873
virPCIGetNetName(const char *device_link_sysfs_path,
                 size_t idx,
                 char *physPortID,
                 char **netname)
2874 2875 2876 2877 2878
{
    char *pcidev_sysfs_net_path = NULL;
    int ret = -1;
    DIR *dir = NULL;
    struct dirent *entry = NULL;
2879
    char *firstEntryName = NULL;
2880 2881
    char *thisPhysPortID = NULL;
    size_t i = 0;
2882

2883 2884 2885 2886 2887 2888
    if (virBuildPath(&pcidev_sysfs_net_path, device_link_sysfs_path,
                     "net") == -1) {
        virReportOOMError();
        return -1;
    }

2889 2890 2891
    if (virDirOpenQuiet(&dir, pcidev_sysfs_net_path) < 0) {
        /* this *isn't* an error - caller needs to check for netname == NULL */
        ret = 0;
2892
        goto cleanup;
2893
    }
2894

E
Eric Blake 已提交
2895
    while (virDirRead(dir, &entry, pcidev_sysfs_net_path) > 0) {
2896 2897 2898 2899 2900 2901 2902 2903 2904 2905
        /* if the caller sent a physPortID, compare it to the
         * physportID of this netdev. If not, look for entry[idx].
         */
        if (physPortID) {
            if (virNetDevGetPhysPortID(entry->d_name, &thisPhysPortID) < 0)
                goto cleanup;

            /* if this one doesn't match, keep looking */
            if (STRNEQ_NULLABLE(physPortID, thisPhysPortID)) {
                VIR_FREE(thisPhysPortID);
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
                /* save the first entry we find to use as a failsafe
                 * in case we don't match the phys_port_id. This is
                 * needed because some NIC drivers (e.g. i40e)
                 * implement phys_port_id for PFs, but not for VFs
                 */
                if (!firstEntryName &&
                    VIR_STRDUP(firstEntryName, entry->d_name) < 0) {
                    goto cleanup;
                }

2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
                continue;
            }
        } else {
            if (i++ < idx)
                continue;
        }

        if (VIR_STRDUP(*netname, entry->d_name) < 0)
            goto cleanup;

        ret = 0;
2927 2928 2929
        break;
    }

2930 2931
    if (ret < 0) {
        if (physPortID) {
2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
            if (firstEntryName) {
                /* we didn't match the provided phys_port_id, but this
                 * is probably because phys_port_id isn't implemented
                 * for this NIC driver, so just return the first
                 * (probably only) netname we found.
                 */
                *netname = firstEntryName;
                firstEntryName = NULL;
                ret = 0;
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Could not find network device with "
                                 "phys_port_id '%s' under PCI device at %s"),
                               physPortID, device_link_sysfs_path);
            }
2947 2948 2949 2950 2951
        } else {
            ret = 0; /* no netdev at the given index is *not* an error */
        }
    }
 cleanup:
J
Ján Tomko 已提交
2952
    VIR_DIR_CLOSE(dir);
2953
    VIR_FREE(pcidev_sysfs_net_path);
2954
    VIR_FREE(thisPhysPortID);
2955
    VIR_FREE(firstEntryName);
2956
    return ret;
2957
}
R
Roopa Prabhu 已提交
2958 2959

int
2960
virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
2961 2962 2963
                             int pfNetDevIdx,
                             char **pfname,
                             int *vf_index)
R
Roopa Prabhu 已提交
2964
{
2965
    virPCIDeviceAddressPtr pf_config_address = NULL;
R
Roopa Prabhu 已提交
2966
    char *pf_sysfs_device_path = NULL;
2967 2968
    char *vfname = NULL;
    char *vfPhysPortID = NULL;
R
Roopa Prabhu 已提交
2969 2970
    int ret = -1;

2971
    if (virPCIGetPhysicalFunction(vf_sysfs_device_path, &pf_config_address) < 0)
2972
        goto cleanup;
R
Roopa Prabhu 已提交
2973

2974
    if (!pf_config_address)
2975
        goto cleanup;
2976

2977 2978
    if (virPCIDeviceAddressGetSysfsFile(pf_config_address,
                                        &pf_sysfs_device_path) < 0) {
2979 2980
        goto cleanup;
    }
R
Roopa Prabhu 已提交
2981

2982 2983 2984
    if (virPCIGetVirtualFunctionIndex(pf_sysfs_device_path,
                                      vf_sysfs_device_path, vf_index) < 0) {
        goto cleanup;
R
Roopa Prabhu 已提交
2985 2986
    }

2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006
    /* If the caller hasn't asked for a specific pfNetDevIdx, and VF
     * is bound to a netdev, learn that netdev's phys_port_id (if
     * available). This can be used to disambiguate when the PF has
     * multiple netdevs. If the VF isn't bound to a netdev, then we
     * return netdev[pfNetDevIdx] on the PF, which may or may not be
     * correct.
     */
    if (pfNetDevIdx == -1) {
        if (virPCIGetNetName(vf_sysfs_device_path, 0, NULL, &vfname) < 0)
            goto cleanup;

        if (vfname) {
            if (virNetDevGetPhysPortID(vfname, &vfPhysPortID) < 0)
                goto cleanup;
        }
        pfNetDevIdx = 0;
    }

    if (virPCIGetNetName(pf_sysfs_device_path,
                         pfNetDevIdx, vfPhysPortID, pfname) < 0) {
R
Roopa Prabhu 已提交
3007
        goto cleanup;
3008
    }
R
Roopa Prabhu 已提交
3009

3010 3011 3012 3013 3014 3015 3016 3017 3018
    if (!*pfname) {
        /* this shouldn't be possible. A VF can't exist unless its
         * PF device is bound to a network driver
         */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("The PF device for VF %s has no network device name"),
                       vf_sysfs_device_path);
        goto cleanup;
    }
R
Roopa Prabhu 已提交
3019

3020
    ret = 0;
3021
 cleanup:
R
Roopa Prabhu 已提交
3022 3023
    VIR_FREE(pf_config_address);
    VIR_FREE(pf_sysfs_device_path);
3024 3025
    VIR_FREE(vfname);
    VIR_FREE(vfPhysPortID);
R
Roopa Prabhu 已提交
3026 3027 3028 3029

    return ret;
}

3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087

ssize_t
virPCIGetMdevTypes(const char *sysfspath,
                   virMediatedDeviceTypePtr **types)
{
    ssize_t ret = -1;
    int dirret = -1;
    DIR *dir = NULL;
    struct dirent *entry;
    char *types_path = NULL;
    char *tmppath = NULL;
    virMediatedDeviceTypePtr mdev_type = NULL;
    virMediatedDeviceTypePtr *mdev_types = NULL;
    size_t ntypes = 0;
    size_t i;

    if (virAsprintf(&types_path, "%s/mdev_supported_types", sysfspath) < 0)
        return -1;

    if ((dirret = virDirOpenIfExists(&dir, types_path)) < 0)
        goto cleanup;

    if (dirret == 0) {
        ret = 0;
        goto cleanup;
    }

    while ((dirret = virDirRead(dir, &entry, types_path)) > 0) {
        /* append the type id to the path and read the attributes from there */
        if (virAsprintf(&tmppath, "%s/%s", types_path, entry->d_name) < 0)
            goto cleanup;

        if (virMediatedDeviceTypeReadAttrs(tmppath, &mdev_type) < 0)
            goto cleanup;

        if (VIR_APPEND_ELEMENT(mdev_types, ntypes, mdev_type) < 0)
            goto cleanup;

        VIR_FREE(tmppath);
    }

    if (dirret < 0)
        goto cleanup;

    VIR_STEAL_PTR(*types, mdev_types);
    ret = ntypes;
    ntypes = 0;
 cleanup:
    virMediatedDeviceTypeFree(mdev_type);
    for (i = 0; i < ntypes; i++)
        virMediatedDeviceTypeFree(mdev_types[i]);
    VIR_FREE(mdev_types);
    VIR_FREE(types_path);
    VIR_FREE(tmppath);
    VIR_DIR_CLOSE(dir);
    return ret;
}

3088
#else
3089 3090
static const char *unsupported = N_("not supported on non-linux platforms");

3091 3092 3093 3094
virPCIDeviceAddressPtr
virPCIGetDeviceAddressFromSysfsLink(const char *device_link ATTRIBUTE_UNUSED)
{
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3095
    return NULL;
3096 3097 3098
}


3099
int
3100
virPCIGetPhysicalFunction(const char *vf_sysfs_path ATTRIBUTE_UNUSED,
3101
                          virPCIDeviceAddressPtr *pf ATTRIBUTE_UNUSED)
3102
{
3103
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3104 3105 3106 3107
    return -1;
}

int
3108 3109
virPCIGetVirtualFunctions(const char *sysfs_path ATTRIBUTE_UNUSED,
                          virPCIDeviceAddressPtr **virtual_functions ATTRIBUTE_UNUSED,
3110 3111
                          size_t *num_virtual_functions ATTRIBUTE_UNUSED,
                          unsigned int *max_virtual_functions ATTRIBUTE_UNUSED)
3112
{
3113
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3114 3115
    return -1;
}
3116 3117

int
E
Eric Blake 已提交
3118
virPCIIsVirtualFunction(const char *vf_sysfs_device_link ATTRIBUTE_UNUSED)
3119
{
3120
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3121 3122 3123 3124
    return -1;
}

int
3125 3126 3127
virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link ATTRIBUTE_UNUSED,
                              const char *vf_sysfs_device_link ATTRIBUTE_UNUSED,
                              int *vf_index ATTRIBUTE_UNUSED)
3128
{
3129
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3130 3131 3132 3133
    return -1;

}

3134
int
3135 3136
virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev ATTRIBUTE_UNUSED,
                                char **pci_sysfs_device_link ATTRIBUTE_UNUSED)
3137
{
3138
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3139 3140 3141
    return -1;
}

3142
int
3143
virPCIGetNetName(const char *device_link_sysfs_path ATTRIBUTE_UNUSED,
3144 3145
                 size_t idx ATTRIBUTE_UNUSED,
                 char *physPortID ATTRIBUTE_UNUSED,
3146
                 char **netname ATTRIBUTE_UNUSED)
3147
{
3148
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
3149 3150
    return -1;
}
R
Roopa Prabhu 已提交
3151 3152

int
3153
virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path ATTRIBUTE_UNUSED,
3154
                             int pfNetDevIdx ATTRIBUTE_UNUSED,
3155 3156
                             char **pfname ATTRIBUTE_UNUSED,
                             int *vf_index ATTRIBUTE_UNUSED)
R
Roopa Prabhu 已提交
3157
{
3158
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
R
Roopa Prabhu 已提交
3159 3160
    return -1;
}
3161
#endif /* __linux__ */
3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245

int
virPCIDeviceIsPCIExpress(virPCIDevicePtr dev)
{
    int fd;
    int ret = -1;

    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
        return ret;

    if (virPCIDeviceInit(dev, fd) < 0)
        goto cleanup;

    ret = dev->pcie_cap_pos != 0;

 cleanup:
    virPCIDeviceConfigClose(dev, fd);
    return ret;
}

int
virPCIDeviceHasPCIExpressLink(virPCIDevicePtr dev)
{
    int fd;
    int ret = -1;
    uint16_t cap, type;

    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
        return ret;

    if (virPCIDeviceInit(dev, fd) < 0)
        goto cleanup;

    cap = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_CAP_FLAGS);
    type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;

    ret = type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;

 cleanup:
    virPCIDeviceConfigClose(dev, fd);
    return ret;
}

int
virPCIDeviceGetLinkCapSta(virPCIDevicePtr dev,
                          int *cap_port,
                          unsigned int *cap_speed,
                          unsigned int *cap_width,
                          unsigned int *sta_speed,
                          unsigned int *sta_width)
{
    uint32_t t;
    int fd;
    int ret = -1;

    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
        return ret;

    if (virPCIDeviceInit(dev, fd) < 0)
        goto cleanup;

    if (!dev->pcie_cap_pos) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("pci device %s is not a PCI-Express device"),
                       dev->name);
        goto cleanup;
    }

    t = virPCIDeviceRead32(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKCAP);

    *cap_port = t >> 24;
    *cap_speed = t & PCI_EXP_LNKCAP_SPEED;
    *cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;

    t = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKSTA);

    *sta_speed = t & PCI_EXP_LNKSTA_SPEED;
    *sta_width = (t & PCI_EXP_LNKSTA_WIDTH) >> 4;
    ret = 0;

 cleanup:
    virPCIDeviceConfigClose(dev, fd);
    return ret;
}
3246 3247


3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274
int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType)
{
    int fd;
    uint8_t type;

    *hdrType = -1;

    if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
        return -1;

    type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);

    virPCIDeviceConfigClose(dev, fd);

    type &= PCI_HEADER_TYPE_MASK;
    if (type >= VIR_PCI_HEADER_LAST) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown PCI header type '%d'"), type);
        return -1;
    }

    *hdrType = type;

    return 0;
}


3275 3276 3277 3278 3279 3280 3281 3282 3283 3284
void
virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev)
{
    if (!dev)
        return;

    VIR_FREE(dev->link_cap);
    VIR_FREE(dev->link_sta);
    VIR_FREE(dev);
}