aboutsummaryrefslogtreecommitdiff
path: root/drivers/xen/xen-pciback/pci_stub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/xen-pciback/pci_stub.c')
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c339
1 files changed, 252 insertions, 87 deletions
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index 19834d1c7c3..d57a173685f 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -4,6 +4,9 @@
* Ryan Wilson <hap9@epoch.ncsc.mil>
* Chris Bookholt <hap10@epoch.ncsc.mil>
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rwsem.h>
@@ -17,6 +20,7 @@
#include <xen/events.h>
#include <asm/xen/pci.h>
#include <asm/xen/hypervisor.h>
+#include <xen/interface/physdev.h>
#include "pciback.h"
#include "conf_space.h"
#include "conf_space_quirks.h"
@@ -85,22 +89,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
static void pcistub_device_release(struct kref *kref)
{
struct pcistub_device *psdev;
+ struct pci_dev *dev;
+ struct xen_pcibk_dev_data *dev_data;
psdev = container_of(kref, struct pcistub_device, kref);
+ dev = psdev->dev;
+ dev_data = pci_get_drvdata(dev);
+
+ dev_dbg(&dev->dev, "pcistub_device_release\n");
- dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
+ xen_unregister_device_domain_owner(dev);
- xen_unregister_device_domain_owner(psdev->dev);
+ /* Call the reset function which does not take lock as this
+ * is called from "unbind" which takes a device_lock mutex.
+ */
+ __pci_reset_function_locked(dev);
+ if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
+ dev_dbg(&dev->dev, "Could not reload PCI state\n");
+ else
+ pci_restore_state(dev);
+
+ if (dev->msix_cap) {
+ struct physdev_pci_device ppdev = {
+ .seg = pci_domain_nr(dev->bus),
+ .bus = dev->bus->number,
+ .devfn = dev->devfn
+ };
+ int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix,
+ &ppdev);
+
+ if (err)
+ dev_warn(&dev->dev, "MSI-X release failed (%d)\n",
+ err);
+ }
+
+ /* Disable the device */
+ xen_pcibk_reset_device(dev);
+
+ kfree(dev_data);
+ pci_set_drvdata(dev, NULL);
/* Clean-up the device */
- xen_pcibk_reset_device(psdev->dev);
- xen_pcibk_config_free_dyn_fields(psdev->dev);
- xen_pcibk_config_free_dev(psdev->dev);
- kfree(pci_get_drvdata(psdev->dev));
- pci_set_drvdata(psdev->dev, NULL);
+ xen_pcibk_config_free_dyn_fields(dev);
+ xen_pcibk_config_free_dev(dev);
- psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
- pci_dev_put(psdev->dev);
+ dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
+ pci_dev_put(dev);
kfree(psdev);
}
@@ -127,7 +161,8 @@ static struct pcistub_device *pcistub_device_find(int domain, int bus,
if (psdev->dev != NULL
&& domain == pci_domain_nr(psdev->dev->bus)
&& bus == psdev->dev->bus->number
- && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+ && slot == PCI_SLOT(psdev->dev->devfn)
+ && func == PCI_FUNC(psdev->dev->devfn)) {
pcistub_device_get(psdev);
goto out;
}
@@ -176,7 +211,8 @@ struct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev,
if (psdev->dev != NULL
&& domain == pci_domain_nr(psdev->dev->bus)
&& bus == psdev->dev->bus->number
- && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
+ && slot == PCI_SLOT(psdev->dev->devfn)
+ && func == PCI_FUNC(psdev->dev->devfn)) {
found_dev = pcistub_device_get_pci_dev(pdev, psdev);
break;
}
@@ -206,6 +242,15 @@ struct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev,
return found_dev;
}
+/*
+ * Called when:
+ * - XenBus state has been reconfigure (pci unplug). See xen_pcibk_remove_device
+ * - XenBus state has been disconnected (guest shutdown). See xen_pcibk_xenbus_remove
+ * - 'echo BDF > unbind' on pciback module with no guest attached. See pcistub_remove
+ * - 'echo BDF > unbind' with a guest still using it. See pcistub_remove
+ *
+ * As such we have to be careful.
+ */
void pcistub_put_pci_dev(struct pci_dev *dev)
{
struct pcistub_device *psdev, *found_psdev = NULL;
@@ -231,11 +276,21 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
/* Cleanup our device
* (so it's ready for the next domain)
*/
- xen_pcibk_reset_device(found_psdev->dev);
- xen_pcibk_config_free_dyn_fields(found_psdev->dev);
- xen_pcibk_config_reset_dev(found_psdev->dev);
- xen_unregister_device_domain_owner(found_psdev->dev);
+ /* This is OK - we are running from workqueue context
+ * and want to inhibit the user from fiddling with 'reset'
+ */
+ pci_reset_function(dev);
+ pci_restore_state(dev);
+
+ /* This disables the device. */
+ xen_pcibk_reset_device(dev);
+
+ /* And cleanup up our emulated fields. */
+ xen_pcibk_config_reset_dev(dev);
+ xen_pcibk_config_free_dyn_fields(dev);
+
+ xen_unregister_device_domain_owner(dev);
spin_lock_irqsave(&found_psdev->lock, flags);
found_psdev->pdev = NULL;
@@ -245,8 +300,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
up_write(&pcistub_sem);
}
-static int __devinit pcistub_match_one(struct pci_dev *dev,
- struct pcistub_device_id *pdev_id)
+static int pcistub_match_one(struct pci_dev *dev,
+ struct pcistub_device_id *pdev_id)
{
/* Match the specified device by domain, bus, slot, func and also if
* any of the device's parent bridges match.
@@ -265,7 +320,7 @@ static int __devinit pcistub_match_one(struct pci_dev *dev,
return 0;
}
-static int __devinit pcistub_match(struct pci_dev *dev)
+static int pcistub_match(struct pci_dev *dev)
{
struct pcistub_device_id *pdev_id;
unsigned long flags;
@@ -283,7 +338,7 @@ static int __devinit pcistub_match(struct pci_dev *dev)
return found;
}
-static int __devinit pcistub_init_device(struct pci_dev *dev)
+static int pcistub_init_device(struct pci_dev *dev)
{
struct xen_pcibk_dev_data *dev_data;
int err = 0;
@@ -328,6 +383,30 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
if (err)
goto config_release;
+ if (dev->msix_cap) {
+ struct physdev_pci_device ppdev = {
+ .seg = pci_domain_nr(dev->bus),
+ .bus = dev->bus->number,
+ .devfn = dev->devfn
+ };
+
+ err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev);
+ if (err)
+ dev_err(&dev->dev, "MSI-X preparation failed (%d)\n",
+ err);
+ }
+
+ /* We need the device active to save the state. */
+ dev_dbg(&dev->dev, "save state of device\n");
+ pci_save_state(dev);
+ dev_data->pci_saved_state = pci_store_saved_state(dev);
+ if (!dev_data->pci_saved_state)
+ dev_err(&dev->dev, "Could not store PCI conf saved state!\n");
+ else {
+ dev_dbg(&dev->dev, "resetting (FLR, D3, etc) the device\n");
+ __pci_reset_function_locked(dev);
+ pci_restore_state(dev);
+ }
/* Now disable the device (this also ensures some private device
* data is setup before we export)
*/
@@ -358,8 +437,6 @@ static int __init pcistub_init_devices_late(void)
unsigned long flags;
int err = 0;
- pr_debug(DRV_NAME ": pcistub_init_devices_late\n");
-
spin_lock_irqsave(&pcistub_devices_lock, flags);
while (!list_empty(&seized_devices)) {
@@ -390,7 +467,7 @@ static int __init pcistub_init_devices_late(void)
return 0;
}
-static int __devinit pcistub_seize(struct pci_dev *dev)
+static int pcistub_seize(struct pci_dev *dev)
{
struct pcistub_device *psdev;
unsigned long flags;
@@ -425,8 +502,9 @@ static int __devinit pcistub_seize(struct pci_dev *dev)
return err;
}
-static int __devinit pcistub_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+/* Called when 'bind'. This means we must _NOT_ call pci_reset_function or
+ * other functions that take the sysfs lock. */
+static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int err = 0;
@@ -453,6 +531,8 @@ out:
return err;
}
+/* Called when 'unbind'. This means we must _NOT_ call pci_reset_function or
+ * other functions that take the sysfs lock. */
static void pcistub_remove(struct pci_dev *dev)
{
struct pcistub_device *psdev, *found_psdev = NULL;
@@ -478,16 +558,14 @@ static void pcistub_remove(struct pci_dev *dev)
found_psdev->pdev);
if (found_psdev->pdev) {
- printk(KERN_WARNING DRV_NAME ": ****** removing device "
- "%s while still in-use! ******\n",
+ pr_warn("****** removing device %s while still in-use! ******\n",
pci_name(found_psdev->dev));
- printk(KERN_WARNING DRV_NAME ": ****** driver domain may"
- " still access this device's i/o resources!\n");
- printk(KERN_WARNING DRV_NAME ": ****** shutdown driver "
- "domain before binding device\n");
- printk(KERN_WARNING DRV_NAME ": ****** to other drivers "
- "or domains\n");
+ pr_warn("****** driver domain may still access this device's i/o resources!\n");
+ pr_warn("****** shutdown driver domain before binding device\n");
+ pr_warn("****** to other drivers or domains\n");
+ /* N.B. This ends up calling pcistub_put_pci_dev which ends up
+ * doing the FLR. */
xen_pcibk_release_pci_dev(found_psdev->pdev,
found_psdev->dev);
}
@@ -646,14 +724,14 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev)
dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
" by HVM, kill it\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
if (!test_bit(_XEN_PCIB_AERHANDLER,
(unsigned long *)&psdev->pdev->sh_info->flags)) {
dev_err(&dev->dev,
"guest with no AER driver should have been killed\n");
- goto release;
+ goto end;
}
result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result);
@@ -663,9 +741,9 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev)
"No AER slot_reset service or disconnected!\n");
kill_domain_by_device(psdev);
}
-release:
- pcistub_device_put(psdev);
end:
+ if (psdev)
+ pcistub_device_put(psdev);
up_write(&pcistub_sem);
return result;
@@ -704,14 +782,14 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev)
dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
" by HVM, kill it\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
if (!test_bit(_XEN_PCIB_AERHANDLER,
(unsigned long *)&psdev->pdev->sh_info->flags)) {
dev_err(&dev->dev,
"guest with no AER driver should have been killed\n");
- goto release;
+ goto end;
}
result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result);
@@ -721,9 +799,9 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev)
"No AER mmio_enabled service or disconnected!\n");
kill_domain_by_device(psdev);
}
-release:
- pcistub_device_put(psdev);
end:
+ if (psdev)
+ pcistub_device_put(psdev);
up_write(&pcistub_sem);
return result;
}
@@ -762,7 +840,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
" by HVM, kill it\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
/*Guest owns the device yet no aer handler regiested, kill guest*/
@@ -770,7 +848,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
(unsigned long *)&psdev->pdev->sh_info->flags)) {
dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result);
@@ -780,9 +858,9 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
"No AER error_detected service or disconnected!\n");
kill_domain_by_device(psdev);
}
-release:
- pcistub_device_put(psdev);
end:
+ if (psdev)
+ pcistub_device_put(psdev);
up_write(&pcistub_sem);
return result;
}
@@ -816,7 +894,7 @@ static void xen_pcibk_error_resume(struct pci_dev *dev)
dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
" by HVM, kill it\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
if (!test_bit(_XEN_PCIB_AERHANDLER,
@@ -824,19 +902,19 @@ static void xen_pcibk_error_resume(struct pci_dev *dev)
dev_err(&dev->dev,
"guest with no AER driver should have been killed\n");
kill_domain_by_device(psdev);
- goto release;
+ goto end;
}
common_process(psdev, 1, XEN_PCI_OP_aer_resume,
PCI_ERS_RESULT_RECOVERED);
-release:
- pcistub_device_put(psdev);
end:
+ if (psdev)
+ pcistub_device_put(psdev);
up_write(&pcistub_sem);
return;
}
/*add xen_pcibk AER handling*/
-static struct pci_error_handlers xen_pcibk_error_handler = {
+static const struct pci_error_handlers xen_pcibk_error_handler = {
.error_detected = xen_pcibk_error_detected,
.mmio_enabled = xen_pcibk_mmio_enabled,
.slot_reset = xen_pcibk_slot_reset,
@@ -861,18 +939,35 @@ static struct pci_driver xen_pcibk_pci_driver = {
static inline int str_to_slot(const char *buf, int *domain, int *bus,
int *slot, int *func)
{
- int err;
-
- err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
- if (err == 4)
+ int parsed = 0;
+
+ switch (sscanf(buf, " %x:%x:%x.%x %n", domain, bus, slot, func,
+ &parsed)) {
+ case 3:
+ *func = -1;
+ sscanf(buf, " %x:%x:%x.* %n", domain, bus, slot, &parsed);
+ break;
+ case 2:
+ *slot = *func = -1;
+ sscanf(buf, " %x:%x:*.* %n", domain, bus, &parsed);
+ break;
+ }
+ if (parsed && !buf[parsed])
return 0;
- else if (err < 0)
- return -EINVAL;
/* try again without domain */
*domain = 0;
- err = sscanf(buf, " %x:%x.%x", bus, slot, func);
- if (err == 3)
+ switch (sscanf(buf, " %x:%x.%x %n", bus, slot, func, &parsed)) {
+ case 2:
+ *func = -1;
+ sscanf(buf, " %x:%x.* %n", bus, slot, &parsed);
+ break;
+ case 1:
+ *slot = *func = -1;
+ sscanf(buf, " %x:*.* %n", bus, &parsed);
+ break;
+ }
+ if (parsed && !buf[parsed])
return 0;
return -EINVAL;
@@ -881,13 +976,20 @@ static inline int str_to_slot(const char *buf, int *domain, int *bus,
static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
*slot, int *func, int *reg, int *size, int *mask)
{
- int err;
+ int parsed = 0;
+
+ sscanf(buf, " %x:%x:%x.%x-%x:%x:%x %n", domain, bus, slot, func,
+ reg, size, mask, &parsed);
+ if (parsed && !buf[parsed])
+ return 0;
- err =
- sscanf(buf, " %04x:%02x:%02x.%d-%08x:%1x:%08x", domain, bus, slot,
- func, reg, size, mask);
- if (err == 7)
+ /* try again without domain */
+ *domain = 0;
+ sscanf(buf, " %x:%x.%x-%x:%x:%x %n", bus, slot, func, reg, size,
+ mask, &parsed);
+ if (parsed && !buf[parsed])
return 0;
+
return -EINVAL;
}
@@ -895,6 +997,30 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
{
struct pcistub_device_id *pci_dev_id;
unsigned long flags;
+ int rc = 0, devfn = PCI_DEVFN(slot, func);
+
+ if (slot < 0) {
+ for (slot = 0; !rc && slot < 32; ++slot)
+ rc = pcistub_device_id_add(domain, bus, slot, func);
+ return rc;
+ }
+
+ if (func < 0) {
+ for (func = 0; !rc && func < 8; ++func)
+ rc = pcistub_device_id_add(domain, bus, slot, func);
+ return rc;
+ }
+
+ if ((
+#if !defined(MODULE) /* pci_domains_supported is not being exported */ \
+ || !defined(CONFIG_PCI_DOMAINS)
+ !pci_domains_supported ? domain :
+#endif
+ domain < 0 || domain > 0xffff)
+ || bus < 0 || bus > 0xff
+ || PCI_SLOT(devfn) != slot
+ || PCI_FUNC(devfn) != func)
+ return -EINVAL;
pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
if (!pci_dev_id)
@@ -902,9 +1028,9 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
pci_dev_id->domain = domain;
pci_dev_id->bus = bus;
- pci_dev_id->devfn = PCI_DEVFN(slot, func);
+ pci_dev_id->devfn = devfn;
- pr_debug(DRV_NAME ": wants to seize %04x:%02x:%02x.%d\n",
+ pr_debug("wants to seize %04x:%02x:%02x.%d\n",
domain, bus, slot, func);
spin_lock_irqsave(&device_ids_lock, flags);
@@ -917,15 +1043,15 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
{
struct pcistub_device_id *pci_dev_id, *t;
- int devfn = PCI_DEVFN(slot, func);
int err = -ENOENT;
unsigned long flags;
spin_lock_irqsave(&device_ids_lock, flags);
list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids,
slot_list) {
- if (pci_dev_id->domain == domain
- && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
+ if (pci_dev_id->domain == domain && pci_dev_id->bus == bus
+ && (slot < 0 || PCI_SLOT(pci_dev_id->devfn) == slot)
+ && (func < 0 || PCI_FUNC(pci_dev_id->devfn) == func)) {
/* Don't break; here because it's possible the same
* slot could be in the list more than once
*/
@@ -934,8 +1060,8 @@ static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
err = 0;
- pr_debug(DRV_NAME ": removed %04x:%02x:%02x.%d from "
- "seize list\n", domain, bus, slot, func);
+ pr_debug("removed %04x:%02x:%02x.%d from seize list\n",
+ domain, bus, slot, func);
}
}
spin_unlock_irqrestore(&device_ids_lock, flags);
@@ -943,16 +1069,20 @@ static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
return err;
}
-static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
- int size, int mask)
+static int pcistub_reg_add(int domain, int bus, int slot, int func,
+ unsigned int reg, unsigned int size,
+ unsigned int mask)
{
int err = 0;
struct pcistub_device *psdev;
struct pci_dev *dev;
struct config_field *field;
+ if (reg > 0xfff || (size < 4 && (mask >> (size * 8))))
+ return -EINVAL;
+
psdev = pcistub_device_find(domain, bus, slot, func);
- if (!psdev || !psdev->dev) {
+ if (!psdev) {
err = -ENODEV;
goto out;
}
@@ -976,6 +1106,8 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
if (err)
kfree(field);
out:
+ if (psdev)
+ pcistub_device_put(psdev);
return err;
}
@@ -1076,20 +1208,23 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
struct pcistub_device *psdev;
struct xen_pcibk_dev_data *dev_data;
int domain, bus, slot, func;
- int err = -ENOENT;
+ int err;
err = str_to_slot(buf, &domain, &bus, &slot, &func);
if (err)
- goto out;
+ return err;
psdev = pcistub_device_find(domain, bus, slot, func);
-
- if (!psdev)
+ if (!psdev) {
+ err = -ENOENT;
goto out;
+ }
dev_data = pci_get_drvdata(psdev->dev);
- if (!dev_data)
+ if (!dev_data) {
+ err = -ENOENT;
goto out;
+ }
dev_dbg(&psdev->dev->dev, "%s fake irq handler: %d->%d\n",
dev_data->irq_name, dev_data->isr_on,
@@ -1099,6 +1234,8 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
if (dev_data->isr_on)
dev_data->ack_intr = 1;
out:
+ if (psdev)
+ pcistub_device_put(psdev);
if (!err)
err = count;
return err;
@@ -1178,18 +1315,17 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf,
int err;
struct pcistub_device *psdev;
struct xen_pcibk_dev_data *dev_data;
+
err = str_to_slot(buf, &domain, &bus, &slot, &func);
if (err)
goto out;
+
psdev = pcistub_device_find(domain, bus, slot, func);
if (!psdev) {
err = -ENODEV;
goto out;
}
- if (!psdev->dev) {
- err = -ENODEV;
- goto release;
- }
+
dev_data = pci_get_drvdata(psdev->dev);
/* the driver data for a device should never be null at this point */
if (!dev_data) {
@@ -1267,22 +1403,51 @@ static int __init pcistub_init(void)
err = sscanf(pci_devs_to_hide + pos,
" (%x:%x:%x.%x) %n",
&domain, &bus, &slot, &func, &parsed);
- if (err != 4) {
+ switch (err) {
+ case 3:
+ func = -1;
+ sscanf(pci_devs_to_hide + pos,
+ " (%x:%x:%x.*) %n",
+ &domain, &bus, &slot, &parsed);
+ break;
+ case 2:
+ slot = func = -1;
+ sscanf(pci_devs_to_hide + pos,
+ " (%x:%x:*.*) %n",
+ &domain, &bus, &parsed);
+ break;
+ }
+
+ if (!parsed) {
domain = 0;
err = sscanf(pci_devs_to_hide + pos,
" (%x:%x.%x) %n",
&bus, &slot, &func, &parsed);
- if (err != 3)
- goto parse_error;
+ switch (err) {
+ case 2:
+ func = -1;
+ sscanf(pci_devs_to_hide + pos,
+ " (%x:%x.*) %n",
+ &bus, &slot, &parsed);
+ break;
+ case 1:
+ slot = func = -1;
+ sscanf(pci_devs_to_hide + pos,
+ " (%x:*.*) %n",
+ &bus, &parsed);
+ break;
+ }
}
+ if (parsed <= 0)
+ goto parse_error;
+
err = pcistub_device_id_add(domain, bus, slot, func);
if (err)
goto out;
- /* if parsed<=0, we've reached the end of the string */
pos += parsed;
- } while (parsed > 0 && pci_devs_to_hide[pos]);
+ } while (pci_devs_to_hide[pos]);
}
/* If we're the first PCI Device Driver to register, we're the
@@ -1321,7 +1486,7 @@ out:
return err;
parse_error:
- printk(KERN_ERR DRV_NAME ": Error parsing pci_devs_to_hide at \"%s\"\n",
+ pr_err("Error parsing pci_devs_to_hide at \"%s\"\n",
pci_devs_to_hide + pos);
return -EINVAL;
}