Message ID | 20110829150552.GA6851@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On 2011-08-29 18:23, Michael S. Tsirkin wrote: > On Mon, Aug 29, 2011 at 06:14:39PM +0200, Jan Kiszka wrote: >> On 2011-08-29 17:58, Michael S. Tsirkin wrote: >>> On Mon, Aug 29, 2011 at 05:42:16PM +0200, Jan Kiszka wrote: >>>> I still don't get what prevents converting ipr to allow plain mutex >>>> synchronization. My vision is: >>>> - push reset-on-error of ipr into workqueue (or threaded IRQ?) >>>> - require mutex synchronization for common config space access >>> >>> Meaning pci_user_ read/write config? >> >> And pci_dev_reset, yes. >> >>> >>>> and the >>>> full reset cycle >>>> - only exception: INTx status/masking access >>>> => use pci_lock + test for reset_in_progress, skip operation if >>>> that is the case >>>> >>>> That would allow to drop the whole block_user_cfg infrastructure. >>>> >>>> Jan >>> >>> We still need to block userspace access while INTx does >>> the status/masking access, right? >> >> Yes, pci_lock would do that for us. > > Well this means block_user_cfg is not going away, > this is what it really is: pci_lock + a bit to lock out userspace. I does as we only end up with a mutex and pci_lock. No more hand-crafted queuing/blocking/waking. INTx masking is a bit special as it's the only thing that truly requires atomic context. But that's something we should address generically anyway. Jan
On Mon, Aug 29, 2011 at 08:47:07PM +0200, Jan Kiszka wrote: > On 2011-08-29 17:42, Jan Kiszka wrote: > > I still don't get what prevents converting ipr to allow plain mutex > > synchronization. My vision is: > > - push reset-on-error of ipr into workqueue (or threaded IRQ?) > > I'm starting to like your proposal: I had a look at ipr, but it turned > out to be anything but trivial to convert that driver. It runs its > complete state machine under spin_lock_irq, and the functions calling > pci_block/unblock_user_cfg_access are deep inside this thing. I have no > hardware to test whatever change, and I feel a bit uncomfortable asking > Brian to redesign his driver that massively. > > So back to your idea: I would generalize pci_block_user_cfg_access to > pci_block_cfg_access. It should fail when some other site already holds > the access lock, but it should remain non-blocking - for the sake of ipr. It would be easy to have blocking and non-blocking variants. But - I have no idea whether supporting sysfs config/reset access while ipr is active makes any sense - I know we need it for uio. - reset while uio handles interrupt needs to block, not fail I think > We should still provide generic pci-2.3 IRQ masking services, but that > could be done in a second step. I could have a look at this. > > Jan > > -- > Siemens AG, Corporate Technology, CT T DE IT 1 > Corporate Competence Center Embedded Linux -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/29/2011 02:18 PM, Michael S. Tsirkin wrote: > On Mon, Aug 29, 2011 at 08:47:07PM +0200, Jan Kiszka wrote: >> On 2011-08-29 17:42, Jan Kiszka wrote: >>> I still don't get what prevents converting ipr to allow plain mutex >>> synchronization. My vision is: >>> - push reset-on-error of ipr into workqueue (or threaded IRQ?) >> >> I'm starting to like your proposal: I had a look at ipr, but it turned >> out to be anything but trivial to convert that driver. It runs its >> complete state machine under spin_lock_irq, and the functions calling >> pci_block/unblock_user_cfg_access are deep inside this thing. I have no >> hardware to test whatever change, and I feel a bit uncomfortable asking >> Brian to redesign his driver that massively. >> >> So back to your idea: I would generalize pci_block_user_cfg_access to >> pci_block_cfg_access. It should fail when some other site already holds >> the access lock, but it should remain non-blocking - for the sake of ipr. > > It would be easy to have blocking and non-blocking variants. > > But > - I have no idea whether supporting sysfs config/reset access > while ipr is active makes any sense - I know we need it for uio. I really don't think it makes sense. Ideally, I really think the driver should be able to override the PCI layer reset interface in sysfs. If a driver is loaded, the driver owns all the state of that device and resetting it without informing the driver is just nasty. Additionally, many devices may have much more complex logic to performing a reset than what PCI defines. With ipr, for example, it needs to get a shutdown command issued to it prior to the reset if at all possible so that the firmware quiesces any I/O it is performing. It also needs additional communication prior to resetting the chip to ensure the firmware is not modifying its persistent error log on the adapter's flash, since resetting the card while the flash segment is being updated will cause the adapter to lose the persistent error log. Post reset, ipr has a bunch of work to do to get the firmware back up and running to a state where it can handle I/O again. Different ipr chips also have different requirements as to what reset mechanisms defined by PCI actually work. Some chips require BIST to be run via PCI config space, while others require a PCI warm reset, otherwise the card ends up in an unusable state. So, here is my proposal to resolve this particular issue. Add a reset function to the pci_driver struct which would allow drivers to override the default reset action. Drivers that can tolerate the existing reset mechanism can simply point to a generic PCI function to perform the reset. Drivers which can't handle their device getting reset, will simply not have a reset function defined. In this case, anyone attempting to issue a reset via sysfs will get an error. If a driver is not loaded, then we can perform the default reset method and fix any device specific oddities with quirks. I like keeping pci_block_user_cfg_access a non blocking interface. If it can return a failure due to some other caller, it should be easy enough to modify the ipr driver to wait for access to get unblocked before resetting the adapter. Thanks, Brian
On Tue, Aug 30, 2011 at 11:30:35AM -0500, Brian King wrote: > On 08/29/2011 02:18 PM, Michael S. Tsirkin wrote: > > On Mon, Aug 29, 2011 at 08:47:07PM +0200, Jan Kiszka wrote: > >> On 2011-08-29 17:42, Jan Kiszka wrote: > >>> I still don't get what prevents converting ipr to allow plain mutex > >>> synchronization. My vision is: > >>> - push reset-on-error of ipr into workqueue (or threaded IRQ?) > >> > >> I'm starting to like your proposal: I had a look at ipr, but it turned > >> out to be anything but trivial to convert that driver. It runs its > >> complete state machine under spin_lock_irq, and the functions calling > >> pci_block/unblock_user_cfg_access are deep inside this thing. I have no > >> hardware to test whatever change, and I feel a bit uncomfortable asking > >> Brian to redesign his driver that massively. > >> > >> So back to your idea: I would generalize pci_block_user_cfg_access to > >> pci_block_cfg_access. It should fail when some other site already holds > >> the access lock, but it should remain non-blocking - for the sake of ipr. > > > > It would be easy to have blocking and non-blocking variants. > > > > But > > - I have no idea whether supporting sysfs config/reset access > > while ipr is active makes any sense - I know we need it for uio. > > I really don't think it makes sense. Ideally, I really think the driver > should be able to override the PCI layer reset interface in sysfs. Well, it's always possible for root to do silly things like reset the device from userspace using sysfs config access. So I don't really see this blocking as necessary: broken application with access to a physical device will lead to problems. > If a driver > is loaded, the driver owns all the state of that device and resetting it without > informing the driver is just nasty. Additionally, many devices may have > much more complex logic to performing a reset than what PCI defines. With > ipr, for example, it needs to get a shutdown command issued to it prior to the > reset if at all possible so that the firmware quiesces any I/O it is performing. > It also needs additional communication prior to resetting the chip to ensure > the firmware is not modifying its persistent error log on the adapter's flash, > since resetting the card while the flash segment is being updated will cause > the adapter to lose the persistent error log. Post reset, ipr has a bunch > of work to do to get the firmware back up and running to a state where it > can handle I/O again. > > Different ipr chips also have different requirements as to what > reset mechanisms defined by PCI actually work. Some chips require BIST to be > run via PCI config space, while others require a PCI warm reset, otherwise > the card ends up in an unusable state. > > So, here is my proposal to resolve this particular issue. As userspace has no place touching the device while ipr is active, there's no issue with ipr at all, is there? > Add a reset function > to the pci_driver struct which would allow drivers to override the default reset > action. Drivers that can tolerate the existing reset mechanism can simply point > to a generic PCI function to perform the reset. Drivers which can't handle their > device getting reset, will simply not have a reset function defined. In this case, > anyone attempting to issue a reset via sysfs will get an error. If a driver > is not loaded, then we can perform the default reset method and fix any device > specific oddities with quirks. > > I like keeping pci_block_user_cfg_access a non blocking interface. If it can > return a failure due to some other caller, it should be easy enough to modify > the ipr driver to wait for access to get unblocked before resetting the adapter. > > Thanks, > > Brian There shouldn't be other callers though, should there? So it might be enough to fail gracefully (to make debugging easier) rather than retry. > -- > Brian King > Linux on Power Virtualization > IBM Linux Technology Center > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/30/2011 01:01 PM, Michael S. Tsirkin wrote: > On Tue, Aug 30, 2011 at 11:30:35AM -0500, Brian King wrote: >> On 08/29/2011 02:18 PM, Michael S. Tsirkin wrote: >>> On Mon, Aug 29, 2011 at 08:47:07PM +0200, Jan Kiszka wrote: >>>> On 2011-08-29 17:42, Jan Kiszka wrote: >>>>> I still don't get what prevents converting ipr to allow plain mutex >>>>> synchronization. My vision is: >>>>> - push reset-on-error of ipr into workqueue (or threaded IRQ?) >>>> >>>> I'm starting to like your proposal: I had a look at ipr, but it turned >>>> out to be anything but trivial to convert that driver. It runs its >>>> complete state machine under spin_lock_irq, and the functions calling >>>> pci_block/unblock_user_cfg_access are deep inside this thing. I have no >>>> hardware to test whatever change, and I feel a bit uncomfortable asking >>>> Brian to redesign his driver that massively. >>>> >>>> So back to your idea: I would generalize pci_block_user_cfg_access to >>>> pci_block_cfg_access. It should fail when some other site already holds >>>> the access lock, but it should remain non-blocking - for the sake of ipr. >>> >>> It would be easy to have blocking and non-blocking variants. >>> >>> But >>> - I have no idea whether supporting sysfs config/reset access >>> while ipr is active makes any sense - I know we need it for uio. >> >> I really don't think it makes sense. Ideally, I really think the driver >> should be able to override the PCI layer reset interface in sysfs. > > Well, it's always possible for root to do silly things > like reset the device from userspace using sysfs config > access. So I don't really see this blocking as necessary: > broken application with access to a physical device will lead > to problems. I agree that it is probably not necessary for the current use of the sysfs API, but if there was interest in expanding it to be usable for other purposes, we might need to do something like what I am proposing. However, it doesn't appear that anyone has any immediate need for doing so. > > >> If a driver >> is loaded, the driver owns all the state of that device and resetting it without >> informing the driver is just nasty. Additionally, many devices may have >> much more complex logic to performing a reset than what PCI defines. With >> ipr, for example, it needs to get a shutdown command issued to it prior to the >> reset if at all possible so that the firmware quiesces any I/O it is performing. >> It also needs additional communication prior to resetting the chip to ensure >> the firmware is not modifying its persistent error log on the adapter's flash, >> since resetting the card while the flash segment is being updated will cause >> the adapter to lose the persistent error log. Post reset, ipr has a bunch >> of work to do to get the firmware back up and running to a state where it >> can handle I/O again. >> >> Different ipr chips also have different requirements as to what >> reset mechanisms defined by PCI actually work. Some chips require BIST to be >> run via PCI config space, while others require a PCI warm reset, otherwise >> the card ends up in an unusable state. >> >> So, here is my proposal to resolve this particular issue. > > As userspace has no place touching the device while > ipr is active, there's no issue with ipr at all, is there? Correct. >> Add a reset function >> to the pci_driver struct which would allow drivers to override the default reset >> action. Drivers that can tolerate the existing reset mechanism can simply point >> to a generic PCI function to perform the reset. Drivers which can't handle their >> device getting reset, will simply not have a reset function defined. In this case, >> anyone attempting to issue a reset via sysfs will get an error. If a driver >> is not loaded, then we can perform the default reset method and fix any device >> specific oddities with quirks. >> >> I like keeping pci_block_user_cfg_access a non blocking interface. If it can >> return a failure due to some other caller, it should be easy enough to modify >> the ipr driver to wait for access to get unblocked before resetting the adapter. >> >> Thanks, >> >> Brian > > There shouldn't be other callers though, should there? > So it might be enough to fail gracefully (to make debugging > easier) rather than retry. Actually, its probably not worth the complexity to change much of anything in the ipr driver. With the current users, ipr should be the only caller. If, for some reason, we were double blocked due to ipr, the ipr driver already handles that today just fine and having the second block essentially be a noop is fine, since we will only get a single unblock due to ipr's reset state machine. If another caller is added in the future, then we will need to make potential changes, but without knowing the use case, its not clear to me what the proper action would be anyway. Thanks, Brian
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index fdaa42a..2492365 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -139,7 +139,7 @@ static noinline void pci_wait_ucfg(struct pci_dev *dev) raw_spin_unlock_irq(&pci_lock); schedule(); raw_spin_lock_irq(&pci_lock); - } while (dev->block_ucfg_access); + } while (dev->block_ucfg_access || dev->reset_in_progress); __remove_wait_queue(&pci_ucfg_wait, &wait); } @@ -153,7 +153,8 @@ int pci_user_read_config_##size \ if (PCI_##size##_BAD) \ return -EINVAL; \ raw_spin_lock_irq(&pci_lock); \ - if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \ + if (unlikely(dev->block_ucfg_access || dev->reset_in_progress)) \ + pci_wait_ucfg(dev); \ ret = dev->bus->ops->read(dev->bus, dev->devfn, \ pos, sizeof(type), &data); \ raw_spin_unlock_irq(&pci_lock); \ @@ -171,8 +172,9 @@ int pci_user_write_config_##size \ int ret = -EIO; \ if (PCI_##size##_BAD) \ return -EINVAL; \ - raw_spin_lock_irq(&pci_lock); \ - if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \ + raw_spin_lock_irq(&pci_lock); \ + if (unlikely(dev->block_ucfg_access || dev->reset_in_progress)) \ + pci_wait_ucfg(dev); \ ret = dev->bus->ops->write(dev->bus, dev->devfn, \ pos, sizeof(type), val); \ raw_spin_unlock_irq(&pci_lock); \ @@ -408,19 +410,24 @@ EXPORT_SYMBOL(pci_vpd_truncate); * sleep until access is unblocked again. We don't allow nesting of * block/unblock calls. */ -void pci_block_user_cfg_access(struct pci_dev *dev) +int pci_block_user_cfg_access(struct pci_dev *dev) { unsigned long flags; int was_blocked; + int in_progress; raw_spin_lock_irqsave(&pci_lock, flags); was_blocked = dev->block_ucfg_access; dev->block_ucfg_access = 1; + in_progress = dev->reset_in_progress; raw_spin_unlock_irqrestore(&pci_lock, flags); + if (in_progress) + return -EIO; /* If we BUG() inside the pci_lock, we're guaranteed to hose * the machine */ BUG_ON(was_blocked); + return 0; } EXPORT_SYMBOL_GPL(pci_block_user_cfg_access); @@ -445,3 +452,31 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev) raw_spin_unlock_irqrestore(&pci_lock, flags); } EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); + +void pci_reset_start(struct pci_dev *dev) +{ + int was_started; + + raw_spin_lock_irq(&pci_lock); + if (unlikely(dev->block_ucfg_access || dev->reset_in_progress)) + pci_wait_ucfg(dev); + was_started = dev->reset_in_progress; + dev->reset_in_progress = 1; + raw_spin_unlock_irq(&pci_lock); + + /* If we BUG() inside the pci_lock, we're guaranteed to hose + * the machine */ + BUG_ON(was_started); +} +void pci_reset_end(struct pci_dev *dev) +{ + raw_spin_lock_irq(&pci_lock); + + /* This indicates a problem in the caller, but we don't need + * to kill them, unlike a double-reset above. */ + WARN_ON(!dev->reset_in_progress); + + dev->reset_in_progress = 0; + wake_up_all(&pci_ucfg_wait); + raw_spin_unlock_irq(&pci_lock); +} diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 42fae47..464d9b5 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -275,7 +275,7 @@ static void sriov_disable_migration(struct pci_dev *dev) static int sriov_enable(struct pci_dev *dev, int nr_virtfn) { - int rc; + int rc, rc1; int i, j; int nres; u16 offset, stride, initial; @@ -340,7 +340,10 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) } iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; - pci_block_user_cfg_access(dev); + rc = pci_block_user_cfg_access(dev); + if (rc) + goto err; + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); msleep(100); pci_unblock_user_cfg_access(dev); @@ -371,11 +374,14 @@ failed: virtfn_remove(dev, j, 0); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); - pci_block_user_cfg_access(dev); + rc1 = pci_block_user_cfg_access(dev); + if (rc1) + goto err; pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); ssleep(1); pci_unblock_user_cfg_access(dev); +err: if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); @@ -384,7 +390,7 @@ failed: static void sriov_disable(struct pci_dev *dev) { - int i; + int i, rc; struct pci_sriov *iov = dev->sriov; if (!iov->nr_virtfn) @@ -397,11 +403,14 @@ static void sriov_disable(struct pci_dev *dev) virtfn_remove(dev, i, 0); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); - pci_block_user_cfg_access(dev); + rc = pci_block_user_cfg_access(dev); + if (rc) + goto err; pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); ssleep(1); pci_unblock_user_cfg_access(dev); +err: if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0ce6742..815efc2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2959,7 +2959,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) might_sleep(); if (!probe) { - pci_block_user_cfg_access(dev); + pci_reset_start(dev); /* block PM suspend, driver probe, etc. */ device_lock(&dev->dev); } @@ -2984,7 +2984,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) done: if (!probe) { device_unlock(&dev->dev); - pci_unblock_user_cfg_access(dev); + pci_reset_end(dev); } return rc; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 8d63630..d322da3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7661,7 +7661,9 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) int rc = PCIBIOS_SUCCESSFUL; ENTER; - pci_block_user_cfg_access(ioa_cfg->pdev); + rc = pci_block_user_cfg_access(ioa_cfg->pdev); + if (rc) + goto err; if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) writel(IPR_UPROCI_SIS64_START_BIST, @@ -7681,6 +7683,13 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) LEAVE; return rc; + +err: + + ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + rc = IPR_RC_JOB_CONTINUE; + LEAVE; + return rc; } /** @@ -7715,14 +7724,23 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct pci_dev *pdev = ioa_cfg->pdev; + int rc; ENTER; - pci_block_user_cfg_access(pdev); + rc = pci_block_user_cfg_access(pdev); + if (rc) + goto err; + pci_set_pcie_reset_state(pdev, pcie_warm_reset); ipr_cmd->job_step = ipr_reset_slot_reset_done; ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); LEAVE; return IPR_RC_JOB_RETURN; + + ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + rc = IPR_RC_JOB_CONTINUE; + LEAVE; + return rc; } /** diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index fc22e1e..a26d35f 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -51,6 +51,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) irqreturn_t ret = IRQ_NONE; u32 cmd_status_dword; u16 origcmd, newcmd, status; + int r; /* We do a single dword read to retrieve both command and status. * Document assumptions that make this possible. */ @@ -58,7 +59,9 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); spin_lock_irq(&gdev->lock); - pci_block_user_cfg_access(pdev); + r = pci_block_user_cfg_access(pdev); + if (r < 0) + goto err; /* Read both command and status registers in a single 32-bit operation. * Note: we could cache the value for command and move the status read @@ -83,6 +86,8 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) done: pci_unblock_user_cfg_access(pdev); +err: + spin_unlock_irq(&gdev->lock); return ret; } diff --git a/include/linux/pci.h b/include/linux/pci.h index 8c230cb..ec3b8fe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -322,6 +322,7 @@ struct pci_dev { unsigned int is_hotplug_bridge:1; unsigned int __aer_firmware_first_valid:1; unsigned int __aer_firmware_first:1; + unsigned int reset_in_progress:1; pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ @@ -1079,9 +1080,12 @@ int ht_create_irq(struct pci_dev *dev, int idx); void ht_destroy_irq(unsigned int irq); #endif /* CONFIG_HT_IRQ */ -extern void pci_block_user_cfg_access(struct pci_dev *dev); +extern int pci_block_user_cfg_access(struct pci_dev *dev); extern void pci_unblock_user_cfg_access(struct pci_dev *dev); +extern void pci_reset_start(struct pci_dev *dev); +extern void pci_reset_end(struct pci_dev *dev); + /* * PCI domain support. Sometimes called PCI segment (eg by ACPI), * a PCI domain is defined to be a set of PCI busses which share
So how about something like the following? Compile tested only, and I'm not sure I got the ipr and iov error handling right. Comments? ----> Subject: [PATCH] pci: fail block usercfg access on reset Anyone who wants to block usercfg access will also want to block reset from userspace. On the other hand, reset from userspace should block any other access from userspace. Finally, make it possible to detect reset in pregress by returning an error status from pci_block_user_cfg_access. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- drivers/pci/access.c | 45 ++++++++++++++++++++++++++++++++++++---- drivers/pci/iov.c | 19 ++++++++++++---- drivers/pci/pci.c | 4 +- drivers/scsi/ipr.c | 22 ++++++++++++++++++- drivers/uio/uio_pci_generic.c | 7 +++++- include/linux/pci.h | 6 ++++- 6 files changed, 87 insertions(+), 16 deletions(-)