diff mbox

Inform users about busy device assignment attempt

Message ID 1260486386-5898-2-git-send-email-agraf@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Alexander Graf Dec. 10, 2009, 11:06 p.m. UTC
None
diff mbox

Patch

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index 5cee929..98faa83 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -564,14 +564,44 @@  static int assigned_dev_register_regions(PCIRegion *io_regions,
     return 0;
 }
 
+static int get_real_id(const char *devpath, const char *idname, uint16_t *val)
+{
+    FILE *f;
+    char name[128];
+    long id;
+
+    snprintf(name, sizeof(name), "%s%s", devpath, idname);
+    f = fopen(name, "r");
+    if (f == NULL) {
+        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+        return -1;
+    }
+    if (fscanf(f, "%li\n", &id) == 1) {
+        *val = id;
+    }
+    fclose(f);
+
+    return 0;
+}
+
+static int get_real_vendor_id(const char *devpath, uint16_t *val)
+{
+    return get_real_id(devpath, "vendor", val);
+}
+
+static int get_real_device_id(const char *devpath, uint16_t *val)
+{
+    return get_real_id(devpath, "device", val);
+}
+
 static int get_real_device(AssignedDevice *pci_dev, uint8_t r_bus,
                            uint8_t r_dev, uint8_t r_func)
 {
     char dir[128], name[128];
-    int fd, r = 0;
+    int fd, r = 0, v;
     FILE *f;
     unsigned long long start, end, size, flags;
-    unsigned long id;
+    uint16_t id;
     struct stat statbuf;
     PCIRegion *rp;
     PCIDevRegions *dev = &pci_dev->real_device;
@@ -637,31 +667,21 @@  again:
 
     fclose(f);
 
-    /* read and fill device ID */
-    snprintf(name, sizeof(name), "%svendor", dir);
-    f = fopen(name, "r");
-    if (f == NULL) {
-        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+    /* read and fill vendor ID */
+    v = get_real_vendor_id(dir, &id);
+    if (v) {
         return 1;
     }
-    if (fscanf(f, "%li\n", &id) == 1) {
-	pci_dev->dev.config[0] = id & 0xff;
-	pci_dev->dev.config[1] = (id & 0xff00) >> 8;
-    }
-    fclose(f);
+    pci_dev->dev.config[0] = id & 0xff;
+    pci_dev->dev.config[1] = (id & 0xff00) >> 8;
 
-    /* read and fill vendor ID */
-    snprintf(name, sizeof(name), "%sdevice", dir);
-    f = fopen(name, "r");
-    if (f == NULL) {
-        fprintf(stderr, "%s: %s: %m\n", __func__, name);
+    /* read and fill device ID */
+    v = get_real_device_id(dir, &id);
+    if (v) {
         return 1;
     }
-    if (fscanf(f, "%li\n", &id) == 1) {
-	pci_dev->dev.config[2] = id & 0xff;
-	pci_dev->dev.config[3] = (id & 0xff00) >> 8;
-    }
-    fclose(f);
+    pci_dev->dev.config[2] = id & 0xff;
+    pci_dev->dev.config[3] = (id & 0xff00) >> 8;
 
     /* dealing with virtual function device */
     snprintf(name, sizeof(name), "%sphysfn/", dir);
@@ -739,7 +759,9 @@  static uint32_t calc_assigned_dev_id(uint8_t bus, uint8_t devfn)
 static int assign_device(AssignedDevice *dev)
 {
     struct kvm_assigned_pci_dev assigned_dev_data;
-    int r;
+    char name[128], dir[128], driver[128], *ns;
+    uint16_t vendor_id, device_id;
+    int r, v;
 
     memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
     assigned_dev_data.assigned_dev_id  =
@@ -761,9 +783,48 @@  static int assign_device(AssignedDevice *dev)
 #endif
 
     r = kvm_assign_pci_device(kvm_context, &assigned_dev_data);
-    if (r < 0)
+    if (r < 0) {
 	fprintf(stderr, "Failed to assign device \"%s\" : %s\n",
                 dev->dev.qdev.id, strerror(-r));
+
+        snprintf(dir, sizeof(dir),
+                 "/sys/bus/pci/devices/0000:%02x:%02x.%x/",
+	         dev->host.bus, dev->host.dev, dev->host.func);
+
+        snprintf(name, sizeof(name), "%sdriver", dir);
+
+        memset(driver, 0, sizeof(driver));
+        v = readlink(name, driver, sizeof(driver));
+        if ((v <= 0) || !(ns = strrchr(driver, '/'))) {
+            return r;
+        }
+
+        ns++;
+
+        if (get_real_vendor_id(dir, &vendor_id) ||
+            get_real_device_id(dir, &device_id)) {
+            return r;
+        }
+
+        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 \"%x %x\" > /sys/bus/pci/drivers/pci-stub"
+                        "/remove_id\n", vendor_id, device_id);
+        fprintf(stderr, "***\n");
+    }
     return r;
 }