When using -pcidevice on a device that is already in use by a kernel driver all the user gets is the following (very useful) information: Failed to assign device "04:00.0" : Device or resource busy Failed to deassign device "04:00.0" : Invalid argument Error initializing device pci-assign Since I usually prefer to have my computer do the thinking for me, I figured it might be a good idea to check and see if a device is actually used by a driver. If so, tell the user. So with this patch applied you get the following output: Failed to assign device "04:00.0" : Device or resource busy *** The driver 'igb' is occupying your device 04:00.0. *** *** You can try the following commands to free it: *** *** $ echo "8086 150a" > /sys/bus/pci/drivers/pci-stub/new_id *** $ echo "0000:04:00.0" > /sys/bus/pci/drivers/igb/unbind *** $ echo "0000:04:00.0" > /sys/bus/pci/drivers/pci-stub/bind *** $ echo "8086 150a" > /sys/bus/pci/drivers/pci-stub/remove_id *** Failed to deassign device "04:00.0" : Invalid argument Error initializing device pci-assign That should keep people like me from doing the most obvious misuses :-). CC: Daniel P. Berrange <berrange@xxxxxxxxxx> Signed-off-by: Alexander Graf <agraf@xxxxxxx> --- v1 -> v2: - add more helpful guidance thanks to Daniel Berrange v2 -> v3: - clear name variable before using it, thus 0-terminating the string - fix region numbers - use correct unbind/bind names v3 -> v4: - split id retrieval part - mst comments --- hw/device-assignment.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 53 insertions(+), 2 deletions(-) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 566671c..d7a03c9 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -756,6 +756,54 @@ static uint32_t calc_assigned_dev_id(uint8_t bus, uint8_t devfn) return (uint32_t)bus << 8 | (uint32_t)devfn; } +static void assign_failed_examine(AssignedDevice *dev) +{ + char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; + uint16_t vendor_id, device_id; + int r; + + /* XXX implement multidomain */ + sprintf(dir, "/sys/bus/pci/devices/0000:%02x:%02x.%01x/", + dev->host.bus, dev->host.dev, dev->host.func); + + sprintf(name, "%sdriver", dir); + + r = readlink(name, driver, sizeof(driver)); + if ((r <= 0) || !(ns = strrchr(driver, '/')) || r >= sizeof(driver)) { + goto fail; + } + + ns++; + + if (get_real_vendor_id(dir, &vendor_id) || + get_real_device_id(dir, &device_id)) { + goto fail; + } + + fprintf(stderr, "*** The driver '%s' is occupying your device " + "%02x:%02x.%x.\n", + ns, dev->host.bus, dev->host.dev, dev->host.func); + fprintf(stderr, "***\n"); + fprintf(stderr, "*** You can try the following commands to free it:\n"); + fprintf(stderr, "***\n"); + fprintf(stderr, "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/" + "new_id\n", vendor_id, device_id); + fprintf(stderr, "*** $ echo \"0000:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "%s/unbind\n", + dev->host.bus, dev->host.dev, dev->host.func, ns); + fprintf(stderr, "*** $ echo \"0000:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "pci-stub/bind\n", + dev->host.bus, dev->host.dev, dev->host.func); + fprintf(stderr, "*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub" + "/remove_id\n", vendor_id, device_id); + fprintf(stderr, "***\n"); + + return; + +fail: + fprintf(stderr, "Couldn't find out why.\n"); +} + static int assign_device(AssignedDevice *dev) { struct kvm_assigned_pci_dev assigned_dev_data; @@ -781,9 +829,12 @@ static int assign_device(AssignedDevice *dev) #endif r = kvm_assign_pci_device(kvm_context, &assigned_dev_data); - if (r < 0) - fprintf(stderr, "Failed to assign device \"%s\" : %s\n", + if (r < 0) { + fprintf(stderr, "Failed to assign device \"%s\" : %s\n", dev->dev.qdev.id, strerror(-r)); + + assign_failed_examine(dev); + } return r; } -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html