From fb51ccbf217c1c994607b6519c7d85250928553d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 4 Nov 2011 09:45:59 +0100 Subject: PCI: Rework config space blocking services pci_block_user_cfg_access was designed for the use case that a single context, the IPR driver, temporarily delays user space accesses to the config space via sysfs. This assumption became invalid by the time pci_dev_reset was added as locking instance. Today, if you run two loops in parallel that reset the same device via sysfs, you end up with a kernel BUG as pci_block_user_cfg_access detect the broken assumption. This reworks the pci_block_user_cfg_access to a sleeping service pci_cfg_access_lock and an atomic-compatible variant called pci_cfg_access_trylock. The former not only blocks user space access as before but also waits if access was already locked. The latter service just returns false in this case, allowing the caller to resolve the conflict instead of raising a BUG. Adaptions of the ipr driver were originally written by Brian King. Acked-by: Brian King Acked-by: Michael S. Tsirkin Signed-off-by: Jan Kiszka Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6d4a5319148d..c3cca7cdc6e5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2965,7 +2965,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) might_sleep(); if (!probe) { - pci_block_user_cfg_access(dev); + pci_cfg_access_lock(dev); /* block PM suspend, driver probe, etc. */ device_lock(&dev->dev); } @@ -2990,7 +2990,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_cfg_access_unlock(dev); } return rc; -- cgit v1.2.3 From a2e27787f893621c5a6b865acf6b7766f8671328 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 4 Nov 2011 09:46:00 +0100 Subject: PCI: Introduce INTx check & mask API These new PCI services allow to probe for 2.3-compliant INTx masking support and then use the feature from PCI interrupt handlers. The services are properly synchronized with concurrent config space access via sysfs or on device reset. This enables generic PCI device drivers like uio_pci_generic or KVM's device assignment to implement the necessary kernel-side IRQ handling without any knowledge about device-specific interrupt status and control registers. Acked-by: Michael S. Tsirkin Signed-off-by: Jan Kiszka Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c3cca7cdc6e5..924193ef4fe1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2767,6 +2767,116 @@ pci_intx(struct pci_dev *pdev, int enable) } } +/** + * pci_intx_mask_supported - probe for INTx masking support + * @pdev: the PCI device to operate on + * + * Check if the device dev support INTx masking via the config space + * command word. + */ +bool pci_intx_mask_supported(struct pci_dev *dev) +{ + bool mask_supported = false; + u16 orig, new; + + pci_cfg_access_lock(dev); + + pci_read_config_word(dev, PCI_COMMAND, &orig); + pci_write_config_word(dev, PCI_COMMAND, + orig ^ PCI_COMMAND_INTX_DISABLE); + pci_read_config_word(dev, PCI_COMMAND, &new); + + /* + * There's no way to protect against hardware bugs or detect them + * reliably, but as long as we know what the value should be, let's + * go ahead and check it. + */ + if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { + dev_err(&dev->dev, "Command register changed from " + "0x%x to 0x%x: driver or hardware bug?\n", orig, new); + } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) { + mask_supported = true; + pci_write_config_word(dev, PCI_COMMAND, orig); + } + + pci_cfg_access_unlock(dev); + return mask_supported; +} +EXPORT_SYMBOL_GPL(pci_intx_mask_supported); + +static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) +{ + struct pci_bus *bus = dev->bus; + bool mask_updated = true; + u32 cmd_status_dword; + u16 origcmd, newcmd; + unsigned long flags; + bool irq_pending; + + /* + * We do a single dword read to retrieve both command and status. + * Document assumptions that make this possible. + */ + BUILD_BUG_ON(PCI_COMMAND % 4); + BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); + + raw_spin_lock_irqsave(&pci_lock, flags); + + bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); + + irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; + + /* + * Check interrupt status register to see whether our device + * triggered the interrupt (when masking) or the next IRQ is + * already pending (when unmasking). + */ + if (mask != irq_pending) { + mask_updated = false; + goto done; + } + + origcmd = cmd_status_dword; + newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; + if (mask) + newcmd |= PCI_COMMAND_INTX_DISABLE; + if (newcmd != origcmd) + bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); + +done: + raw_spin_unlock_irqrestore(&pci_lock, flags); + + return mask_updated; +} + +/** + * pci_check_and_mask_intx - mask INTx on pending interrupt + * @pdev: the PCI device to operate on + * + * Check if the device dev has its INTx line asserted, mask it and + * return true in that case. False is returned if not interrupt was + * pending. + */ +bool pci_check_and_mask_intx(struct pci_dev *dev) +{ + return pci_check_and_set_intx_mask(dev, true); +} +EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); + +/** + * pci_check_and_mask_intx - unmask INTx of no interrupt is pending + * @pdev: the PCI device to operate on + * + * Check if the device dev has its INTx line asserted, unmask it if not + * and return true. False is returned and the mask remains active if + * there was still an interrupt pending. + */ +bool pci_check_and_unmask_intx(struct pci_dev *dev) +{ + return pci_check_and_set_intx_mask(dev, false); +} +EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); + /** * pci_msi_off - disables any msi or msix capabilities * @dev: the PCI device to operate on -- cgit v1.2.3 From 96c5590058d7fded14f43af2ab521436cecf3125 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Fri, 28 Oct 2011 15:48:38 -0600 Subject: PCI: Pull PCI 'latency timer' setup up into the core The 'latency timer' of PCI devices, both Type 0 and Type 1, is setup in architecture-specific code [see: 'pcibios_set_master()']. There are two approaches being taken by all the architectures - check if the 'latency timer' is currently set between 16 and 255 and if not bring it within bounds, or, do nothing (and then there is the gratuitously different PA-RISC implementation). There is nothing architecture-specific about PCI's 'latency timer' so this patch pulls its setup functionality up into the PCI core by creating a generic 'pcibios_set_master()' function using the '__weak' attribute which can be used by all architectures as a default which, if necessary, can then be over-ridden by architecture-specific code. No functional change. Signed-off-by: Myron Stowe Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 924193ef4fe1..f9abe84cf5e0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -88,6 +88,12 @@ enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2; u8 pci_cache_line_size; +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as certain BIOSes forget to set it properly. + */ +unsigned int pcibios_max_latency = 255; + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -2595,6 +2601,29 @@ static void __pci_set_master(struct pci_dev *dev, bool enable) dev->is_busmaster = enable; } +/** + * pcibios_set_master - enable PCI bus-mastering for device dev + * @dev: the PCI device to enable + * + * Enables PCI bus-mastering for the device. This is the default + * implementation. Architecture specific implementations can override + * this if necessary. + */ +void __weak pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + /** * pci_set_master - enables bus-mastering for device dev * @dev: the PCI device to enable -- cgit v1.2.3 From f676678f8952d5e2bfc03903dba410c856ae3f3d Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Fri, 28 Oct 2011 15:49:20 -0600 Subject: PCI: latency timer doesn't apply to PCIe The latency timer is read-only and hardwired to zero for all PCIe devices, both Type 0 and Type 1, so don't bother trying to update it and cluttering the dmesg log with meaningless "setting latency timer to 64" messages. Signed-off-by: Myron Stowe Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f9abe84cf5e0..5c5adef85bd7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2613,6 +2613,10 @@ void __weak pcibios_set_master(struct pci_dev *dev) { u8 lat; + /* The latency timer doesn't apply to PCIe (either Type 0 or Type 1) */ + if (pci_is_pcie(dev)) + return; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); if (lat < 16) lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; -- cgit v1.2.3 From 85b8582d7ca516030efb84d94fa29a73c1d9a125 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Mon, 5 Dec 2011 11:51:18 -0800 Subject: PCI/PM/Runtime: make PCI traces quieter When the runtime PM is activated on PCI, if a device switches state frequently (e.g. an EHCI controller with autosuspending USB devices connected) the PCI configuration traces might be very verbose in the kernel log. Let's guard those traces with DEBUG condition. Acked-by: "Rafael J. Wysocki" Signed-off-by: Vincent Palatin Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5c5adef85bd7..54343aa5b30a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -973,7 +973,7 @@ void pci_restore_state(struct pci_dev *dev) for (i = 15; i >= 0; i--) { pci_read_config_dword(dev, i * 4, &val); if (val != dev->saved_config_space[i]) { - dev_printk(KERN_DEBUG, &dev->dev, "restoring config " + dev_dbg(&dev->dev, "restoring config " "space at offset %#x (was %#x, writing %#x)\n", i, val, (int)dev->saved_config_space[i]); pci_write_config_dword(dev,i * 4, @@ -1542,8 +1542,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) } out: - dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n", - enable ? "enabled" : "disabled"); + dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled"); } /** -- cgit v1.2.3 From 1900ca132f53c3d51e6e6b94ea8912530223c63a Mon Sep 17 00:00:00 2001 From: "Hao, Xudong" Date: Sat, 17 Dec 2011 21:24:40 +0800 Subject: PCI: Enable ATS at the device state restore During S3 or S4 resume or PCI reset, ATS regs aren't restored correctly. This patch enables ATS at the device state restore if PCI device has ATS capability. Signed-off-by: Xudong Hao Signed-off-by: Xiantao Zhang Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 54343aa5b30a..97fff785e97e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -965,6 +965,7 @@ void pci_restore_state(struct pci_dev *dev) /* PCI Express register must be restored first */ pci_restore_pcie_state(dev); + pci_restore_ats_state(dev); /* * The Base Address register should be programmed before the command -- cgit v1.2.3