]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'samsung/fixes' of git+ssh://master.kernel.org/pub/scm/linux/kernel...
authorArnd Bergmann <arnd@arndb.de>
Fri, 26 Aug 2011 15:08:19 +0000 (15:08 +0000)
committerArnd Bergmann <arnd@arndb.de>
Fri, 26 Aug 2011 15:08:19 +0000 (15:08 +0000)
165 files changed:
Documentation/PCI/MSI-HOWTO.txt
Documentation/block/cfq-iosched.txt
Documentation/kernel-parameters.txt
Documentation/virtual/00-INDEX
Documentation/virtual/lguest/lguest.c
Documentation/virtual/virtio-spec.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/ia64/Kconfig
arch/ia64/configs/generic_defconfig
arch/sparc/Kconfig
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/kernel/pcic.c
arch/x86/include/asm/xen/page.h
arch/x86/kvm/Kconfig
arch/x86/mm/fault.c
arch/x86/pci/acpi.c
arch/x86/xen/Makefile
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/smp.c
block/Kconfig
block/Makefile
block/blk-core.c
block/blk-flush.c
block/blk-softirq.c
block/blk-throttle.c
block/blk.h
block/bsg-lib.c [new file with mode: 0644]
block/cfq-iosched.c
block/genhd.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/pata_imx.c [new file with mode: 0644]
drivers/ata/pata_via.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_sil.c
drivers/base/power/domain.c
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap.c
drivers/block/Kconfig
drivers/block/drbd/drbd_nl.c
drivers/block/loop.c
drivers/block/swim3.c
drivers/block/xen-blkfront.c
drivers/cdrom/cdrom.c
drivers/edac/i7core_edac.c
drivers/firewire/core-cdev.c
drivers/firewire/core-device.c
drivers/firewire/ohci.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/pci/hotplug/pcihp_slot.c
drivers/pci/of.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/rtc/interface.c
drivers/staging/gma500/mdfld_dsi_dbi.c
drivers/staging/gma500/mdfld_dsi_dbi.h
drivers/staging/gma500/mdfld_dsi_dpi.c
drivers/staging/gma500/mdfld_dsi_output.c
drivers/staging/gma500/medfield.h
drivers/staging/gma500/psb_drv.h
drivers/xen/xen-selfballoon.c
fs/befs/linuxvfs.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cifs/cifs_debug.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/transport.c
fs/ext4/ext4_jbd2.h
fs/ext4/indirect.c
fs/ext4/inode.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/fat/dir.c
fs/fat/inode.c
fs/jfs/jfs_umount.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/objlayout/pnfs_osd_xdr_cli.c
include/asm-generic/memory_model.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bsg-lib.h [new file with mode: 0644]
include/linux/hash.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/loop.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/pci.h
include/linux/pm_domain.h
include/linux/rtc.h
include/trace/events/block.h
kernel/irq/generic-chip.c
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/lockdep.c
kernel/power/Kconfig
kernel/trace/blktrace.c
mm/highmem.c
sound/aoa/fabrics/layout.c
sound/pci/ac97/ac97_patch.c
sound/pci/hda/alc268_quirks.c
sound/pci/hda/hda_eld.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_realtek.c
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.h
sound/usb/mixer.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-stat.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/evlist.c
tools/perf/util/header.c
tools/perf/util/include/linux/compiler.h
tools/perf/util/parse-events.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/ui/browsers/top.c

index 3f5e0b09bed5b29efe2493a3c05857e8c7a56901..53e6fca146d73919e9b7dbc4fd32631a18141795 100644 (file)
@@ -45,7 +45,7 @@ arrived in memory (this becomes more likely with devices behind PCI-PCI
 bridges).  In order to ensure that all the data has arrived in memory,
 the interrupt handler must read a register on the device which raised
 the interrupt.  PCI transaction ordering rules require that all the data
-arrives in memory before the value can be returned from the register.
+arrive in memory before the value may be returned from the register.
 Using MSIs avoids this problem as the interrupt-generating write cannot
 pass the data writes, so by the time the interrupt is raised, the driver
 knows that all the data has arrived in memory.
@@ -86,13 +86,13 @@ device.
 
 int pci_enable_msi(struct pci_dev *dev)
 
-A successful call will allocate ONE interrupt to the device, regardless
-of how many MSIs the device supports.  The device will be switched from
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device is switched from
 pin-based interrupt mode to MSI mode.  The dev->irq number is changed
-to a new number which represents the message signaled interrupt.
-This function should be called before the driver calls request_irq()
-since enabling MSIs disables the pin-based IRQ and the driver will not
-receive interrupts on the old interrupt.
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
 
 4.2.2 pci_enable_msi_block
 
@@ -111,20 +111,20 @@ the device are in the range dev->irq to dev->irq + count - 1.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to request any more MSI interrupts for
-this device.  If this function returns a positive number, it will be
-less than 'count' and indicate the number of interrupts that could have
-been allocated.  In neither case will the irq value have been
-updated, nor will the device have been switched into MSI mode.
+this device.  If this function returns a positive number, it is
+less than 'count' and indicates the number of interrupts that could have
+been allocated.  In neither case is the irq value updated or the device
+switched into MSI mode.
 
 The device driver must decide what action to take if
-pci_enable_msi_block() returns a value less than the number asked for.
-Some devices can make use of fewer interrupts than the maximum they
-request; in this case the driver should call pci_enable_msi_block()
+pci_enable_msi_block() returns a value less than the number requested.
+For instance, the driver could still make use of fewer interrupts;
+in this case the driver should call pci_enable_msi_block()
 again.  Note that it is not guaranteed to succeed, even when the
 'count' has been reduced to the value returned from a previous call to
 pci_enable_msi_block().  This is because there are multiple constraints
 on the number of vectors that can be allocated; pci_enable_msi_block()
-will return as soon as it finds any constraint that doesn't allow the
+returns as soon as it finds any constraint that doesn't allow the
 call to succeed.
 
 4.2.3 pci_disable_msi
@@ -137,10 +137,10 @@ interrupt number and frees the previously allocated message signaled
 interrupt(s).  The interrupt may subsequently be assigned to another
 device, so drivers should not cache the value of dev->irq.
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI enabled and thus leaking its vector.
 
 4.3 Using MSI-X
 
@@ -155,10 +155,10 @@ struct msix_entry {
 };
 
 This allows for the device to use these interrupts in a sparse fashion;
-for example it could use interrupts 3 and 1027 and allocate only a
+for example, it could use interrupts 3 and 1027 and yet allocate only a
 two-element array.  The driver is expected to fill in the 'entry' value
-in each element of the array to indicate which entries it wants the kernel
-to assign interrupts for.  It is invalid to fill in two entries with the
+in each element of the array to indicate for which entries the kernel
+should assign interrupts; it is invalid to fill in two entries with the
 same number.
 
 4.3.1 pci_enable_msix
@@ -168,10 +168,11 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
 The 'entries' argument is a pointer to an array of msix_entry structs
 which should be at least 'nvec' entries in size.  On success, the
-function will return 0 and the device will have been switched into
-MSI-X interrupt mode.  The 'vector' elements in each entry will have
-been filled in with the interrupt number.  The driver should then call
-request_irq() for each 'vector' that it decides to use.
+device is switched into MSI-X mode and the function returns 0.
+The 'vector' member in each entry is populated with the interrupt number;
+the driver should then call request_irq() for each 'vector' that it
+decides to use.  The device driver is responsible for keeping track of the
+interrupts assigned to the MSI-X vectors so it can free them again later.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to allocate any more MSI-X interrupts for
@@ -181,16 +182,14 @@ below.
 
 This function, in contrast with pci_enable_msi(), does not adjust
 dev->irq.  The device will not generate interrupts for this interrupt
-number once MSI-X is enabled.  The device driver is responsible for
-keeping track of the interrupts assigned to the MSI-X vectors so it can
-free them again later.
+number once MSI-X is enabled.
 
 Device drivers should normally call this function once per device
 during the initialization phase.
 
-It is ideal if drivers can cope with a variable number of MSI-X interrupts,
+It is ideal if drivers can cope with a variable number of MSI-X interrupts;
 there are many reasons why the platform may not be able to provide the
-exact number a driver asks for.
+exact number that a driver asks for.
 
 A request loop to achieve that might look like:
 
@@ -212,15 +211,15 @@ static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 
 void pci_disable_msix(struct pci_dev *dev)
 
-This API should be used to undo the effect of pci_enable_msix().  It frees
+This function should be used to undo the effect of pci_enable_msix().  It frees
 the previously allocated message signaled interrupts.  The interrupts may
 subsequently be assigned to another device, so drivers should not cache
 the value of the 'vector' elements over a call to pci_disable_msix().
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI-X enabled and thus leaking its vector.
 
 4.3.3 The MSI-X Table
 
@@ -232,10 +231,10 @@ mask or unmask an interrupt, it should call disable_irq() / enable_irq().
 4.4 Handling devices implementing both MSI and MSI-X capabilities
 
 If a device implements both MSI and MSI-X capabilities, it can
-run in either MSI mode or MSI-X mode but not both simultaneously.
+run in either MSI mode or MSI-X mode, but not both simultaneously.
 This is a requirement of the PCI spec, and it is enforced by the
 PCI layer.  Calling pci_enable_msi() when MSI-X is already enabled or
-pci_enable_msix() when MSI is already enabled will result in an error.
+pci_enable_msix() when MSI is already enabled results in an error.
 If a device driver wishes to switch between MSI and MSI-X at runtime,
 it must first quiesce the device, then switch it back to pin-interrupt
 mode, before calling pci_enable_msi() or pci_enable_msix() and resuming
@@ -251,7 +250,7 @@ the MSI-X facilities in preference to the MSI facilities.  As mentioned
 above, MSI-X supports any number of interrupts between 1 and 2048.
 In constrast, MSI is restricted to a maximum of 32 interrupts (and
 must be a power of two).  In addition, the MSI interrupt vectors must
-be allocated consecutively, so the system may not be able to allocate
+be allocated consecutively, so the system might not be able to allocate
 as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
 interrupts must all be targeted at the same set of CPUs whereas MSI-X
 interrupts can all be targeted at different CPUs.
@@ -281,7 +280,7 @@ disabled to enabled and back again.
 
 Using 'lspci -v' (as root) may show some devices with "MSI", "Message
 Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
-has an 'Enable' flag which will be followed with either "+" (enabled)
+has an 'Enable' flag which is followed with either "+" (enabled)
 or "-" (disabled).
 
 
@@ -298,7 +297,7 @@ The PCI stack provides three ways to disable MSIs:
 
 Some host chipsets simply don't support MSIs properly.  If we're
 lucky, the manufacturer knows this and has indicated it in the ACPI
-FADT table.  In this case, Linux will automatically disable MSIs.
+FADT table.  In this case, Linux automatically disables MSIs.
 Some boards don't include this information in the table and so we have
 to detect them ourselves.  The complete list of these is found near the
 quirk_disable_all_msi() function in drivers/pci/quirks.c.
@@ -317,7 +316,7 @@ Some bridges allow you to enable MSIs by changing some bits in their
 PCI configuration space (especially the Hypertransport chipsets such
 as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
 Linux mostly knows about them and automatically enables MSIs if it can.
-If you have a bridge which Linux doesn't yet know about, you can enable
+If you have a bridge unknown to Linux, you can enable
 MSIs in configuration space using whatever method you know works, then
 enable MSIs on that bridge by doing:
 
@@ -327,7 +326,7 @@ where $bridge is the PCI address of the bridge you've enabled (eg
 0000:00:0e.0).
 
 To disable MSIs, echo 0 instead of 1.  Changing this value should be
-done with caution as it can break interrupt handling for all devices
+done with caution as it could break interrupt handling for all devices
 below this bridge.
 
 Again, please notify linux-pci@vger.kernel.org of any bridges that need
@@ -336,7 +335,7 @@ special handling.
 5.3. Disabling MSIs on a single device
 
 Some devices are known to have faulty MSI implementations.  Usually this
-is handled in the individual device driver but occasionally it's necessary
+is handled in the individual device driver, but occasionally it's necessary
 to handle this with a quirk.  Some drivers have an option to disable use
 of MSI.  While this is a convenient workaround for the driver author,
 it is not good practise, and should not be emulated.
@@ -350,7 +349,7 @@ for your machine.  You should also check your .config to be sure you
 have enabled CONFIG_PCI_MSI.
 
 Then, 'lspci -t' gives the list of bridges above a device.  Reading
-/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1)
+/sys/bus/pci/devices/*/msi_bus will tell you whether MSIs are enabled (1)
 or disabled (0).  If 0 is found in any of the msi_bus files belonging
 to bridges between the PCI root and the device, MSIs are disabled.
 
index e578feed6d818f13b148f16cba3dbca8505362fc..6d670f570451a14c1ce4f8c2eb1c69d52736ee01 100644 (file)
@@ -43,3 +43,74 @@ If one sets slice_idle=0 and if storage supports NCQ, CFQ internally switches
 to IOPS mode and starts providing fairness in terms of number of requests
 dispatched. Note that this mode switching takes effect only for group
 scheduling. For non-cgroup users nothing should change.
+
+CFQ IO scheduler Idling Theory
+===============================
+Idling on a queue is primarily about waiting for the next request to come
+on same queue after completion of a request. In this process CFQ will not
+dispatch requests from other cfq queues even if requests are pending there.
+
+The rationale behind idling is that it can cut down on number of seeks
+on rotational media. For example, if a process is doing dependent
+sequential reads (next read will come on only after completion of previous
+one), then not dispatching request from other queue should help as we
+did not move the disk head and kept on dispatching sequential IO from
+one queue.
+
+CFQ has following service trees and various queues are put on these trees.
+
+       sync-idle       sync-noidle     async
+
+All cfq queues doing synchronous sequential IO go on to sync-idle tree.
+On this tree we idle on each queue individually.
+
+All synchronous non-sequential queues go on sync-noidle tree. Also any
+request which are marked with REQ_NOIDLE go on this service tree. On this
+tree we do not idle on individual queues instead idle on the whole group
+of queues or the tree. So if there are 4 queues waiting for IO to dispatch
+we will idle only once last queue has dispatched the IO and there is
+no more IO on this service tree.
+
+All async writes go on async service tree. There is no idling on async
+queues.
+
+CFQ has some optimizations for SSDs and if it detects a non-rotational
+media which can support higher queue depth (multiple requests at in
+flight at a time), then it cuts down on idling of individual queues and
+all the queues move to sync-noidle tree and only tree idle remains. This
+tree idling provides isolation with buffered write queues on async tree.
+
+FAQ
+===
+Q1. Why to idle at all on queues marked with REQ_NOIDLE.
+
+A1. We only do tree idle (all queues on sync-noidle tree) on queues marked
+    with REQ_NOIDLE. This helps in providing isolation with all the sync-idle
+    queues. Otherwise in presence of many sequential readers, other
+    synchronous IO might not get fair share of disk.
+
+    For example, if there are 10 sequential readers doing IO and they get
+    100ms each. If a REQ_NOIDLE request comes in, it will be scheduled
+    roughly after 1 second. If after completion of REQ_NOIDLE request we
+    do not idle, and after a couple of milli seconds a another REQ_NOIDLE
+    request comes in, again it will be scheduled after 1second. Repeat it
+    and notice how a workload can lose its disk share and suffer due to
+    multiple sequential readers.
+
+    fsync can generate dependent IO where bunch of data is written in the
+    context of fsync, and later some journaling data is written. Journaling
+    data comes in only after fsync has finished its IO (atleast for ext4
+    that seemed to be the case). Now if one decides not to idle on fsync
+    thread due to REQ_NOIDLE, then next journaling write will not get
+    scheduled for another second. A process doing small fsync, will suffer
+    badly in presence of multiple sequential readers.
+
+    Hence doing tree idling on threads using REQ_NOIDLE flag on requests
+    provides isolation from multiple sequential readers and at the same
+    time we do not idle on individual threads.
+
+Q2. When to specify REQ_NOIDLE
+A2. I would think whenever one is doing synchronous write and not expecting
+    more writes to be dispatched from same context soon, should be able
+    to specify REQ_NOIDLE on writes and that probably should work well for
+    most of the cases.
index 6ca1f5cb71e0b1290a429c5d33fcf2f578ad3cc9..614d0382e2cbe5b4fd37ce5ce67db76ddd89a6c4 100644 (file)
@@ -1350,9 +1350,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        it is equivalent to "nosmp", which also disables
                        the IO APIC.
 
-       max_loop=       [LOOP] Maximum number of loopback devices that can
-                       be mounted
-                       Format: <1-256>
+       max_loop=       [LOOP] The number of loop block devices that get
+       (loop.max_loop) unconditionally pre-created at init time. The default
+                       number is configured by BLK_DEV_LOOP_MIN_COUNT. Instead
+                       of statically allocating a predefined number, loop
+                       devices can be requested on-demand with the
+                       /dev/loop-control interface.
 
        mcatest=        [IA-64]
 
index fe0251c4cfb7dcd589163d1283e516153d066cbe..8e601991d91c6b4e0247cd9b7a5735f3df7661b3 100644 (file)
@@ -8,3 +8,6 @@ lguest/
        - Extremely simple hypervisor for experimental/educational use.
 uml/
        - User Mode Linux, builds/runs Linux kernel as a userspace program.
+virtio.txt
+       - Text version of draft virtio spec.
+          See http://ozlabs.org/~rusty/virtio-spec
index 043bd7df31399a6a02c770393eb6d7f083e331e3..d928c134dee66953f0b7f163a8e3633ac95e3747 100644 (file)
@@ -1996,6 +1996,9 @@ int main(int argc, char *argv[])
        /* We use a simple helper to copy the arguments separated by spaces. */
        concat((char *)(boot + 1), argv+optind+2);
 
+       /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
+       boot->hdr.kernel_alignment = 0x1000000;
+
        /* Boot protocol version: 2.07 supports the fields for lguest. */
        boot->hdr.version = 0x207;
 
diff --git a/Documentation/virtual/virtio-spec.txt b/Documentation/virtual/virtio-spec.txt
new file mode 100644 (file)
index 0000000..a350ae1
--- /dev/null
@@ -0,0 +1,2200 @@
+[Generated file: see http://ozlabs.org/~rusty/virtio-spec/]
+Virtio PCI Card Specification
+v0.9.1 DRAFT
+-
+
+Rusty Russell <rusty@rustcorp.com.au>IBM Corporation (Editor)
+
+2011 August 1.
+
+Purpose and Description
+
+This document describes the specifications of the “virtio” family
+of PCI[LaTeX Command: nomenclature] devices. These are devices
+are found in virtual environments[LaTeX Command: nomenclature],
+yet by design they are not all that different from physical PCI
+devices, and this document treats them as such. This allows the
+guest to use standard PCI drivers and discovery mechanisms.
+
+The purpose of virtio and this specification is that virtual
+environments and guests should have a straightforward, efficient,
+standard and extensible mechanism for virtual devices, rather
+than boutique per-environment or per-OS mechanisms.
+
+  Straightforward: Virtio PCI devices use normal PCI mechanisms
+  of interrupts and DMA which should be familiar to any device
+  driver author. There is no exotic page-flipping or COW
+  mechanism: it's just a PCI device.[footnote:
+This lack of page-sharing implies that the implementation of the
+device (e.g. the hypervisor or host) needs full access to the
+guest memory. Communication with untrusted parties (i.e.
+inter-guest communication) requires copying.
+]
+
+  Efficient: Virtio PCI devices consist of rings of descriptors
+  for input and output, which are neatly separated to avoid cache
+  effects from both guest and device writing to the same cache
+  lines.
+
+  Standard: Virtio PCI makes no assumptions about the environment
+  in which it operates, beyond supporting PCI. In fact the virtio
+  devices specified in the appendices do not require PCI at all:
+  they have been implemented on non-PCI buses.[footnote:
+The Linux implementation further separates the PCI virtio code
+from the specific virtio drivers: these drivers are shared with
+the non-PCI implementations (currently lguest and S/390).
+]
+
+  Extensible: Virtio PCI devices contain feature bits which are
+  acknowledged by the guest operating system during device setup.
+  This allows forwards and backwards compatibility: the device
+  offers all the features it knows about, and the driver
+  acknowledges those it understands and wishes to use.
+
+  Virtqueues
+
+The mechanism for bulk data transport on virtio PCI devices is
+pretentiously called a virtqueue. Each device can have zero or
+more virtqueues: for example, the network device has one for
+transmit and one for receive.
+
+Each virtqueue occupies two or more physically-contiguous pages
+(defined, for the purposes of this specification, as 4096 bytes),
+and consists of three parts:
+
+
++-------------------+-----------------------------------+-----------+
+| Descriptor Table  |   Available Ring     (padding)    | Used Ring |
++-------------------+-----------------------------------+-----------+
+
+
+When the driver wants to send buffers to the device, it puts them
+in one or more slots in the descriptor table, and writes the
+descriptor indices into the available ring. It then notifies the
+device. When the device has finished with the buffers, it writes
+the descriptors into the used ring, and sends an interrupt.
+
+Specification
+
+  PCI Discovery
+
+Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000
+through 0x103F inclusive is a virtio device[footnote:
+The actual value within this range is ignored
+]. The device must also have a Revision ID of 0 to match this
+specification.
+
+The Subsystem Device ID indicates which virtio device is
+supported by the device. The Subsystem Vendor ID should reflect
+the PCI Vendor ID of the environment (it's currently only used
+for informational purposes by the guest).
+
+
++----------------------+--------------------+---------------+
+| Subsystem Device ID  |   Virtio Device    | Specification |
++----------------------+--------------------+---------------+
++----------------------+--------------------+---------------+
+|          1           |   network card     |  Appendix C   |
++----------------------+--------------------+---------------+
+|          2           |   block device     |  Appendix D   |
++----------------------+--------------------+---------------+
+|          3           |      console       |  Appendix E   |
++----------------------+--------------------+---------------+
+|          4           |  entropy source    |  Appendix F   |
++----------------------+--------------------+---------------+
+|          5           | memory ballooning  |  Appendix G   |
++----------------------+--------------------+---------------+
+|          6           |     ioMemory       |       -       |
++----------------------+--------------------+---------------+
+|          9           |   9P transport     |       -       |
++----------------------+--------------------+---------------+
+
+
+  Device Configuration
+
+To configure the device, we use the first I/O region of the PCI
+device. This contains a virtio header followed by a
+device-specific region.
+
+There may be different widths of accesses to the I/O region; the “
+natural” access method for each field in the virtio header must
+be used (i.e. 32-bit accesses for 32-bit fields, etc), but the
+device-specific region can be accessed using any width accesses,
+and should obtain the same results.
+
+Note that this is possible because while the virtio header is PCI
+(i.e. little) endian, the device-specific region is encoded in
+the native endian of the guest (where such distinction is
+applicable).
+
+  Device Initialization Sequence
+
+We start with an overview of device initialization, then expand
+on the details of the device and how each step is preformed.
+
+  Reset the device. This is not required on initial start up.
+
+  The ACKNOWLEDGE status bit is set: we have noticed the device.
+
+  The DRIVER status bit is set: we know how to drive the device.
+
+  Device-specific setup, including reading the Device Feature
+  Bits, discovery of virtqueues for the device, optional MSI-X
+  setup, and reading and possibly writing the virtio
+  configuration space.
+
+  The subset of Device Feature Bits understood by the driver is
+  written to the device.
+
+  The DRIVER_OK status bit is set.
+
+  The device can now be used (ie. buffers added to the
+  virtqueues)[footnote:
+Historically, drivers have used the device before steps 5 and 6.
+This is only allowed if the driver does not use any features
+which would alter this early use of the device.
+]
+
+If any of these steps go irrecoverably wrong, the guest should
+set the FAILED status bit to indicate that it has given up on the
+device (it can reset the device later to restart if desired).
+
+We now cover the fields required for general setup in detail.
+
+  Virtio Header
+
+The virtio header looks as follows:
+
+
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Bits       || 32                  | 32                  | 32       | 16     | 16      | 16      | 8       | 8      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Read/Write || R                   | R+W                 | R+W      | R      | R+W     | R+W     | R+W     | R      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Purpose    || Device              | Guest               | Queue    | Queue  | Queue   | Queue   | Device  | ISR    |
+|            || Features bits 0:31  | Features bits 0:31  | Address  | Size   | Select  | Notify  | Status  | Status |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+
+
+If MSI-X is enabled for the device, two additional fields
+immediately follow this header:
+
+
++------------++----------------+--------+
+| Bits       || 16             | 16     |
+              +----------------+--------+
++------------++----------------+--------+
+| Read/Write || R+W            | R+W    |
++------------++----------------+--------+
+| Purpose    || Configuration  | Queue  |
+| (MSI-X)    || Vector         | Vector |
++------------++----------------+--------+
+
+
+Finally, if feature bits (VIRTIO_F_FEATURES_HI) this is
+immediately followed by two additional fields:
+
+
++------------++----------------------+----------------------
+| Bits       || 32                   | 32
++------------++----------------------+----------------------
+| Read/Write || R                    | R+W
++------------++----------------------+----------------------
+| Purpose    || Device               | Guest
+|            || Features bits 32:63  | Features bits 32:63
++------------++----------------------+----------------------
+
+
+Immediately following these general headers, there may be
+device-specific headers:
+
+
++------------++--------------------+
+| Bits       || Device Specific    |
+              +--------------------+
++------------++--------------------+
+| Read/Write || Device Specific    |
++------------++--------------------+
+| Purpose    || Device Specific... |
+|            ||                    |
++------------++--------------------+
+
+
+  Device Status
+
+The Device Status field is updated by the guest to indicate its
+progress. This provides a simple low-level diagnostic: it's most
+useful to imagine them hooked up to traffic lights on the console
+indicating the status of each device.
+
+The device can be reset by writing a 0 to this field, otherwise
+at least one bit should be set:
+
+  ACKNOWLEDGE (1) Indicates that the guest OS has found the
+  device and recognized it as a valid virtio device.
+
+  DRIVER (2) Indicates that the guest OS knows how to drive the
+  device. Under Linux, drivers can be loadable modules so there
+  may be a significant (or infinite) delay before setting this
+  bit.
+
+  DRIVER_OK (3) Indicates that the driver is set up and ready to
+  drive the device.
+
+  FAILED (8) Indicates that something went wrong in the guest,
+  and it has given up on the device. This could be an internal
+  error, or the driver didn't like the device for some reason, or
+  even a fatal error during device operation. The device must be
+  reset before attempting to re-initialize.
+
+  Feature Bits
+
+The least significant 31 bits of the first configuration field
+indicates the features that the device supports (the high bit is
+reserved, and will be used to indicate the presence of future
+feature bits elsewhere). If more than 31 feature bits are
+supported, the device indicates so by setting feature bit 31 (see
+[cha:Reserved-Feature-Bits]). The bits are allocated as follows:
+
+  0 to 23 Feature bits for the specific device type
+
+  24 to 40 Feature bits reserved for extensions to the queue and
+  feature negotiation mechanisms
+
+  41 to 63 Feature bits reserved for future extensions
+
+For example, feature bit 0 for a network device (i.e. Subsystem
+Device ID 1) indicates that the device supports checksumming of
+packets.
+
+The feature bits are negotiated: the device lists all the
+features it understands in the Device Features field, and the
+guest writes the subset that it understands into the Guest
+Features field. The only way to renegotiate is to reset the
+device.
+
+In particular, new fields in the device configuration header are
+indicated by offering a feature bit, so the guest can check
+before accessing that part of the configuration space.
+
+This allows for forwards and backwards compatibility: if the
+device is enhanced with a new feature bit, older guests will not
+write that feature bit back to the Guest Features field and it
+can go into backwards compatibility mode. Similarly, if a guest
+is enhanced with a feature that the device doesn't support, it
+will not see that feature bit in the Device Features field and
+can go into backwards compatibility mode (or, for poor
+implementations, set the FAILED Device Status bit).
+
+Access to feature bits 32 to 63 is enabled by Guest by setting
+feature bit 31. If this bit is unset, Device must assume that all
+feature bits > 31 are unset.
+
+  Configuration/Queue Vectors
+
+When MSI-X capability is present and enabled in the device
+(through standard PCI configuration space) 4 bytes at byte offset
+20 are used to map configuration change and queue interrupts to
+MSI-X vectors. In this case, the ISR Status field is unused, and
+device specific configuration starts at byte offset 24 in virtio
+header structure. When MSI-X capability is not enabled, device
+specific configuration starts at byte offset 20 in virtio header.
+
+Writing a valid MSI-X Table entry number, 0 to 0x7FF, to one of
+Configuration/Queue Vector registers, maps interrupts triggered
+by the configuration change/selected queue events respectively to
+the corresponding MSI-X vector. To disable interrupts for a
+specific event type, unmap it by writing a special NO_VECTOR
+value:
+
+/* Vector value used to disable MSI for queue */
+
+#define VIRTIO_MSI_NO_VECTOR            0xffff
+
+Reading these registers returns vector mapped to a given event,
+or NO_VECTOR if unmapped. All queue and configuration change
+events are unmapped by default.
+
+Note that mapping an event to vector might require allocating
+internal device resources, and might fail. Devices report such
+failures by returning the NO_VECTOR value when the relevant
+Vector field is read. After mapping an event to vector, the
+driver must verify success by reading the Vector field value: on
+success, the previously written value is returned, and on
+failure, NO_VECTOR is returned. If a mapping failure is detected,
+the driver can retry mapping with fewervectors, or disable MSI-X.
+
+  Virtqueue Configuration
+
+As a device can have zero or more virtqueues for bulk data
+transport (for example, the network driver has two), the driver
+needs to configure them as part of the device-specific
+configuration.
+
+This is done as follows, for each virtqueue a device has:
+
+  Write the virtqueue index (first queue is 0) to the Queue
+  Select field.
+
+  Read the virtqueue size from the Queue Size field, which is
+  always a power of 2. This controls how big the virtqueue is
+  (see below). If this field is 0, the virtqueue does not exist.
+
+  Allocate and zero virtqueue in contiguous physical memory, on a
+  4096 byte alignment. Write the physical address, divided by
+  4096 to the Queue Address field.[footnote:
+The 4096 is based on the x86 page size, but it's also large
+enough to ensure that the separate parts of the virtqueue are on
+separate cache lines.
+]
+
+  Optionally, if MSI-X capability is present and enabled on the
+  device, select a vector to use to request interrupts triggered
+  by virtqueue events. Write the MSI-X Table entry number
+  corresponding to this vector in Queue Vector field. Read the
+  Queue Vector field: on success, previously written value is
+  returned; on failure, NO_VECTOR value is returned.
+
+The Queue Size field controls the total number of bytes required
+for the virtqueue according to the following formula:
+
+#define ALIGN(x) (((x) + 4095) & ~4095)
+
+static inline unsigned vring_size(unsigned int qsz)
+
+{
+
+     return ALIGN(sizeof(struct vring_desc)*qsz + sizeof(u16)*(2
++ qsz))
+
+          + ALIGN(sizeof(struct vring_used_elem)*qsz);
+
+}
+
+This currently wastes some space with padding, but also allows
+future extensions. The virtqueue layout structure looks like this
+(qsz is the Queue Size field, which is a variable, so this code
+won't compile):
+
+struct vring {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[qsz];
+
+
+
+    /* A ring of available descriptor heads with free-running
+index. */
+
+    struct vring_avail avail;
+
+
+
+    // Padding to the next 4096 boundary.
+
+    char pad[];
+
+
+
+    // A ring of used descriptor heads with free-running index.
+
+    struct vring_used used;
+
+};
+
+  A Note on Virtqueue Endianness
+
+Note that the endian of these fields and everything else in the
+virtqueue is the native endian of the guest, not little-endian as
+PCI normally is. This makes for simpler guest code, and it is
+assumed that the host already has to be deeply aware of the guest
+endian so such an “endian-aware” device is not a significant
+issue.
+
+  Descriptor Table
+
+The descriptor table refers to the buffers the guest is using for
+the device. The addresses are physical addresses, and the buffers
+can be chained via the next field. Each descriptor describes a
+buffer which is read-only or write-only, but a chain of
+descriptors can contain both read-only and write-only buffers.
+
+No descriptor chain may be more than 2^32 bytes long in total.struct vring_desc {
+
+    /* Address (guest-physical). */
+
+    u64 addr;
+
+    /* Length. */
+
+    u32 len;
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT   1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE     2
+
+/* This means the buffer contains a list of buffer descriptors.
+*/
+
+#define VRING_DESC_F_INDIRECT   4
+
+    /* The flags as indicated above. */
+
+    u16 flags;
+
+    /* Next field if flags & NEXT */
+
+    u16 next;
+
+};
+
+The number of descriptors in the table is specified by the Queue
+Size field for this virtqueue.
+
+  <sub:Indirect-Descriptors>Indirect Descriptors
+
+Some devices benefit by concurrently dispatching a large number
+of large requests. The VIRTIO_RING_F_INDIRECT_DESC feature can be
+used to allow this (see [cha:Reserved-Feature-Bits]). To increase
+ring capacity it is possible to store a table of indirect
+descriptors anywhere in memory, and insert a descriptor in main
+virtqueue (with flags&INDIRECT on) that refers to memory buffer
+containing this indirect descriptor table; fields addr and len
+refer to the indirect table address and length in bytes,
+respectively. The indirect table layout structure looks like this
+(len is the length of the descriptor that refers to this table,
+which is a variable, so this code won't compile):
+
+struct indirect_descriptor_table {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[len / 16];
+
+};
+
+The first indirect descriptor is located at start of the indirect
+descriptor table (index 0), additional indirect descriptors are
+chained by next field. An indirect descriptor without next field
+(with flags&NEXT off) signals the end of the indirect descriptor
+table, and transfers control back to the main virtqueue. An
+indirect descriptor can not refer to another indirect descriptor
+table (flags&INDIRECT must be off). A single indirect descriptor
+table can include both read-only and write-only descriptors;
+write-only flag (flags&WRITE) in the descriptor that refers to it
+is ignored.
+
+  Available Ring
+
+The available ring refers to what descriptors we are offering the
+device: it refers to the head of a descriptor chain. The “flags”
+field is currently 0 or 1: 1 indicating that we do not need an
+interrupt when the device consumes a descriptor from the
+available ring. Alternatively, the guest can ask the device to
+delay interrupts until an entry with an index specified by the “
+used_event” field is written in the used ring (equivalently,
+until the idx field in the used ring will reach the value
+used_event + 1). The method employed by the device is controlled
+by the VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). This interrupt suppression is merely an optimization; it may
+not suppress interrupts entirely.
+
+The “idx” field indicates where we would put the next descriptor
+entry (modulo the ring size). This starts at 0, and increases.
+
+struct vring_avail {
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+   u16 flags;
+
+   u16 idx;
+
+   u16 ring[qsz]; /* qsz is the Queue Size field read from device
+*/
+
+   u16 used_event;
+
+};
+
+  Used Ring
+
+The used ring is where the device returns buffers once it is done
+with them. The flags field can be used by the device to hint that
+no notification is necessary when the guest adds to the available
+ring. Alternatively, the “avail_event” field can be used by the
+device to hint that no notification is necessary until an entry
+with an index specified by the “avail_event” is written in the
+available ring (equivalently, until the idx field in the
+available ring will reach the value avail_event + 1). The method
+employed by the device is controlled by the guest through the
+VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). [footnote:
+These fields are kept here because this is the only part of the
+virtqueue written by the device
+].
+
+Each entry in the ring is a pair: the head entry of the
+descriptor chain describing the buffer (this matches an entry
+placed in the available ring by the guest earlier), and the total
+of bytes written into the buffer. The latter is extremely useful
+for guests using untrusted buffers: if you do not know exactly
+how much has been written by the device, you usually have to zero
+the buffer to ensure no data leakage occurs.
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+    /* Index of start of used descriptor chain. */
+
+    u32 id;
+
+    /* Total length of the descriptor chain which was used
+(written to) */
+
+    u32 len;
+
+};
+
+
+
+struct vring_used {
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+    u16 flags;
+
+    u16 idx;
+
+    struct vring_used_elem ring[qsz];
+
+    u16 avail_event;
+
+};
+
+  Helpers for Managing Virtqueues
+
+The Linux Kernel Source code contains the definitions above and
+helper routines in a more usable form, in
+include/linux/virtio_ring.h. This was explicitly licensed by IBM
+and Red Hat under the (3-clause) BSD license so that it can be
+freely used by all other projects, and is reproduced (with slight
+variation to remove Linux assumptions) in Appendix A.
+
+  Device Operation
+
+There are two parts to device operation: supplying new buffers to
+the device, and processing used buffers from the device. As an
+example, the virtio network device has two virtqueues: the
+transmit virtqueue and the receive virtqueue. The driver adds
+outgoing (read-only) packets to the transmit virtqueue, and then
+frees them after they are used. Similarly, incoming (write-only)
+buffers are added to the receive virtqueue, and processed after
+they are used.
+
+  Supplying Buffers to The Device
+
+Actual transfer of buffers from the guest OS to the device
+operates as follows:
+
+  Place the buffer(s) into free descriptor(s).
+
+  If there are no free descriptors, the guest may choose to
+    notify the device even if notifications are suppressed (to
+    reduce latency).[footnote:
+The Linux drivers do this only for read-only buffers: for
+write-only buffers, it is assumed that the driver is merely
+trying to keep the receive buffer ring full, and no notification
+of this expected condition is necessary.
+]
+
+  Place the id of the buffer in the next ring entry of the
+  available ring.
+
+  The steps (1) and (2) may be performed repeatedly if batching
+  is possible.
+
+  A memory barrier should be executed to ensure the device sees
+  the updated descriptor table and available ring before the next
+  step.
+
+  The available “idx” field should be increased by the number of
+  entries added to the available ring.
+
+  A memory barrier should be executed to ensure that we update
+  the idx field before checking for notification suppression.
+
+  If notifications are not suppressed, the device should be
+  notified of the new buffers.
+
+Note that the above code does not take precautions against the
+available ring buffer wrapping around: this is not possible since
+the ring buffer is the same size as the descriptor table, so step
+(1) will prevent such a condition.
+
+In addition, the maximum queue size is 32768 (it must be a power
+of 2 which fits in 16 bits), so the 16-bit “idx” value can always
+distinguish between a full and empty buffer.
+
+Here is a description of each stage in more detail.
+
+  Placing Buffers Into The Descriptor Table
+
+A buffer consists of zero or more read-only physically-contiguous
+elements followed by zero or more physically-contiguous
+write-only elements (it must have at least one element). This
+algorithm maps it into the descriptor table:
+
+  for each buffer element, b:
+
+  Get the next free descriptor table entry, d
+
+  Set d.addr to the physical address of the start of b
+
+  Set d.len to the length of b.
+
+  If b is write-only, set d.flags to VRING_DESC_F_WRITE,
+    otherwise 0.
+
+  If there is a buffer element after this:
+
+    Set d.next to the index of the next free descriptor element.
+
+    Set the VRING_DESC_F_NEXT bit in d.flags.
+
+In practice, the d.next fields are usually used to chain free
+descriptors, and a separate count kept to check there are enough
+free descriptors before beginning the mappings.
+
+  Updating The Available Ring
+
+The head of the buffer we mapped is the first d in the algorithm
+above. A naive implementation would do the following:
+
+avail->ring[avail->idx % qsz] = head;
+
+However, in general we can add many descriptors before we update
+the “idx” field (at which point they become visible to the
+device), so we keep a counter of how many we've added:
+
+avail->ring[(avail->idx + added++) % qsz] = head;
+
+  Updating The Index Field
+
+Once the idx field of the virtqueue is updated, the device will
+be able to access the descriptor entries we've created and the
+memory they refer to. This is why a memory barrier is generally
+used before the idx update, to ensure it sees the most up-to-date
+copy.
+
+The idx field always increments, and we let it wrap naturally at
+65536:
+
+avail->idx += added;
+
+  <sub:Notifying-The-Device>Notifying The Device
+
+Device notification occurs by writing the 16-bit virtqueue index
+of this virtqueue to the Queue Notify field of the virtio header
+in the first I/O region of the PCI device. This can be expensive,
+however, so the device can suppress such notifications if it
+doesn't need them. We have to be careful to expose the new idx
+value before checking the suppression flag: it's OK to notify
+gratuitously, but not to omit a required notification. So again,
+we use a memory barrier here before reading the flags or the
+avail_event field.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated, and if
+the VRING_USED_F_NOTIFY flag is not set, we go ahead and write to
+the PCI configuration space.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is negotiated, we read the
+avail_event field in the available ring structure. If the
+available index crossed_the avail_event field value since the
+last notification, we go ahead and write to the PCI configuration
+space. The avail_event field wraps naturally at 65536 as well:
+
+(u16)(new_idx - avail_event - 1) < (u16)(new_idx - old_idx)
+
+  <sub:Receiving-Used-Buffers>Receiving Used Buffers From The
+  Device
+
+Once the device has used a buffer (read from or written to it, or
+parts of both, depending on the nature of the virtqueue and the
+device), it sends an interrupt, following an algorithm very
+similar to the algorithm used for the driver to send the device a
+buffer:
+
+  Write the head descriptor number to the next field in the used
+  ring.
+
+  Update the used ring idx.
+
+  Determine whether an interrupt is necessary:
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated: check
+    if f the VRING_AVAIL_F_NO_INTERRUPT flag is not set in avail-
+    >flags
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is negotiated: check
+    whether the used index crossed the used_event field value
+    since the last update. The used_event field wraps naturally
+    at 65536 as well:(u16)(new_idx - used_event - 1) < (u16)(new_idx - old_idx)
+
+  If an interrupt is necessary:
+
+  If MSI-X capability is disabled:
+
+    Set the lower bit of the ISR Status field for the device.
+
+    Send the appropriate PCI interrupt for the device.
+
+  If MSI-X capability is enabled:
+
+    Request the appropriate MSI-X interrupt message for the
+      device, Queue Vector field sets the MSI-X Table entry
+      number.
+
+    If Queue Vector field value is NO_VECTOR, no interrupt
+      message is requested for this event.
+
+The guest interrupt handler should:
+
+  If MSI-X capability is disabled: read the ISR Status field,
+  which will reset it to zero. If the lower bit is zero, the
+  interrupt was not for this device. Otherwise, the guest driver
+  should look through the used rings of each virtqueue for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+  If MSI-X capability is enabled: look through the used rings of
+  each virtqueue mapped to the specific MSI-X vector for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+For each ring, guest should then disable interrupts by writing
+VRING_AVAIL_F_NO_INTERRUPT flag in avail structure, if required.
+It can then process used ring entries finally enabling interrupts
+by clearing the VRING_AVAIL_F_NO_INTERRUPT flag or updating the
+EVENT_IDX field in the available structure, Guest should then
+execute a memory barrier, and then recheck the ring empty
+condition. This is necessary to handle the case where, after the
+last check and before enabling interrupts, an interrupt has been
+suppressed by the device:
+
+vring_disable_interrupts(vq);
+
+for (;;) {
+
+    if (vq->last_seen_used != vring->used.idx) {
+
+               vring_enable_interrupts(vq);
+
+               mb();
+
+               if (vq->last_seen_used != vring->used.idx)
+
+                       break;
+
+    }
+
+    struct vring_used_elem *e =
+vring.used->ring[vq->last_seen_used%vsz];
+
+    process_buffer(e);
+
+    vq->last_seen_used++;
+
+}
+
+  Dealing With Configuration Changes
+
+Some virtio PCI devices can change the device configuration
+state, as reflected in the virtio header in the PCI configuration
+space. In this case:
+
+  If MSI-X capability is disabled: an interrupt is delivered and
+  the second highest bit is set in the ISR Status field to
+  indicate that the driver should re-examine the configuration
+  space.Note that a single interrupt can indicate both that one
+  or more virtqueue has been used and that the configuration
+  space has changed: even if the config bit is set, virtqueues
+  must be scanned.
+
+  If MSI-X capability is enabled: an interrupt message is
+  requested. The Configuration Vector field sets the MSI-X Table
+  entry number to use. If Configuration Vector field value is
+  NO_VECTOR, no interrupt message is requested for this event.
+
+Creating New Device Types
+
+Various considerations are necessary when creating a new device
+type:
+
+  How Many Virtqueues?
+
+It is possible that a very simple device will operate entirely
+through its configuration space, but most will need at least one
+virtqueue in which it will place requests. A device with both
+input and output (eg. console and network devices described here)
+need two queues: one which the driver fills with buffers to
+receive input, and one which the driver places buffers to
+transmit output.
+
+  What Configuration Space Layout?
+
+Configuration space is generally used for rarely-changing or
+initialization-time parameters. But it is a limited resource, so
+it might be better to use a virtqueue to update configuration
+information (the network device does this for filtering,
+otherwise the table in the config space could potentially be very
+large).
+
+Note that this space is generally the guest's native endian,
+rather than PCI's little-endian.
+
+  What Device Number?
+
+Currently device numbers are assigned quite freely: a simple
+request mail to the author of this document or the Linux
+virtualization mailing list[footnote:
+
+https://lists.linux-foundation.org/mailman/listinfo/virtualization
+] will be sufficient to secure a unique one.
+
+Meanwhile for experimental drivers, use 65535 and work backwards.
+
+  How many MSI-X vectors?
+
+Using the optional MSI-X capability devices can speed up
+interrupt processing by removing the need to read ISR Status
+register by guest driver (which might be an expensive operation),
+reducing interrupt sharing between devices and queues within the
+device, and handling interrupts from multiple CPUs. However, some
+systems impose a limit (which might be as low as 256) on the
+total number of MSI-X vectors that can be allocated to all
+devices. Devices and/or device drivers should take this into
+account, limiting the number of vectors used unless the device is
+expected to cause a high volume of interrupts. Devices can
+control the number of vectors used by limiting the MSI-X Table
+Size or not presenting MSI-X capability in PCI configuration
+space. Drivers can control this by mapping events to as small
+number of vectors as possible, or disabling MSI-X capability
+altogether.
+
+  Message Framing
+
+The descriptors used for a buffer should not effect the semantics
+of the message, except for the total length of the buffer. For
+example, a network buffer consists of a 10 byte header followed
+by the network packet. Whether this is presented in the ring
+descriptor chain as (say) a 10 byte buffer and a 1514 byte
+buffer, or a single 1524 byte buffer, or even three buffers,
+should have no effect.
+
+In particular, no implementation should use the descriptor
+boundaries to determine the size of any header in a request.[footnote:
+The current qemu device implementations mistakenly insist that
+the first descriptor cover the header in these cases exactly, so
+a cautious driver should arrange it so.
+]
+
+  Device Improvements
+
+Any change to configuration space, or new virtqueues, or
+behavioural changes, should be indicated by negotiation of a new
+feature bit. This establishes clarity[footnote:
+Even if it does mean documenting design or implementation
+mistakes!
+] and avoids future expansion problems.
+
+Clusters of functionality which are always implemented together
+can use a single bit, but if one feature makes sense without the
+others they should not be gratuitously grouped together to
+conserve feature bits. We can always extend the spec when the
+first person needs more than 24 feature bits for their device.
+
+[LaTeX Command: printnomenclature]
+
+Appendix A: virtio_ring.h
+
+#ifndef VIRTIO_RING_H
+
+#define VIRTIO_RING_H
+
+/* An interface for efficient virtio implementation.
+
+ *
+
+ * This header is BSD licensed so anyone can use the definitions
+
+ * to implement compatible drivers/servers.
+
+ *
+
+ * Copyright 2007, 2009, IBM Corporation
+
+ * Copyright 2011, Red Hat, Inc
+
+ * All rights reserved.
+
+ *
+
+ * Redistribution and use in source and binary forms, with or
+without
+
+ * modification, are permitted provided that the following
+conditions
+
+ * are met:
+
+ * 1. Redistributions of source code must retain the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer.
+
+ * 2. Redistributions in binary form must reproduce the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer in the
+
+ *    documentation and/or other materials provided with the
+distribution.
+
+ * 3. Neither the name of IBM nor the names of its contributors
+
+ *    may be used to endorse or promote products derived from
+this software
+
+ *    without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS ``AS IS'' AND
+
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE
+
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE
+
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE
+LIABLE
+
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL
+
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS
+
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION)
+
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT
+
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY
+
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF
+
+ * SUCH DAMAGE.
+
+ */
+
+
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT       1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE      2
+
+
+
+/* The Host uses this in used->flags to advise the Guest: don't
+kick me
+
+ * when you add a buffer.  It's unreliable, so it's simply an
+
+ * optimization.  Guest will still kick if it's out of buffers.
+*/
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+/* The Guest uses this in avail->flags to advise the Host: don't
+
+ * interrupt me when you consume a buffer.  It's unreliable, so
+it's
+
+ * simply an optimization.  */
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+
+
+/* Virtio ring descriptors: 16 bytes.
+
+ * These can chain together via "next". */
+
+struct vring_desc {
+
+        /* Address (guest-physical). */
+
+        uint64_t addr;
+
+        /* Length. */
+
+        uint32_t len;
+
+        /* The flags as indicated above. */
+
+        uint16_t flags;
+
+        /* We chain unused descriptors via this, too */
+
+        uint16_t next;
+
+};
+
+
+
+struct vring_avail {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        uint16_t ring[];
+
+        uint16_t used_event;
+
+};
+
+
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+        /* Index of start of used descriptor chain. */
+
+        uint32_t id;
+
+        /* Total length of the descriptor chain which was written
+to. */
+
+        uint32_t len;
+
+};
+
+
+
+struct vring_used {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        struct vring_used_elem ring[];
+
+        uint16_t avail_event;
+
+};
+
+
+
+struct vring {
+
+        unsigned int num;
+
+
+
+        struct vring_desc *desc;
+
+        struct vring_avail *avail;
+
+        struct vring_used *used;
+
+};
+
+
+
+/* The standard layout for the ring is a continuous chunk of
+memory which
+
+ * looks like this.  We assume num is a power of 2.
+
+ *
+
+ * struct vring {
+
+ *      // The actual descriptors (16 bytes each)
+
+ *      struct vring_desc desc[num];
+
+ *
+
+ *      // A ring of available descriptor heads with free-running
+index.
+
+ *      __u16 avail_flags;
+
+ *      __u16 avail_idx;
+
+ *      __u16 available[num];
+
+ *
+
+ *      // Padding to the next align boundary.
+
+ *      char pad[];
+
+ *
+
+ *      // A ring of used descriptor heads with free-running
+index.
+
+ *      __u16 used_flags;
+
+ *      __u16 EVENT_IDX;
+
+ *      struct vring_used_elem used[num];
+
+ * };
+
+ * Note: for virtio PCI, align is 4096.
+
+ */
+
+static inline void vring_init(struct vring *vr, unsigned int num,
+void *p,
+
+                              unsigned long align)
+
+{
+
+        vr->num = num;
+
+        vr->desc = p;
+
+        vr->avail = p + num*sizeof(struct vring_desc);
+
+        vr->used = (void *)(((unsigned long)&vr->avail->ring[num]
+
+                              + align-1)
+
+                            & ~(align - 1));
+
+}
+
+
+
+static inline unsigned vring_size(unsigned int num, unsigned long
+align)
+
+{
+
+        return ((sizeof(struct vring_desc)*num +
+sizeof(uint16_t)*(2+num)
+
+                 + align - 1) & ~(align - 1))
+
+                + sizeof(uint16_t)*3 + sizeof(struct
+vring_used_elem)*num;
+
+}
+
+
+
+static inline int vring_need_event(uint16_t event_idx, uint16_t
+new_idx, uint16_t old_idx)
+
+{
+
+         return (uint16_t)(new_idx - event_idx - 1) <
+(uint16_t)(new_idx - old_idx);
+
+}
+
+#endif /* VIRTIO_RING_H */
+
+<cha:Reserved-Feature-Bits>Appendix B: Reserved Feature Bits
+
+Currently there are five device-independent feature bits defined:
+
+  VIRTIO_F_NOTIFY_ON_EMPTY (24) Negotiating this feature
+  indicates that the driver wants an interrupt if the device runs
+  out of available descriptors on a virtqueue, even though
+  interrupts are suppressed using the VRING_AVAIL_F_NO_INTERRUPT
+  flag or the used_event field. An example of this is the
+  networking driver: it doesn't need to know every time a packet
+  is transmitted, but it does need to free the transmitted
+  packets a finite time after they are transmitted. It can avoid
+  using a timer if the device interrupts it when all the packets
+  are transmitted.
+
+  VIRTIO_F_RING_INDIRECT_DESC (28) Negotiating this feature
+  indicates that the driver can use descriptors with the
+  VRING_DESC_F_INDIRECT flag set, as described in [sub:Indirect-Descriptors]
+  .
+
+  VIRTIO_F_RING_EVENT_IDX(29) This feature enables the used_event
+  and the avail_event fields. If set, it indicates that the
+  device should ignore the flags field in the available ring
+  structure. Instead, the used_event field in this structure is
+  used by guest to suppress device interrupts. Further, the
+  driver should ignore the flags field in the used ring
+  structure. Instead, the avail_event field in this structure is
+  used by the device to suppress notifications. If unset, the
+  driver should ignore the used_event field; the device should
+  ignore the avail_event field; the flags field is used
+
+  VIRTIO_F_BAD_FEATURE(30) This feature should never be
+  negotiated by the guest; doing so is an indication that the
+  guest is faulty[footnote:
+An experimental virtio PCI driver contained in Linux version
+2.6.25 had this problem, and this feature bit can be used to
+detect it.
+]
+
+  VIRTIO_F_FEATURES_HIGH(31) This feature indicates that the
+  device supports feature bits 32:63. If unset, feature bits
+  32:63 are unset.
+
+Appendix C: Network Device
+
+The virtio network device is a virtual ethernet card, and is the
+most complex of the devices supported so far by virtio. It has
+enhanced rapidly and demonstrates clearly how support for new
+features should be added to an existing device. Empty buffers are
+placed in one virtqueue for receiving packets, and outgoing
+packets are enqueued into another for transmission in that order.
+A third command queue is used to control advanced filtering
+features.
+
+  Configuration
+
+  Subsystem Device ID 1
+
+  Virtqueues 0:receiveq. 1:transmitq. 2:controlq[footnote:
+Only if VIRTIO_NET_F_CTRL_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_NET_F_CSUM (0) Device handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_GUEST_CSUM (1) Guest handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_MAC (5) Device has given MAC address.
+
+  VIRTIO_NET_F_GSO (6) (Deprecated) device handles packets with
+    any GSO type.[footnote:
+It was supposed to indicate segmentation offload support, but
+upon further investigation it became clear that multiple bits
+were required.
+]
+
+  VIRTIO_NET_F_GUEST_TSO4 (7) Guest can receive TSOv4.
+
+  VIRTIO_NET_F_GUEST_TSO6 (8) Guest can receive TSOv6.
+
+  VIRTIO_NET_F_GUEST_ECN (9) Guest can receive TSO with ECN.
+
+  VIRTIO_NET_F_GUEST_UFO (10) Guest can receive UFO.
+
+  VIRTIO_NET_F_HOST_TSO4 (11) Device can receive TSOv4.
+
+  VIRTIO_NET_F_HOST_TSO6 (12) Device can receive TSOv6.
+
+  VIRTIO_NET_F_HOST_ECN (13) Device can receive TSO with ECN.
+
+  VIRTIO_NET_F_HOST_UFO (14) Device can receive UFO.
+
+  VIRTIO_NET_F_MRG_RXBUF (15) Guest can merge receive buffers.
+
+  VIRTIO_NET_F_STATUS (16) Configuration status field is
+    available.
+
+  VIRTIO_NET_F_CTRL_VQ (17) Control channel is available.
+
+  VIRTIO_NET_F_CTRL_RX (18) Control channel RX mode support.
+
+  VIRTIO_NET_F_CTRL_VLAN (19) Control channel VLAN filtering.
+
+  Device configuration layout Two configuration fields are
+  currently defined. The mac address field always exists (though
+  is only valid if VIRTIO_NET_F_MAC is set), and the status field
+  only exists if VIRTIO_NET_F_STATUS is set. Only one bit is
+  currently defined for the status field: VIRTIO_NET_S_LINK_UP. #define VIRTIO_NET_S_LINK_UP   1
+
+
+
+struct virtio_net_config {
+
+    u8 mac[6];
+
+    u16 status;
+
+};
+
+  Device Initialization
+
+  The initialization routine should identify the receive and
+  transmission virtqueues.
+
+  If the VIRTIO_NET_F_MAC feature bit is set, the configuration
+  space “mac” entry indicates the “physical” address of the the
+  network card, otherwise a private MAC address should be
+  assigned. All guests are expected to negotiate this feature if
+  it is set.
+
+  If the VIRTIO_NET_F_CTRL_VQ feature bit is negotiated, identify
+  the control virtqueue.
+
+  If the VIRTIO_NET_F_STATUS feature bit is negotiated, the link
+  status can be read from the bottom bit of the “status” config
+  field. Otherwise, the link should be assumed active.
+
+  The receive virtqueue should be filled with receive buffers.
+  This is described in detail below in “Setting Up Receive
+  Buffers”.
+
+  A driver can indicate that it will generate checksumless
+  packets by negotating the VIRTIO_NET_F_CSUM feature. This “
+  checksum offload” is a common feature on modern network cards.
+
+  If that feature is negotiated, a driver can use TCP or UDP
+  segmentation offload by negotiating the VIRTIO_NET_F_HOST_TSO4
+  (IPv4 TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP) and
+  VIRTIO_NET_F_HOST_UFO (UDP fragmentation) features. It should
+  not send TCP packets requiring segmentation offload which have
+  the Explicit Congestion Notification bit set, unless the
+  VIRTIO_NET_F_HOST_ECN feature is negotiated.[footnote:
+This is a common restriction in real, older network cards.
+]
+
+  The converse features are also available: a driver can save the
+  virtual device some work by negotiating these features.[footnote:
+For example, a network packet transported between two guests on
+the same system may not require checksumming at all, nor
+segmentation, if both guests are amenable.
+] The VIRTIO_NET_F_GUEST_CSUM feature indicates that partially
+  checksummed packets can be received, and if it can do that then
+  the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
+  VIRTIO_NET_F_GUEST_UFO and VIRTIO_NET_F_GUEST_ECN are the input
+  equivalents of the features described above. See “Receiving
+  Packets” below.
+
+  Device Operation
+
+Packets are transmitted by placing them in the transmitq, and
+buffers for incoming packets are placed in the receiveq. In each
+case, the packet itself is preceeded by a header:
+
+struct virtio_net_hdr {
+
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1
+
+       u8 flags;
+
+#define VIRTIO_NET_HDR_GSO_NONE        0
+
+#define VIRTIO_NET_HDR_GSO_TCPV4       1
+
+#define VIRTIO_NET_HDR_GSO_UDP          3
+
+#define VIRTIO_NET_HDR_GSO_TCPV6       4
+
+#define VIRTIO_NET_HDR_GSO_ECN      0x80
+
+       u8 gso_type;
+
+       u16 hdr_len;
+
+       u16 gso_size;
+
+       u16 csum_start;
+
+       u16 csum_offset;
+
+/* Only if VIRTIO_NET_F_MRG_RXBUF: */
+
+       u16 num_buffers
+
+};
+
+The controlq is used to control device features such as
+filtering.
+
+  Packet Transmission
+
+Transmitting a single packet is simple, but varies depending on
+the different features the driver negotiated.
+
+  If the driver negotiated VIRTIO_NET_F_CSUM, and the packet has
+  not been fully checksummed, then the virtio_net_hdr's fields
+  are set as follows. Otherwise, the packet must be fully
+  checksummed, and flags is zero.
+
+  flags has the VIRTIO_NET_HDR_F_NEEDS_CSUM set,
+
+  <ite:csum_start-is-set>csum_start is set to the offset within
+    the packet to begin checksumming, and
+
+  csum_offset indicates how many bytes after the csum_start the
+    new (16 bit ones' complement) checksum should be placed.[footnote:
+For example, consider a partially checksummed TCP (IPv4) packet.
+It will have a 14 byte ethernet header and 20 byte IP header
+followed by the TCP header (with the TCP checksum field 16 bytes
+into that header). csum_start will be 14+20 = 34 (the TCP
+checksum includes the header), and csum_offset will be 16. The
+value in the TCP checksum field will be the sum of the TCP pseudo
+header, so that replacing it by the ones' complement checksum of
+the TCP header and body will give the correct result.
+]
+
+  <enu:If-the-driver>If the driver negotiated
+  VIRTIO_NET_F_HOST_TSO4, TSO6 or UFO, and the packet requires
+  TCP segmentation or UDP fragmentation, then the “gso_type”
+  field is set to VIRTIO_NET_HDR_GSO_TCPV4, TCPV6 or UDP.
+  (Otherwise, it is set to VIRTIO_NET_HDR_GSO_NONE). In this
+  case, packets larger than 1514 bytes can be transmitted: the
+  metadata indicates how to replicate the packet header to cut it
+  into smaller packets. The other gso fields are set:
+
+  hdr_len is a hint to the device as to how much of the header
+    needs to be kept to copy into each packet, usually set to the
+    length of the headers, including the transport header.[footnote:
+Due to various bugs in implementations, this field is not useful
+as a guarantee of the transport header size.
+]
+
+  gso_size is the size of the packet beyond that header (ie.
+    MSS).
+
+  If the driver negotiated the VIRTIO_NET_F_HOST_ECN feature, the
+    VIRTIO_NET_HDR_GSO_ECN bit may be set in “gso_type” as well,
+    indicating that the TCP packet has the ECN bit set.[footnote:
+This case is not handled by some older hardware, so is called out
+specifically in the protocol.
+]
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  the num_buffers field is set to zero.
+
+  The header and packet are added as one output buffer to the
+  transmitq, and the device is notified of the new entry (see [sub:Notifying-The-Device]
+  ).[footnote:
+Note that the header will be two bytes longer for the
+VIRTIO_NET_F_MRG_RXBUF case.
+]
+
+  Packet Transmission Interrupt
+
+Often a driver will suppress transmission interrupts using the
+VRING_AVAIL_F_NO_INTERRUPT flag (see [sub:Receiving-Used-Buffers]
+) and check for used packets in the transmit path of following
+packets. However, it will still receive interrupts if the
+VIRTIO_F_NOTIFY_ON_EMPTY feature is negotiated, indicating that
+the transmission queue is completely emptied.
+
+The normal behavior in this interrupt handler is to retrieve and
+new descriptors from the used ring and free the corresponding
+headers and packets.
+
+  Setting Up Receive Buffers
+
+It is generally a good idea to keep the receive virtqueue as
+fully populated as possible: if it runs out, network performance
+will suffer.
+
+If the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6 or
+VIRTIO_NET_F_GUEST_UFO features are used, the Guest will need to
+accept packets of up to 65550 bytes long (the maximum size of a
+TCP or UDP packet, plus the 14 byte ethernet header), otherwise
+1514 bytes. So unless VIRTIO_NET_F_MRG_RXBUF is negotiated, every
+buffer in the receive queue needs to be at least this length [footnote:
+Obviously each one can be split across multiple descriptor
+elements.
+].
+
+If VIRTIO_NET_F_MRG_RXBUF is negotiated, each buffer must be at
+least the size of the struct virtio_net_hdr.
+
+  Packet Receive Interrupt
+
+When a packet is copied into a buffer in the receiveq, the
+optimal path is to disable further interrupts for the receiveq
+(see [sub:Receiving-Used-Buffers]) and process packets until no
+more are found, then re-enable them.
+
+Processing packet involves:
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  then the “num_buffers” field indicates how many descriptors
+  this packet is spread over (including this one). This allows
+  receipt of large packets without having to allocate large
+  buffers. In this case, there will be at least “num_buffers” in
+  the used ring, and they should be chained together to form a
+  single packet. The other buffers will not begin with a struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_MRG_RXBUF feature was not negotiated, or
+  the “num_buffers” field is one, then the entire packet will be
+  contained within this buffer, immediately following the struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_GUEST_CSUM feature was negotiated, the
+  VIRTIO_NET_HDR_F_NEEDS_CSUM bit in the “flags” field may be
+  set: if so, the checksum on the packet is incomplete and the “
+  csum_start” and “csum_offset” fields indicate how to calculate
+  it (see [ite:csum_start-is-set]).
+
+  If the VIRTIO_NET_F_GUEST_TSO4, TSO6 or UFO options were
+  negotiated, then the “gso_type” may be something other than
+  VIRTIO_NET_HDR_GSO_NONE, and the “gso_size” field indicates the
+  desired MSS (see [enu:If-the-driver]).Control Virtqueue
+
+The driver uses the control virtqueue (if VIRTIO_NET_F_VTRL_VQ is
+negotiated) to send commands to manipulate various features of
+the device which would not easily map into the configuration
+space.
+
+All commands are of the following form:
+
+struct virtio_net_ctrl {
+
+       u8 class;
+
+       u8 command;
+
+       u8 command-specific-data[];
+
+       u8 ack;
+
+};
+
+
+
+/* ack values */
+
+#define VIRTIO_NET_OK     0
+
+#define VIRTIO_NET_ERR    1
+
+The class, command and command-specific-data are set by the
+driver, and the device sets the ack byte. There is little it can
+do except issue a diagnostic if the ack byte is not
+VIRTIO_NET_OK.
+
+  Packet Receive Filtering
+
+If the VIRTIO_NET_F_CTRL_RX feature is negotiated, the driver can
+send control commands for promiscuous mode, multicast receiving,
+and filtering of MAC addresses.
+
+Note that in general, these commands are best-effort: unwanted
+packets may still arrive.
+
+  Setting Promiscuous Mode
+
+#define VIRTIO_NET_CTRL_RX    0
+
+ #define VIRTIO_NET_CTRL_RX_PROMISC      0
+
+ #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+
+The class VIRTIO_NET_CTRL_RX has two commands:
+VIRTIO_NET_CTRL_RX_PROMISC turns promiscuous mode on and off, and
+VIRTIO_NET_CTRL_RX_ALLMULTI turns all-multicast receive on and
+off. The command-specific-data is one byte containing 0 (off) or
+1 (on).
+
+  Setting MAC Address Filtering
+
+struct virtio_net_ctrl_mac {
+
+       u32 entries;
+
+       u8 macs[entries][ETH_ALEN];
+
+};
+
+
+
+#define VIRTIO_NET_CTRL_MAC    1
+
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+
+The device can filter incoming packets by any number of
+destination MAC addresses.[footnote:
+Since there are no guarentees, it can use a hash filter
+orsilently switch to allmulti or promiscuous mode if it is given
+too many addresses.
+] This table is set using the class VIRTIO_NET_CTRL_MAC and the
+command VIRTIO_NET_CTRL_MAC_TABLE_SET. The command-specific-data
+is two variable length tables of 6-byte MAC addresses. The first
+table contains unicast addresses, and the second contains
+multicast addresses.
+
+  VLAN Filtering
+
+If the driver negotiates the VIRTION_NET_F_CTRL_VLAN feature, it
+can control a VLAN filter table in the device.
+
+#define VIRTIO_NET_CTRL_VLAN       2
+
+ #define VIRTIO_NET_CTRL_VLAN_ADD             0
+
+ #define VIRTIO_NET_CTRL_VLAN_DEL             1
+
+Both the VIRTIO_NET_CTRL_VLAN_ADD and VIRTIO_NET_CTRL_VLAN_DEL
+command take a 16-bit VLAN id as the command-specific-data.
+
+Appendix D: Block Device
+
+The virtio block device is a simple virtual block device (ie.
+disk). Read and write requests (and other exotic requests) are
+placed in the queue, and serviced (probably out of order) by the
+device except where noted.
+
+  Configuration
+
+  Subsystem Device ID 2
+
+  Virtqueues 0:requestq.
+
+  Feature bits
+
+  VIRTIO_BLK_F_BARRIER (0) Host supports request barriers.
+
+  VIRTIO_BLK_F_SIZE_MAX (1) Maximum size of any single segment is
+    in “size_max”.
+
+  VIRTIO_BLK_F_SEG_MAX (2) Maximum number of segments in a
+    request is in “seg_max”.
+
+  VIRTIO_BLK_F_GEOMETRY (4) Disk-style geometry specified in “
+    geometry”.
+
+  VIRTIO_BLK_F_RO (5) Device is read-only.
+
+  VIRTIO_BLK_F_BLK_SIZE (6) Block size of disk is in “blk_size”.
+
+  VIRTIO_BLK_F_SCSI (7) Device supports scsi packet commands.
+
+  VIRTIO_BLK_F_FLUSH (9) Cache flush command support.
+
+
+
+  Device configuration layout The capacity of the device
+  (expressed in 512-byte sectors) is always present. The
+  availability of the others all depend on various feature bits
+  as indicated above. struct virtio_blk_config {
+
+       u64 capacity;
+
+       u32 size_max;
+
+       u32 seg_max;
+
+       struct virtio_blk_geometry {
+
+               u16 cylinders;
+
+               u8 heads;
+
+               u8 sectors;
+
+       } geometry;
+
+       u32 blk_size;
+
+
+
+};
+
+  Device Initialization
+
+  The device size should be read from the “capacity”
+  configuration field. No requests should be submitted which goes
+  beyond this limit.
+
+  If the VIRTIO_BLK_F_BLK_SIZE feature is negotiated, the
+  blk_size field can be read to determine the optimal sector size
+  for the driver to use. This does not effect the units used in
+  the protocol (always 512 bytes), but awareness of the correct
+  value can effect performance.
+
+  If the VIRTIO_BLK_F_RO feature is set by the device, any write
+  requests will fail.
+
+
+
+  Device Operation
+
+The driver queues requests to the virtqueue, and they are used by
+the device (not necessarily in order). Each request is of form:
+
+struct virtio_blk_req {
+
+
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+       char data[][512];
+
+       u8 status;
+
+};
+
+If the device has VIRTIO_BLK_F_SCSI feature, it can also support
+scsi packet command requests, each of these requests is of form:struct virtio_scsi_pc_req {
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+    char cmd[];
+
+       char data[][512];
+
+#define SCSI_SENSE_BUFFERSIZE   96
+
+    u8 sense[SCSI_SENSE_BUFFERSIZE];
+
+    u32 errors;
+
+    u32 data_len;
+
+    u32 sense_len;
+
+    u32 residual;
+
+       u8 status;
+
+};
+
+The type of the request is either a read (VIRTIO_BLK_T_IN), a
+write (VIRTIO_BLK_T_OUT), a scsi packet command
+(VIRTIO_BLK_T_SCSI_CMD or VIRTIO_BLK_T_SCSI_CMD_OUT[footnote:
+the SCSI_CMD and SCSI_CMD_OUT types are equivalent, the device
+does not distinguish between them
+]) or a flush (VIRTIO_BLK_T_FLUSH or VIRTIO_BLK_T_FLUSH_OUT[footnote:
+the FLUSH and FLUSH_OUT types are equivalent, the device does not
+distinguish between them
+]). If the device has VIRTIO_BLK_F_BARRIER feature the high bit
+(VIRTIO_BLK_T_BARRIER) indicates that this request acts as a
+barrier and that all preceeding requests must be complete before
+this one, and all following requests must not be started until
+this is complete. Note that a barrier does not flush caches in
+the underlying backend device in host, and thus does not serve as
+data consistency guarantee. Driver must use FLUSH request to
+flush the host cache.
+
+#define VIRTIO_BLK_T_IN           0
+
+#define VIRTIO_BLK_T_OUT          1
+
+#define VIRTIO_BLK_T_SCSI_CMD     2
+
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+
+#define VIRTIO_BLK_T_FLUSH        4
+
+#define VIRTIO_BLK_T_FLUSH_OUT    5
+
+#define VIRTIO_BLK_T_BARRIER    0x80000000
+
+The ioprio field is a hint about the relative priorities of
+requests to the device: higher numbers indicate more important
+requests.
+
+The sector number indicates the offset (multiplied by 512) where
+the read or write is to occur. This field is unused and set to 0
+for scsi packet commands and for flush commands.
+
+The cmd field is only present for scsi packet command requests,
+and indicates the command to perform. This field must reside in a
+single, separate read-only buffer; command length can be derived
+from the length of this buffer.
+
+Note that these first three (four for scsi packet commands)
+fields are always read-only: the data field is either read-only
+or write-only, depending on the request. The size of the read or
+write can be derived from the total size of the request buffers.
+
+The sense field is only present for scsi packet command requests,
+and indicates the buffer for scsi sense data.
+
+The data_len field is only present for scsi packet command
+requests, this field is deprecated, and should be ignored by the
+driver. Historically, devices copied data length there.
+
+The sense_len field is only present for scsi packet command
+requests and indicates the number of bytes actually written to
+the sense buffer.
+
+The residual field is only present for scsi packet command
+requests and indicates the residual size, calculated as data
+length - number of bytes actually transferred.
+
+The final status byte is written by the device: either
+VIRTIO_BLK_S_OK for success, VIRTIO_BLK_S_IOERR for host or guest
+error or VIRTIO_BLK_S_UNSUPP for a request unsupported by host:#define VIRTIO_BLK_S_OK        0
+
+#define VIRTIO_BLK_S_IOERR     1
+
+#define VIRTIO_BLK_S_UNSUPP    2
+
+Historically, devices assumed that the fields type, ioprio and
+sector reside in a single, separate read-only buffer; the fields
+errors, data_len, sense_len and residual reside in a single,
+separate write-only buffer; the sense field in a separate
+write-only buffer of size 96 bytes, by itself; the fields errors,
+data_len, sense_len and residual in a single write-only buffer;
+and the status field is a separate read-only buffer of size 1
+byte, by itself.
+
+Appendix E: Console Device
+
+The virtio console device is a simple device for data input and
+output. A device may have one or more ports. Each port has a pair
+of input and output virtqueues. Moreover, a device has a pair of
+control IO virtqueues. The control virtqueues are used to
+communicate information between the device and the driver about
+ports being opened and closed on either side of the connection,
+indication from the host about whether a particular port is a
+console port, adding new ports, port hot-plug/unplug, etc., and
+indication from the guest about whether a port or a device was
+successfully added, port open/close, etc.. For data IO, one or
+more empty buffers are placed in the receive queue for incoming
+data and outgoing characters are placed in the transmit queue.
+
+  Configuration
+
+  Subsystem Device ID 3
+
+  Virtqueues 0:receiveq(port0). 1:transmitq(port0), 2:control
+  receiveq[footnote:
+Ports 2 onwards only if VIRTIO_CONSOLE_F_MULTIPORT is set
+], 3:control transmitq, 4:receiveq(port1), 5:transmitq(port1),
+  ...
+
+  Feature bits
+
+  VIRTIO_CONSOLE_F_SIZE (0) Configuration cols and rows fields
+    are valid.
+
+  VIRTIO_CONSOLE_F_MULTIPORT(1) Device has support for multiple
+    ports; configuration fields nr_ports and max_nr_ports are
+    valid and control virtqueues will be used.
+
+  Device configuration layout The size of the console is supplied
+  in the configuration space if the VIRTIO_CONSOLE_F_SIZE feature
+  is set. Furthermore, if the VIRTIO_CONSOLE_F_MULTIPORT feature
+  is set, the maximum number of ports supported by the device can
+  be fetched.struct virtio_console_config {
+
+       u16 cols;
+
+       u16 rows;
+
+
+
+       u32 max_nr_ports;
+
+};
+
+  Device Initialization
+
+  If the VIRTIO_CONSOLE_F_SIZE feature is negotiated, the driver
+  can read the console dimensions from the configuration fields.
+
+  If the VIRTIO_CONSOLE_F_MULTIPORT feature is negotiated, the
+  driver can spawn multiple ports, not all of which may be
+  attached to a console. Some could be generic ports. In this
+  case, the control virtqueues are enabled and according to the
+  max_nr_ports configuration-space value, the appropriate number
+  of virtqueues are created. A control message indicating the
+  driver is ready is sent to the host. The host can then send
+  control messages for adding new ports to the device. After
+  creating and initializing each port, a
+  VIRTIO_CONSOLE_PORT_READY control message is sent to the host
+  for that port so the host can let us know of any additional
+  configuration options set for that port.
+
+  The receiveq for each port is populated with one or more
+  receive buffers.
+
+  Device Operation
+
+  For output, a buffer containing the characters is placed in the
+  port's transmitq.[footnote:
+Because this is high importance and low bandwidth, the current
+Linux implementation polls for the buffer to be used, rather than
+waiting for an interrupt, simplifying the implementation
+significantly. However, for generic serial ports with the
+O_NONBLOCK flag set, the polling limitation is relaxed and the
+consumed buffers are freed upon the next write or poll call or
+when a port is closed or hot-unplugged.
+]
+
+  When a buffer is used in the receiveq (signalled by an
+  interrupt), the contents is the input to the port associated
+  with the virtqueue for which the notification was received.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_SIZE feature, a
+  configuration change interrupt may occur. The updated size can
+  be read from the configuration fields.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT
+  feature, active ports are announced by the host using the
+  VIRTIO_CONSOLE_PORT_ADD control message. The same message is
+  used for port hot-plug as well.
+
+  If the host specified a port `name', a sysfs attribute is
+  created with the name filled in, so that udev rules can be
+  written that can create a symlink from the port's name to the
+  char device for port discovery by applications in the guest.
+
+  Changes to ports' state are effected by control messages.
+  Appropriate action is taken on the port indicated in the
+  control message. The layout of the structure of the control
+  buffer and the events associated are:struct virtio_console_control {
+
+       uint32_t id;    /* Port number */
+
+       uint16_t event; /* The kind of control event */
+
+       uint16_t value; /* Extra information for the event */
+
+};
+
+
+
+/* Some events for the internal messages (control packets) */
+
+
+
+#define VIRTIO_CONSOLE_DEVICE_READY     0
+
+#define VIRTIO_CONSOLE_PORT_ADD         1
+
+#define VIRTIO_CONSOLE_PORT_REMOVE      2
+
+#define VIRTIO_CONSOLE_PORT_READY       3
+
+#define VIRTIO_CONSOLE_CONSOLE_PORT     4
+
+#define VIRTIO_CONSOLE_RESIZE           5
+
+#define VIRTIO_CONSOLE_PORT_OPEN        6
+
+#define VIRTIO_CONSOLE_PORT_NAME        7
+
+Appendix F: Entropy Device
+
+The virtio entropy device supplies high-quality randomness for
+guest use.
+
+  Configuration
+
+  Subsystem Device ID 4
+
+  Virtqueues 0:requestq.
+
+  Feature bits None currently defined
+
+  Device configuration layout None currently defined.
+
+  Device Initialization
+
+  The virtqueue is initialized
+
+  Device Operation
+
+When the driver requires random bytes, it places the descriptor
+of one or more buffers in the queue. It will be completely filled
+by random data by the device.
+
+Appendix G: Memory Balloon Device
+
+The virtio memory balloon device is a primitive device for
+managing guest memory: the device asks for a certain amount of
+memory, and the guest supplies it (or withdraws it, if the device
+has more than it asks for). This allows the guest to adapt to
+changes in allowance of underlying physical memory. If the
+feature is negotiated, the device can also be used to communicate
+guest memory statistics to the host.
+
+  Configuration
+
+  Subsystem Device ID 5
+
+  Virtqueues 0:inflateq. 1:deflateq. 2:statsq.[footnote:
+Only if VIRTIO_BALLON_F_STATS_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_BALLOON_F_MUST_TELL_HOST (0) Host must be told before
+    pages from the balloon are used.
+
+  VIRTIO_BALLOON_F_STATS_VQ (1) A virtqueue for reporting guest
+    memory statistics is present.
+
+  Device configuration layout Both fields of this configuration
+  are always available. Note that they are little endian, despite
+  convention that device fields are guest endian:struct virtio_balloon_config {
+
+       u32 num_pages;
+
+       u32 actual;
+
+};
+
+  Device Initialization
+
+  The inflate and deflate virtqueues are identified.
+
+  If the VIRTIO_BALLOON_F_STATS_VQ feature bit is negotiated:
+
+  Identify the stats virtqueue.
+
+  Add one empty buffer to the stats virtqueue and notify the
+    host.
+
+Device operation begins immediately.
+
+  Device Operation
+
+  Memory Ballooning The device is driven by the receipt of a
+  configuration change interrupt.
+
+  The “num_pages” configuration field is examined. If this is
+  greater than the “actual” number of pages, memory must be given
+  to the balloon. If it is less than the “actual” number of
+  pages, memory may be taken back from the balloon for general
+  use.
+
+  To supply memory to the balloon (aka. inflate):
+
+  The driver constructs an array of addresses of unused memory
+    pages. These addresses are divided by 4096[footnote:
+This is historical, and independent of the guest page size
+] and the descriptor describing the resulting 32-bit array is
+    added to the inflateq.
+
+  To remove memory from the balloon (aka. deflate):
+
+  The driver constructs an array of addresses of memory pages it
+    has previously given to the balloon, as described above. This
+    descriptor is added to the deflateq.
+
+  If the VIRTIO_BALLOON_F_MUST_TELL_HOST feature is set, the
+    guest may not use these requested pages until that descriptor
+    in the deflateq has been used by the device.
+
+  Otherwise, the guest may begin to re-use pages previously given
+    to the balloon before the device has acknowledged their
+    withdrawl. [footnote:
+In this case, deflation advice is merely a courtesy
+]
+
+  In either case, once the device has completed the inflation or
+  deflation, the “actual” field of the configuration should be
+  updated to reflect the new number of pages in the balloon.[footnote:
+As updates to configuration space are not atomic, this field
+isn't particularly reliable, but can be used to diagnose buggy
+guests.
+]
+
+  Memory Statistics
+
+The stats virtqueue is atypical because communication is driven
+by the device (not the driver). The channel becomes active at
+driver initialization time when the driver adds an empty buffer
+and notifies the device. A request for memory statistics proceeds
+as follows:
+
+  The device pushes the buffer onto the used ring and sends an
+  interrupt.
+
+  The driver pops the used buffer and discards it.
+
+  The driver collects memory statistics and writes them into a
+  new buffer.
+
+  The driver adds the buffer to the virtqueue and notifies the
+  device.
+
+  The device pops the buffer (retaining it to initiate a
+  subsequent request) and consumes the statistics.
+
+  Memory Statistics Format Each statistic consists of a 16 bit
+  tag and a 64 bit value. Both quantities are represented in the
+  native endian of the guest. All statistics are optional and the
+  driver may choose which ones to supply. To guarantee backwards
+  compatibility, unsupported statistics should be omitted.
+
+  struct virtio_balloon_stat {
+
+#define VIRTIO_BALLOON_S_SWAP_IN  0
+
+#define VIRTIO_BALLOON_S_SWAP_OUT 1
+
+#define VIRTIO_BALLOON_S_MAJFLT   2
+
+#define VIRTIO_BALLOON_S_MINFLT   3
+
+#define VIRTIO_BALLOON_S_MEMFREE  4
+
+#define VIRTIO_BALLOON_S_MEMTOT   5
+
+       u16 tag;
+
+       u64 val;
+
+} __attribute__((packed));
+
+  Tags
+
+  VIRTIO_BALLOON_S_SWAP_IN The amount of memory that has been
+  swapped in (in bytes).
+
+  VIRTIO_BALLOON_S_SWAP_OUT The amount of memory that has been
+  swapped out to disk (in bytes).
+
+  VIRTIO_BALLOON_S_MAJFLT The number of major page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MINFLT The number of minor page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MEMFREE The amount of memory not being used
+  for any purpose (in bytes).
+
+  VIRTIO_BALLOON_S_MEMTOT The total amount of memory available
+  (in bytes).
+
index 1d445f572987793c1919d3458af11a4d29cf72a4..069ee3b5c651ff31c7237bd514aff3bb40322873 100644 (file)
@@ -4971,7 +4971,7 @@ M:        Paul Mackerras <paulus@samba.org>
 M:     Ingo Molnar <mingo@elte.hu>
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 S:     Supported
-F:     kernel/perf_event*.c
+F:     kernel/events/*
 F:     include/linux/perf_event.h
 F:     arch/*/kernel/perf_event*.c
 F:     arch/*/kernel/*/perf_event*.c
index 3241d41dfbff0b6dd72c719e9b68f6bb53bb92f4..788511f86a6233ff6a24a4704a556dd4a7fba14f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
 PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
-NAME = Wet Seal
+EXTRAVERSION = -rc3
+NAME = "Divemaster Edition"
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
index 12485471495893cd00c80be024b7983c11e8168c..3ff7785b3beb4d5d042b60e07ce25dc793c8c10f 100644 (file)
@@ -162,7 +162,6 @@ config IA64_GENERIC
        select ACPI_NUMA
        select SWIOTLB
        select PCI_MSI
-       select DMAR
        help
          This selects the system type of your hardware.  A "generic" kernel
          will run on any supported IA-64 system.  However, if you configure
index 1d7bca0a396d3ba27068b5bd2ac48abdb72c1b00..0e5cd1405e0e506c28a7a7edd00a2ff82a20137d 100644 (file)
@@ -234,3 +234,4 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_T10DIF=y
 CONFIG_MISC_DEVICES=y
+CONFIG_DMAR=y
index 42c67beadcae2367e9cb7107bb125d188b3b4443..1a6f20d4e7e6b4648aed89fb7c986a672770ad29 100644 (file)
@@ -55,6 +55,7 @@ config SPARC64
        select PERF_USE_VMALLOC
        select IRQ_PREFLOW_FASTEOI
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select HAVE_C_RECORDMCOUNT
 
 config ARCH_DEFCONFIG
        string
index 5f5b8bf3f50d39a5c4b8cae94231cdd87543bbfa..bcc98fc35281c73bed1ae1e35cb4d56aade44794 100644 (file)
@@ -131,6 +131,15 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
        *(volatile __u32 *)&lp->lock = ~0U;
 }
 
+static void inline arch_write_unlock(arch_rwlock_t *lock)
+{
+       __asm__ __volatile__(
+"      st              %%g0, [%0]"
+       : /* no outputs */
+       : "r" (lock)
+       : "memory");
+}
+
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
        unsigned int val;
@@ -175,8 +184,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw)
        res; \
 })
 
-#define arch_write_unlock(rw)  do { (rw)->lock = 0; } while(0)
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_read_lock_flags(rw, flags)   arch_read_lock(rw)
 #define arch_write_lock_flags(rw, flags)  arch_write_lock(rw)
index 073936a8b2755e1c15e637ff28c5bc607876f4dc..9689176949781fc5ae8985a794def4521e6ba72b 100644 (file)
@@ -210,14 +210,8 @@ static int inline arch_write_trylock(arch_rwlock_t *lock)
        return result;
 }
 
-#define arch_read_lock(p)      arch_read_lock(p)
 #define arch_read_lock_flags(p, f) arch_read_lock(p)
-#define arch_read_trylock(p)   arch_read_trylock(p)
-#define arch_read_unlock(p)    arch_read_unlock(p)
-#define arch_write_lock(p)     arch_write_lock(p)
 #define arch_write_lock_flags(p, f) arch_write_lock(p)
-#define arch_write_unlock(p)   arch_write_unlock(p)
-#define arch_write_trylock(p)  arch_write_trylock(p)
 
 #define arch_read_can_lock(rw)         (!((rw)->lock & 0x80000000UL))
 #define arch_write_can_lock(rw)        (!(rw)->lock)
index a19f04195478a425d22a3da2264b8cf2aa3ce966..1aaf8c180be5d82544df54983ccaaa4ef5c7c071 100644 (file)
@@ -352,8 +352,8 @@ int __init pcic_probe(void)
        strcpy(pbm->prom_name, namebuf);
 
        {
-               extern volatile int t_nmi[1];
-               extern int pcic_nmi_trap_patch[1];
+               extern volatile int t_nmi[4];
+               extern int pcic_nmi_trap_patch[4];
 
                t_nmi[0] = pcic_nmi_trap_patch[0];
                t_nmi[1] = pcic_nmi_trap_patch[1];
index 64a619d47d341739ff34b5236e6bf85db0a79b06..7ff4669580cfc8bd0db462d3d0c07cf94cfddca0 100644 (file)
@@ -39,7 +39,7 @@ typedef struct xpaddr {
     ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
 
 extern unsigned long *machine_to_phys_mapping;
-extern unsigned int   machine_to_phys_order;
+extern unsigned long  machine_to_phys_nr;
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
 extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
@@ -87,7 +87,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return mfn;
 
-       if (unlikely((mfn >> machine_to_phys_order) != 0)) {
+       if (unlikely(mfn >= machine_to_phys_nr)) {
                pfn = ~0;
                goto try_override;
        }
index 988724b236b645466f337677fb2b2c950a252dc1..ff5790d8e990f0c382fa43c5ff2d3b5d7ed46c48 100644 (file)
@@ -22,6 +22,8 @@ config KVM
        depends on HAVE_KVM
        # for device assignment:
        depends on PCI
+       # for TASKSTATS/TASK_DELAY_ACCT:
+       depends on NET
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
        select ANON_INODES
@@ -31,6 +33,7 @@ config KVM
        select KVM_ASYNC_PF
        select USER_RETURN_NOTIFIER
        select KVM_MMIO
+       select TASKSTATS
        select TASK_DELAY_ACCT
        ---help---
          Support hosting fully virtualized guest machines using hardware
index 247aae3dc008bdc78c58ff582fac3c61617b7f45..0d17c8c50acd54334b6c92335dad6e4c954ca18f 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/traps.h>                 /* dotraplinkage, ...           */
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
 #include <asm/kmemcheck.h>             /* kmemcheck_*(), ...           */
+#include <asm/vsyscall.h>
 
 /*
  * Page fault error code bits:
index ae3cb23cd89b86cdecbc6e202fb7e2d912079cf5..c95330267f08cfee41a27a0c94675d5779776f86 100644 (file)
@@ -360,6 +360,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
                }
        }
 
+       /* After the PCI-E bus has been walked and all devices discovered,
+        * configure any settings of the fabric that might be necessary.
+        */
+       if (bus) {
+               struct pci_bus *child;
+               list_for_each_entry(child, &bus->children, node)
+                       pcie_bus_configure_settings(child, child->self->pcie_mpss);
+       }
+
        if (!bus)
                kfree(sd);
 
index 3326204e251f3108650944ef1d558c98745c1935..add2c2d729cef9a0bc804a0cafd6477f142c4df3 100644 (file)
@@ -15,7 +15,7 @@ obj-y         := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        grant-table.o suspend.o platform-pci-unplug.o \
                        p2m.o
 
-obj-$(CONFIG_FTRACE) += trace.o
+obj-$(CONFIG_EVENT_TRACING) += trace.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
index e2345af01af0aeeeef02c6306f50ba984c2f9c29..2d69617950f7c94a8e14c7e5fe7ad8730aa26eeb 100644 (file)
@@ -77,8 +77,8 @@ EXPORT_SYMBOL_GPL(xen_domain_type);
 
 unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
 EXPORT_SYMBOL(machine_to_phys_mapping);
-unsigned int   machine_to_phys_order;
-EXPORT_SYMBOL(machine_to_phys_order);
+unsigned long  machine_to_phys_nr;
+EXPORT_SYMBOL(machine_to_phys_nr);
 
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
index 8cce339db5e7e00e436a2c10b16eadefb8a8ff34..20a6142750644442492dabdbbd6a55aaa75244a5 100644 (file)
@@ -1713,15 +1713,19 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 void __init xen_setup_machphys_mapping(void)
 {
        struct xen_machphys_mapping mapping;
-       unsigned long machine_to_phys_nr_ents;
 
        if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
                machine_to_phys_mapping = (unsigned long *)mapping.v_start;
-               machine_to_phys_nr_ents = mapping.max_mfn + 1;
+               machine_to_phys_nr = mapping.max_mfn + 1;
        } else {
-               machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+               machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
        }
-       machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+#ifdef CONFIG_X86_32
+       if ((machine_to_phys_mapping + machine_to_phys_nr)
+           < machine_to_phys_mapping)
+               machine_to_phys_nr = (unsigned long *)NULL
+                                    - machine_to_phys_mapping;
+#endif
 }
 
 #ifdef CONFIG_X86_64
index b4533a86d7e410668e24033cae32d8382bf4111d..e79dbb95482b84f07f01506ca3692ae8ee63ca22 100644 (file)
@@ -521,8 +521,6 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
        native_smp_prepare_cpus(max_cpus);
        WARN_ON(xen_smp_intr_init(0));
 
-       if (!xen_have_vector_callback)
-               return;
        xen_init_lock_cpu(0);
        xen_init_spinlocks();
 }
@@ -546,6 +544,8 @@ static void xen_hvm_cpu_die(unsigned int cpu)
 
 void __init xen_hvm_smp_init(void)
 {
+       if (!xen_have_vector_callback)
+               return;
        smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
        smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
        smp_ops.cpu_up = xen_hvm_cpu_up;
index 60be1e0455daddb636998a03eb6d47e60d1eae81..e97934eececacbbf4e62d96da3887b624bffeedd 100644 (file)
@@ -65,6 +65,16 @@ config BLK_DEV_BSG
 
          If unsure, say Y.
 
+config BLK_DEV_BSGLIB
+       bool "Block layer SG support v4 helper lib"
+       default n
+       select BLK_DEV_BSG
+       help
+         Subsystems will normally enable this if needed. Users will not
+         normally need to manually enable this.
+
+         If unsure, say N.
+
 config BLK_DEV_INTEGRITY
        bool "Block layer data integrity support"
        ---help---
index 0fec4b3fab511bc065261121f279e6f64038c35c..514c6e4f427a80f269bef08473cc048e5125b968 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-iopoll.o blk-lib.o ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
+obj-$(CONFIG_BLK_DEV_BSGLIB)   += bsg-lib.o
 obj-$(CONFIG_BLK_CGROUP)       += blk-cgroup.o
 obj-$(CONFIG_BLK_DEV_THROTTLING)       += blk-throttle.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
index b627558c461fa7a1d9eaf6ea447db093852c8274..90e1ffdeb415914ffaad20b31f54c8e22d05ce79 100644 (file)
@@ -1702,6 +1702,7 @@ EXPORT_SYMBOL_GPL(blk_rq_check_limits);
 int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
 {
        unsigned long flags;
+       int where = ELEVATOR_INSERT_BACK;
 
        if (blk_rq_check_limits(q, rq))
                return -EIO;
@@ -1718,7 +1719,10 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
         */
        BUG_ON(blk_queued_rq(rq));
 
-       add_acct_request(q, rq, ELEVATOR_INSERT_BACK);
+       if (rq->cmd_flags & (REQ_FLUSH|REQ_FUA))
+               where = ELEVATOR_INSERT_FLUSH;
+
+       add_acct_request(q, rq, where);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        return 0;
@@ -2275,7 +2279,7 @@ static bool blk_end_bidi_request(struct request *rq, int error,
  *     %false - we are done with this request
  *     %true  - still buffers pending for this request
  **/
-static bool __blk_end_bidi_request(struct request *rq, int error,
+bool __blk_end_bidi_request(struct request *rq, int error,
                                   unsigned int nr_bytes, unsigned int bidi_bytes)
 {
        if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes))
index bb21e4c36f70ca437162356edd87d2ce3a265a46..491eb30a242db435b55a7ba962e4acce5af81a15 100644 (file)
@@ -95,11 +95,12 @@ static unsigned int blk_flush_policy(unsigned int fflags, struct request *rq)
 {
        unsigned int policy = 0;
 
+       if (blk_rq_sectors(rq))
+               policy |= REQ_FSEQ_DATA;
+
        if (fflags & REQ_FLUSH) {
                if (rq->cmd_flags & REQ_FLUSH)
                        policy |= REQ_FSEQ_PREFLUSH;
-               if (blk_rq_sectors(rq))
-                       policy |= REQ_FSEQ_DATA;
                if (!(fflags & REQ_FUA) && (rq->cmd_flags & REQ_FUA))
                        policy |= REQ_FSEQ_POSTFLUSH;
        }
@@ -122,7 +123,7 @@ static void blk_flush_restore_request(struct request *rq)
 
        /* make @rq a normal request */
        rq->cmd_flags &= ~REQ_FLUSH_SEQ;
-       rq->end_io = NULL;
+       rq->end_io = rq->flush.saved_end_io;
 }
 
 /**
@@ -300,9 +301,6 @@ void blk_insert_flush(struct request *rq)
        unsigned int fflags = q->flush_flags;   /* may change, cache */
        unsigned int policy = blk_flush_policy(fflags, rq);
 
-       BUG_ON(rq->end_io);
-       BUG_ON(!rq->bio || rq->bio != rq->biotail);
-
        /*
         * @policy now records what operations need to be done.  Adjust
         * REQ_FLUSH and FUA for the driver.
@@ -311,6 +309,19 @@ void blk_insert_flush(struct request *rq)
        if (!(fflags & REQ_FUA))
                rq->cmd_flags &= ~REQ_FUA;
 
+       /*
+        * An empty flush handed down from a stacking driver may
+        * translate into nothing if the underlying device does not
+        * advertise a write-back cache.  In this case, simply
+        * complete the request.
+        */
+       if (!policy) {
+               __blk_end_bidi_request(rq, 0, 0, 0);
+               return;
+       }
+
+       BUG_ON(!rq->bio || rq->bio != rq->biotail);
+
        /*
         * If there's data but flush is not necessary, the request can be
         * processed directly without going through flush machinery.  Queue
@@ -319,6 +330,7 @@ void blk_insert_flush(struct request *rq)
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
                list_add_tail(&rq->queuelist, &q->queue_head);
+               blk_run_queue_async(q);
                return;
        }
 
@@ -329,6 +341,7 @@ void blk_insert_flush(struct request *rq)
        memset(&rq->flush, 0, sizeof(rq->flush));
        INIT_LIST_HEAD(&rq->flush.list);
        rq->cmd_flags |= REQ_FLUSH_SEQ;
+       rq->flush.saved_end_io = rq->end_io; /* Usually NULL */
        rq->end_io = flush_data_end_io;
 
        blk_flush_complete_seq(rq, REQ_FSEQ_ACTIONS & ~policy, 0);
index 475fab809a80cce9eb5573fbb392597d8dd9b838..58340d0cb23a82d40edf95b77874a5781d49bcdb 100644 (file)
@@ -124,6 +124,14 @@ void __blk_complete_request(struct request *req)
        } else
                ccpu = cpu;
 
+       /*
+        * If current CPU and requested CPU are in the same group, running
+        * softirq in current CPU. One might concern this is just like
+        * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is
+        * running in interrupt handler, and currently I/O controller doesn't
+        * support multiple interrupts, so current CPU is unique actually. This
+        * avoids IPI sending from current CPU to the first CPU of a group.
+        */
        if (ccpu == cpu || ccpu == group_cpu) {
                struct list_head *list;
 do_local:
index f6a794120505668084929afdacd0b5e17f8fca8d..a19f58c6fc3a5b5012aabb9f4891c0bbe19ce476 100644 (file)
@@ -746,7 +746,7 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
 static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
 {
        bool rw = bio_data_dir(bio);
-       bool sync = bio->bi_rw & REQ_SYNC;
+       bool sync = rw_is_sync(bio->bi_rw);
 
        /* Charge the bio to the group */
        tg->bytes_disp[rw] += bio->bi_size;
@@ -1150,7 +1150,7 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
 
                if (tg_no_rule_group(tg, rw)) {
                        blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size,
-                                       rw, bio->bi_rw & REQ_SYNC);
+                                       rw, rw_is_sync(bio->bi_rw));
                        rcu_read_unlock();
                        return 0;
                }
index d6586287adc9ccf44e0adc556b552c7b1404ca4b..20b900a377c9d8ba85ab8ba45f10c4deb64652f4 100644 (file)
@@ -17,6 +17,8 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
                      struct bio *bio);
 void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
+bool __blk_end_bidi_request(struct request *rq, int error,
+                           unsigned int nr_bytes, unsigned int bidi_bytes);
 
 void blk_rq_timed_out_timer(unsigned long data);
 void blk_delete_timer(struct request *);
diff --git a/block/bsg-lib.c b/block/bsg-lib.c
new file mode 100644 (file)
index 0000000..6690e6e
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *  BSG helper library
+ *
+ *  Copyright (C) 2008   James Smart, Emulex Corporation
+ *  Copyright (C) 2011   Red Hat, Inc.  All rights reserved.
+ *  Copyright (C) 2011   Mike Christie
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/bsg-lib.h>
+#include <linux/module.h>
+#include <scsi/scsi_cmnd.h>
+
+/**
+ * bsg_destroy_job - routine to teardown/delete a bsg job
+ * @job: bsg_job that is to be torn down
+ */
+static void bsg_destroy_job(struct bsg_job *job)
+{
+       put_device(job->dev);   /* release reference for the request */
+
+       kfree(job->request_payload.sg_list);
+       kfree(job->reply_payload.sg_list);
+       kfree(job);
+}
+
+/**
+ * bsg_job_done - completion routine for bsg requests
+ * @job: bsg_job that is complete
+ * @result: job reply result
+ * @reply_payload_rcv_len: length of payload recvd
+ *
+ * The LLD should call this when the bsg job has completed.
+ */
+void bsg_job_done(struct bsg_job *job, int result,
+                 unsigned int reply_payload_rcv_len)
+{
+       struct request *req = job->req;
+       struct request *rsp = req->next_rq;
+       int err;
+
+       err = job->req->errors = result;
+       if (err < 0)
+               /* we're only returning the result field in the reply */
+               job->req->sense_len = sizeof(u32);
+       else
+               job->req->sense_len = job->reply_len;
+       /* we assume all request payload was transferred, residual == 0 */
+       req->resid_len = 0;
+
+       if (rsp) {
+               WARN_ON(reply_payload_rcv_len > rsp->resid_len);
+
+               /* set reply (bidi) residual */
+               rsp->resid_len -= min(reply_payload_rcv_len, rsp->resid_len);
+       }
+       blk_complete_request(req);
+}
+EXPORT_SYMBOL_GPL(bsg_job_done);
+
+/**
+ * bsg_softirq_done - softirq done routine for destroying the bsg requests
+ * @rq: BSG request that holds the job to be destroyed
+ */
+static void bsg_softirq_done(struct request *rq)
+{
+       struct bsg_job *job = rq->special;
+
+       blk_end_request_all(rq, rq->errors);
+       bsg_destroy_job(job);
+}
+
+static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
+{
+       size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments);
+
+       BUG_ON(!req->nr_phys_segments);
+
+       buf->sg_list = kzalloc(sz, GFP_KERNEL);
+       if (!buf->sg_list)
+               return -ENOMEM;
+       sg_init_table(buf->sg_list, req->nr_phys_segments);
+       buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list);
+       buf->payload_len = blk_rq_bytes(req);
+       return 0;
+}
+
+/**
+ * bsg_create_job - create the bsg_job structure for the bsg request
+ * @dev: device that is being sent the bsg request
+ * @req: BSG request that needs a job structure
+ */
+static int bsg_create_job(struct device *dev, struct request *req)
+{
+       struct request *rsp = req->next_rq;
+       struct request_queue *q = req->q;
+       struct bsg_job *job;
+       int ret;
+
+       BUG_ON(req->special);
+
+       job = kzalloc(sizeof(struct bsg_job) + q->bsg_job_size, GFP_KERNEL);
+       if (!job)
+               return -ENOMEM;
+
+       req->special = job;
+       job->req = req;
+       if (q->bsg_job_size)
+               job->dd_data = (void *)&job[1];
+       job->request = req->cmd;
+       job->request_len = req->cmd_len;
+       job->reply = req->sense;
+       job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer
+                                                * allocated */
+       if (req->bio) {
+               ret = bsg_map_buffer(&job->request_payload, req);
+               if (ret)
+                       goto failjob_rls_job;
+       }
+       if (rsp && rsp->bio) {
+               ret = bsg_map_buffer(&job->reply_payload, rsp);
+               if (ret)
+                       goto failjob_rls_rqst_payload;
+       }
+       job->dev = dev;
+       /* take a reference for the request */
+       get_device(job->dev);
+       return 0;
+
+failjob_rls_rqst_payload:
+       kfree(job->request_payload.sg_list);
+failjob_rls_job:
+       kfree(job);
+       return -ENOMEM;
+}
+
+/*
+ * bsg_goose_queue - restart queue in case it was stopped
+ * @q: request q to be restarted
+ */
+void bsg_goose_queue(struct request_queue *q)
+{
+       if (!q)
+               return;
+
+       blk_run_queue_async(q);
+}
+EXPORT_SYMBOL_GPL(bsg_goose_queue);
+
+/**
+ * bsg_request_fn - generic handler for bsg requests
+ * @q: request queue to manage
+ *
+ * On error the create_bsg_job function should return a -Exyz error value
+ * that will be set to the req->errors.
+ *
+ * Drivers/subsys should pass this to the queue init function.
+ */
+void bsg_request_fn(struct request_queue *q)
+{
+       struct device *dev = q->queuedata;
+       struct request *req;
+       struct bsg_job *job;
+       int ret;
+
+       if (!get_device(dev))
+               return;
+
+       while (1) {
+               req = blk_fetch_request(q);
+               if (!req)
+                       break;
+               spin_unlock_irq(q->queue_lock);
+
+               ret = bsg_create_job(dev, req);
+               if (ret) {
+                       req->errors = ret;
+                       blk_end_request_all(req, ret);
+                       spin_lock_irq(q->queue_lock);
+                       continue;
+               }
+
+               job = req->special;
+               ret = q->bsg_job_fn(job);
+               spin_lock_irq(q->queue_lock);
+               if (ret)
+                       break;
+       }
+
+       spin_unlock_irq(q->queue_lock);
+       put_device(dev);
+       spin_lock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL_GPL(bsg_request_fn);
+
+/**
+ * bsg_setup_queue - Create and add the bsg hooks so we can receive requests
+ * @dev: device to attach bsg device to
+ * @q: request queue setup by caller
+ * @name: device to give bsg device
+ * @job_fn: bsg job handler
+ * @dd_job_size: size of LLD data needed for each job
+ *
+ * The caller should have setup the reuqest queue with bsg_request_fn
+ * as the request_fn.
+ */
+int bsg_setup_queue(struct device *dev, struct request_queue *q,
+                   char *name, bsg_job_fn *job_fn, int dd_job_size)
+{
+       int ret;
+
+       q->queuedata = dev;
+       q->bsg_job_size = dd_job_size;
+       q->bsg_job_fn = job_fn;
+       queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+       blk_queue_softirq_done(q, bsg_softirq_done);
+       blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
+
+       ret = bsg_register_queue(q, dev, name, NULL);
+       if (ret) {
+               printk(KERN_ERR "%s: bsg interface failed to "
+                      "initialize - register queue\n", dev->kobj.name);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bsg_setup_queue);
+
+/**
+ * bsg_remove_queue - Deletes the bsg dev from the q
+ * @q: the request_queue that is to be torn down.
+ *
+ * Notes:
+ *   Before unregistering the queue empty any requests that are blocked
+ */
+void bsg_remove_queue(struct request_queue *q)
+{
+       struct request *req; /* block request */
+       int counts; /* totals for request_list count and starved */
+
+       if (!q)
+               return;
+
+       /* Stop taking in new requests */
+       spin_lock_irq(q->queue_lock);
+       blk_stop_queue(q);
+
+       /* drain all requests in the queue */
+       while (1) {
+               /* need the lock to fetch a request
+                * this may fetch the same reqeust as the previous pass
+                */
+               req = blk_fetch_request(q);
+               /* save requests in use and starved */
+               counts = q->rq.count[0] + q->rq.count[1] +
+                        q->rq.starved[0] + q->rq.starved[1];
+               spin_unlock_irq(q->queue_lock);
+               /* any requests still outstanding? */
+               if (counts == 0)
+                       break;
+
+               /* This may be the same req as the previous iteration,
+                * always send the blk_end_request_all after a prefetch.
+                * It is not okay to not end the request because the
+                * prefetch started the request.
+                */
+               if (req) {
+                       /* return -ENXIO to indicate that this queue is
+                        * going away
+                        */
+                       req->errors = -ENXIO;
+                       blk_end_request_all(req, -ENXIO);
+               }
+
+               msleep(200); /* allow bsg to possibly finish */
+               spin_lock_irq(q->queue_lock);
+       }
+       bsg_unregister_queue(q);
+}
+EXPORT_SYMBOL_GPL(bsg_remove_queue);
index 1f96ad6254f1eea18478b80f3a58de4173c9f8ef..a33bd4377c615e789509431c5f8a7583939149a4 100644 (file)
@@ -130,6 +130,8 @@ struct cfq_queue {
        unsigned long slice_end;
        long slice_resid;
 
+       /* pending metadata requests */
+       int meta_pending;
        /* number of requests that are on the dispatch list or inside driver */
        int dispatched;
 
@@ -682,6 +684,9 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
        if (rq_is_sync(rq1) != rq_is_sync(rq2))
                return rq_is_sync(rq1) ? rq1 : rq2;
 
+       if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
+               return rq1->cmd_flags & REQ_META ? rq1 : rq2;
+
        s1 = blk_rq_pos(rq1);
        s2 = blk_rq_pos(rq2);
 
@@ -1209,6 +1214,9 @@ static void cfq_destroy_cfqg(struct cfq_data *cfqd, struct cfq_group *cfqg)
 
        hlist_del_init(&cfqg->cfqd_node);
 
+       BUG_ON(cfqd->nr_blkcg_linked_grps <= 0);
+       cfqd->nr_blkcg_linked_grps--;
+
        /*
         * Put the reference taken at the time of creation so that when all
         * queues are gone, group can be destroyed.
@@ -1604,6 +1612,10 @@ static void cfq_remove_request(struct request *rq)
        cfqq->cfqd->rq_queued--;
        cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg,
                                        rq_data_dir(rq), rq_is_sync(rq));
+       if (rq->cmd_flags & REQ_META) {
+               WARN_ON(!cfqq->meta_pending);
+               cfqq->meta_pending--;
+       }
 }
 
 static int cfq_merge(struct request_queue *q, struct request **req,
@@ -3356,6 +3368,13 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
            RB_EMPTY_ROOT(&cfqq->sort_list))
                return true;
 
+       /*
+        * So both queues are sync. Let the new request get disk time if
+        * it's a metadata request and the current queue is doing regular IO.
+        */
+       if ((rq->cmd_flags & REQ_META) && !cfqq->meta_pending)
+               return true;
+
        /*
         * Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice.
         */
@@ -3420,6 +3439,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct cfq_io_context *cic = RQ_CIC(rq);
 
        cfqd->rq_queued++;
+       if (rq->cmd_flags & REQ_META)
+               cfqq->meta_pending++;
 
        cfq_update_io_thinktime(cfqd, cfqq, cic);
        cfq_update_io_seektime(cfqd, cfqq, rq);
index 5cb51c55f6d8d57309888aa2810b89f44d876301..e2f67902dd024ed2f07abdfc190c73558d2ddb7b 100644 (file)
@@ -1146,17 +1146,17 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                cpu = part_stat_lock();
                part_round_stats(cpu, hd);
                part_stat_unlock();
-               seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
-                          "%u %lu %lu %llu %u %u %u %u\n",
+               seq_printf(seqf, "%4d %7d %s %lu %lu %lu "
+                          "%u %lu %lu %lu %u %u %u %u\n",
                           MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
                           disk_name(gp, hd->partno, buf),
                           part_stat_read(hd, ios[READ]),
                           part_stat_read(hd, merges[READ]),
-                          (unsigned long long)part_stat_read(hd, sectors[READ]),
+                          part_stat_read(hd, sectors[READ]),
                           jiffies_to_msecs(part_stat_read(hd, ticks[READ])),
                           part_stat_read(hd, ios[WRITE]),
                           part_stat_read(hd, merges[WRITE]),
-                          (unsigned long long)part_stat_read(hd, sectors[WRITE]),
+                          part_stat_read(hd, sectors[WRITE]),
                           jiffies_to_msecs(part_stat_read(hd, ticks[WRITE])),
                           part_in_flight(hd),
                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
index ca3e6be44a0473a9f532ee6ed6af23ac3cab1cde..5987e0ba8c2de7b4548325211d98798d4abc7307 100644 (file)
@@ -468,6 +468,15 @@ config PATA_ICSIDE
          interface card.  This is not required for ICS partition support.
          If you are unsure, say N to this.
 
+config PATA_IMX
+       tristate "PATA support for Freescale iMX"
+       depends on ARCH_MXC
+       help
+         This option enables support for the PATA host available on Freescale
+          iMX SoCs.
+
+         If unsure, say N.
+
 config PATA_IT8213
        tristate "IT8213 PATA support (Experimental)"
        depends on PCI && EXPERIMENTAL
index 8ac64e1aa051c0043a1c4cc24ff49efdcfd74635..9550d691fd19bc92b2d7a53f4beca3bc85350cb8 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_PATA_HPT37X)     += pata_hpt37x.o
 obj-$(CONFIG_PATA_HPT3X2N)     += pata_hpt3x2n.o
 obj-$(CONFIG_PATA_HPT3X3)      += pata_hpt3x3.o
 obj-$(CONFIG_PATA_ICSIDE)      += pata_icside.o
+obj-$(CONFIG_PATA_IMX)         += pata_imx.o
 obj-$(CONFIG_PATA_IT8213)      += pata_it8213.o
 obj-$(CONFIG_PATA_IT821X)      += pata_it821x.o
 obj-$(CONFIG_PATA_JMICRON)     += pata_jmicron.o
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
new file mode 100644 (file)
index 0000000..ca9d9ca
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Freescale iMX PATA driver
+ *
+ * Copyright (C) 2011 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Based on pata_platform - Copyright (C) 2006 - 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * TODO:
+ * - dmaengine support
+ * - check if timing stuff needed
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#define DRV_NAME "pata_imx"
+
+#define PATA_IMX_ATA_CONTROL           0x24
+#define PATA_IMX_ATA_CTRL_FIFO_RST_B   (1<<7)
+#define PATA_IMX_ATA_CTRL_ATA_RST_B    (1<<6)
+#define PATA_IMX_ATA_CTRL_IORDY_EN     (1<<0)
+#define PATA_IMX_ATA_INT_EN            0x2C
+#define PATA_IMX_ATA_INTR_ATA_INTRQ2   (1<<3)
+#define PATA_IMX_DRIVE_DATA            0xA0
+#define PATA_IMX_DRIVE_CONTROL         0xD8
+
+struct pata_imx_priv {
+       struct clk *clk;
+       /* timings/interrupt/control regs */
+       u8 *host_regs;
+       u32 ata_ctl;
+};
+
+static int pata_imx_set_mode(struct ata_link *link, struct ata_device **unused)
+{
+       struct ata_device *dev;
+       struct ata_port *ap = link->ap;
+       struct pata_imx_priv *priv = ap->host->private_data;
+       u32 val;
+
+       ata_for_each_dev(dev, link, ENABLED) {
+               dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
+
+               val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+               if (ata_pio_need_iordy(dev))
+                       val |= PATA_IMX_ATA_CTRL_IORDY_EN;
+               else
+                       val &= ~PATA_IMX_ATA_CTRL_IORDY_EN;
+               __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+       }
+       return 0;
+}
+
+static struct scsi_host_template pata_imx_sht = {
+       ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_imx_port_ops = {
+       .inherits               = &ata_sff_port_ops,
+       .sff_data_xfer          = ata_sff_data_xfer_noirq,
+       .cable_detect           = ata_cable_unknown,
+       .set_mode               = pata_imx_set_mode,
+};
+
+static void pata_imx_setup_port(struct ata_ioports *ioaddr)
+{
+       /* Fixup the port shift for platforms that need it */
+       ioaddr->data_addr       = ioaddr->cmd_addr + (ATA_REG_DATA    << 2);
+       ioaddr->error_addr      = ioaddr->cmd_addr + (ATA_REG_ERR     << 2);
+       ioaddr->feature_addr    = ioaddr->cmd_addr + (ATA_REG_FEATURE << 2);
+       ioaddr->nsect_addr      = ioaddr->cmd_addr + (ATA_REG_NSECT   << 2);
+       ioaddr->lbal_addr       = ioaddr->cmd_addr + (ATA_REG_LBAL    << 2);
+       ioaddr->lbam_addr       = ioaddr->cmd_addr + (ATA_REG_LBAM    << 2);
+       ioaddr->lbah_addr       = ioaddr->cmd_addr + (ATA_REG_LBAH    << 2);
+       ioaddr->device_addr     = ioaddr->cmd_addr + (ATA_REG_DEVICE  << 2);
+       ioaddr->status_addr     = ioaddr->cmd_addr + (ATA_REG_STATUS  << 2);
+       ioaddr->command_addr    = ioaddr->cmd_addr + (ATA_REG_CMD     << 2);
+}
+
+static int __devinit pata_imx_probe(struct platform_device *pdev)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+       struct pata_imx_priv *priv;
+       int irq = 0;
+       struct resource *io_res;
+
+       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (io_res == NULL)
+               return -EINVAL;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -EINVAL;
+
+       priv = devm_kzalloc(&pdev->dev,
+                               sizeof(struct pata_imx_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "Failed to get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       clk_enable(priv->clk);
+
+       host = ata_host_alloc(&pdev->dev, 1);
+       if (!host)
+               goto free_priv;
+
+       host->private_data = priv;
+       ap = host->ports[0];
+
+       ap->ops = &pata_imx_port_ops;
+       ap->pio_mask = ATA_PIO0;
+       ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+       priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
+               resource_size(io_res));
+       if (!priv->host_regs) {
+               dev_err(&pdev->dev, "failed to map IO/CTL base\n");
+               goto free_priv;
+       }
+
+       ap->ioaddr.cmd_addr = priv->host_regs + PATA_IMX_DRIVE_DATA;
+       ap->ioaddr.ctl_addr = priv->host_regs + PATA_IMX_DRIVE_CONTROL;
+
+       ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+
+       pata_imx_setup_port(&ap->ioaddr);
+
+       ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+               (unsigned long long)io_res->start + PATA_IMX_DRIVE_DATA,
+               (unsigned long long)io_res->start + PATA_IMX_DRIVE_CONTROL);
+
+       /* deassert resets */
+       __raw_writel(PATA_IMX_ATA_CTRL_FIFO_RST_B |
+                       PATA_IMX_ATA_CTRL_ATA_RST_B,
+                       priv->host_regs + PATA_IMX_ATA_CONTROL);
+       /* enable interrupts */
+       __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+                       priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       /* activate */
+       return ata_host_activate(host, irq, ata_sff_interrupt, 0,
+                               &pata_imx_sht);
+
+free_priv:
+       clk_disable(priv->clk);
+       clk_put(priv->clk);
+       return -ENOMEM;
+}
+
+static int __devexit pata_imx_remove(struct platform_device *pdev)
+{
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct pata_imx_priv *priv = host->private_data;
+
+       ata_host_detach(host);
+
+       __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       clk_disable(priv->clk);
+       clk_put(priv->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pata_imx_suspend(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct pata_imx_priv *priv = host->private_data;
+       int ret;
+
+       ret = ata_host_suspend(host, PMSG_SUSPEND);
+       if (!ret) {
+               __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+               priv->ata_ctl =
+                       __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+               clk_disable(priv->clk);
+       }
+
+       return ret;
+}
+
+static int pata_imx_resume(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct pata_imx_priv *priv = host->private_data;
+
+       clk_enable(priv->clk);
+
+       __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+       __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+                       priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+       ata_host_resume(host);
+
+       return 0;
+}
+
+static const struct dev_pm_ops pata_imx_pm_ops = {
+       .suspend        = pata_imx_suspend,
+       .resume         = pata_imx_resume,
+};
+#endif
+
+static struct platform_driver pata_imx_driver = {
+       .probe          = pata_imx_probe,
+       .remove         = __devexit_p(pata_imx_remove),
+       .driver = {
+               .name           = DRV_NAME,
+               .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm             = &pata_imx_pm_ops,
+#endif
+       },
+};
+
+static int __init pata_imx_init(void)
+{
+       return platform_driver_register(&pata_imx_driver);
+}
+
+static void __exit pata_imx_exit(void)
+{
+       platform_driver_unregister(&pata_imx_driver);
+}
+module_init(pata_imx_init);
+module_exit(pata_imx_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("low-level driver for iMX PATA");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 65e4be6be22061c882c9763661b319c0725f3d5d..8e9f5048a10a9dab8b2705a579d401d972fe036a 100644 (file)
@@ -124,6 +124,17 @@ static const struct via_isa_bridge {
        { NULL }
 };
 
+static const struct dmi_system_id no_atapi_dma_dmi_table[] = {
+       {
+               .ident = "AVERATEC 3200",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AVERATEC"),
+                       DMI_MATCH(DMI_BOARD_NAME, "3200"),
+               },
+       },
+       { }
+};
+
 struct via_port {
        u8 cached_device;
 };
@@ -355,6 +366,13 @@ static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask)
                        mask &= ~ ATA_MASK_UDMA;
                }
        }
+
+       if (dev->class == ATA_DEV_ATAPI &&
+           dmi_check_system(no_atapi_dma_dmi_table)) {
+               ata_dev_warn(dev, "controller locks up on ATAPI DMA, forcing PIO\n");
+               mask &= ATA_MASK_PIO;
+       }
+
        return mask;
 }
 
index 0a9a774a7e1e9f54c9b2188b251b2a5105c800ea..5c4237452f5072a97a82eca00e95d55c15ce2542 100644 (file)
@@ -1329,7 +1329,7 @@ static int sata_dwc_port_start(struct ata_port *ap)
                        dev_err(ap->dev, "%s: dma_alloc_coherent failed\n",
                                 __func__);
                        err = -ENOMEM;
-                       goto CLEANUP;
+                       goto CLEANUP_ALLOC;
                }
        }
 
@@ -1349,15 +1349,13 @@ static int sata_dwc_port_start(struct ata_port *ap)
        /* Clear any error bits before libata starts issuing commands */
        clear_serror();
        ap->private_data = hsdevp;
+       dev_dbg(ap->dev, "%s: done\n", __func__);
+       return 0;
 
+CLEANUP_ALLOC:
+       kfree(hsdevp);
 CLEANUP:
-       if (err) {
-               sata_dwc_port_stop(ap);
-               dev_dbg(ap->dev, "%s: fail\n", __func__);
-       } else {
-               dev_dbg(ap->dev, "%s: done\n", __func__);
-       }
-
+       dev_dbg(ap->dev, "%s: fail. ap->id = %d\n", __func__, ap->print_id);
        return err;
 }
 
index 98c1d780f552505aac129cf2133b98576161e6ca..9dfb40b8c2c9f7727cf879d38ace79369f948c6e 100644 (file)
@@ -438,7 +438,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
        u8 status;
 
        if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
-               u32 serror;
+               u32 serror = 0xffffffff;
 
                /* SIEN doesn't mask SATA IRQs on some 3112s.  Those
                 * controllers continue to assert IRQ as long as
index e18566a0fedd4c9f7492eab168ffed2bc8d36932..1c374579407c14316b35e8b9d7faff71077b18f6 100644 (file)
@@ -460,6 +460,21 @@ static int pm_genpd_runtime_resume(struct device *dev)
        return 0;
 }
 
+/**
+ * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
+ */
+void pm_genpd_poweroff_unused(void)
+{
+       struct generic_pm_domain *genpd;
+
+       mutex_lock(&gpd_list_lock);
+
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
+               genpd_queue_power_off_work(genpd);
+
+       mutex_unlock(&gpd_list_lock);
+}
+
 #else
 
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
@@ -1255,18 +1270,3 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        list_add(&genpd->gpd_list_node, &gpd_list);
        mutex_unlock(&gpd_list_lock);
 }
-
-/**
- * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
- */
-void pm_genpd_poweroff_unused(void)
-{
-       struct generic_pm_domain *genpd;
-
-       mutex_lock(&gpd_list_lock);
-
-       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
-               genpd_queue_power_off_work(genpd);
-
-       mutex_unlock(&gpd_list_lock);
-}
index c2231ff06cbcfebfe4a5ef6c0aee1ffa6ecc28fb..c4f7a45cd2c3386a95776081eab5350bb0034017 100644 (file)
@@ -113,3 +113,4 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
 }
 EXPORT_SYMBOL_GPL(regmap_init_i2c);
 
+MODULE_LICENSE("GPL");
index 4deba0621bc7f035b66ccc1ffc6821e580591f43..f8396945d6ed6339741ab0bd6db8dca9a985a587 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 static int regmap_spi_write(struct device *dev, const void *data, size_t count)
 {
@@ -70,3 +71,5 @@ struct regmap *regmap_init_spi(struct spi_device *spi,
        return regmap_init(&spi->dev, &regmap_spi, config);
 }
 EXPORT_SYMBOL_GPL(regmap_init_spi);
+
+MODULE_LICENSE("GPL");
index cf3565cae93d951ee7c77ddd7775e5aa878521b7..0eef4da1ac61f1deb274e56fb5601cfc6275c193 100644 (file)
@@ -317,7 +317,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                u8[0] |= map->bus->read_flag_mask;
 
        ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
-                            val, map->format.val_bytes);
+                            val, val_len);
        if (ret != 0)
                return ret;
 
index 717d6e4e18d3d08086fd2d5365574adbd613aef8..6f07ec1c2f58d2dabd766463165e32728910faf6 100644 (file)
@@ -256,6 +256,21 @@ config BLK_DEV_LOOP
 
          Most users will answer N here.
 
+config BLK_DEV_LOOP_MIN_COUNT
+       int "Number of loop devices to pre-create at init time"
+       depends on BLK_DEV_LOOP
+       default 8
+       help
+         Static number of loop devices to be unconditionally pre-created
+         at init time.
+
+         This default value can be overwritten on the kernel command
+         line or with module-parameter loop.max_loop.
+
+         The historic default is 8. If a late 2011 version of losetup(8)
+         is used, it can be set to 0, since needed loop devices can be
+         dynamically allocated with the /dev/loop-control interface.
+
 config BLK_DEV_CRYPTOLOOP
        tristate "Cryptoloop Support"
        select CRYPTO
@@ -471,7 +486,7 @@ config XEN_BLKDEV_FRONTEND
          in another domain which drives the actual block device.
 
 config XEN_BLKDEV_BACKEND
-       tristate "Block-device backend driver"
+       tristate "Xen block-device backend driver"
        depends on XEN_BACKEND
        help
          The block-device backend driver allows the kernel to export its
index 515bcd948a43d7ee04650a06044e7bea6bc4742c..0feab261e295b4c7ec75826066593f41bd44fc96 100644 (file)
@@ -1829,10 +1829,10 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n
 
        /* silently ignore cpu mask on UP kernel */
        if (nr_cpu_ids > 1 && sc.cpu_mask[0] != 0) {
-               err = __bitmap_parse(sc.cpu_mask, 32, 0,
+               err = bitmap_parse(sc.cpu_mask, 32,
                                cpumask_bits(new_cpu_mask), nr_cpu_ids);
                if (err) {
-                       dev_warn(DEV, "__bitmap_parse() failed with %d\n", err);
+                       dev_warn(DEV, "bitmap_parse() failed with %d\n", err);
                        retcode = ERR_CPU_MASK_PARSE;
                        goto fail;
                }
index 76c8da78212bffec71f5dc7af025a84e4028d456..4720c7ade0aed0dfd4fccce47ec7e1b39402587a 100644 (file)
 #include <linux/kthread.h>
 #include <linux/splice.h>
 #include <linux/sysfs.h>
-
+#include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 
-static LIST_HEAD(loop_devices);
-static DEFINE_MUTEX(loop_devices_mutex);
+static DEFINE_IDR(loop_index_idr);
+static DEFINE_MUTEX(loop_index_mutex);
 
 static int max_part;
 static int part_shift;
@@ -722,17 +722,10 @@ static inline int is_loop_device(struct file *file)
 static ssize_t loop_attr_show(struct device *dev, char *page,
                              ssize_t (*callback)(struct loop_device *, char *))
 {
-       struct loop_device *l, *lo = NULL;
-
-       mutex_lock(&loop_devices_mutex);
-       list_for_each_entry(l, &loop_devices, lo_list)
-               if (disk_to_dev(l->lo_disk) == dev) {
-                       lo = l;
-                       break;
-               }
-       mutex_unlock(&loop_devices_mutex);
+       struct gendisk *disk = dev_to_disk(dev);
+       struct loop_device *lo = disk->private_data;
 
-       return lo ? callback(lo, page) : -EIO;
+       return callback(lo, page);
 }
 
 #define LOOP_ATTR_RO(_name)                                            \
@@ -750,10 +743,10 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf)
        ssize_t ret;
        char *p = NULL;
 
-       mutex_lock(&lo->lo_ctl_mutex);
+       spin_lock_irq(&lo->lo_lock);
        if (lo->lo_backing_file)
                p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
-       mutex_unlock(&lo->lo_ctl_mutex);
+       spin_unlock_irq(&lo->lo_lock);
 
        if (IS_ERR_OR_NULL(p))
                ret = PTR_ERR(p);
@@ -1007,7 +1000,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
 
        kthread_stop(lo->lo_thread);
 
+       spin_lock_irq(&lo->lo_lock);
        lo->lo_backing_file = NULL;
+       spin_unlock_irq(&lo->lo_lock);
 
        loop_release_xfer(lo);
        lo->transfer = NULL;
@@ -1485,13 +1480,22 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
 
 static int lo_open(struct block_device *bdev, fmode_t mode)
 {
-       struct loop_device *lo = bdev->bd_disk->private_data;
+       struct loop_device *lo;
+       int err = 0;
+
+       mutex_lock(&loop_index_mutex);
+       lo = bdev->bd_disk->private_data;
+       if (!lo) {
+               err = -ENXIO;
+               goto out;
+       }
 
        mutex_lock(&lo->lo_ctl_mutex);
        lo->lo_refcnt++;
        mutex_unlock(&lo->lo_ctl_mutex);
-
-       return 0;
+out:
+       mutex_unlock(&loop_index_mutex);
+       return err;
 }
 
 static int lo_release(struct gendisk *disk, fmode_t mode)
@@ -1557,40 +1561,71 @@ int loop_register_transfer(struct loop_func_table *funcs)
        return 0;
 }
 
+static int unregister_transfer_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
+       struct loop_func_table *xfer = data;
+
+       mutex_lock(&lo->lo_ctl_mutex);
+       if (lo->lo_encryption == xfer)
+               loop_release_xfer(lo);
+       mutex_unlock(&lo->lo_ctl_mutex);
+       return 0;
+}
+
 int loop_unregister_transfer(int number)
 {
        unsigned int n = number;
-       struct loop_device *lo;
        struct loop_func_table *xfer;
 
        if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
                return -EINVAL;
 
        xfer_funcs[n] = NULL;
-
-       list_for_each_entry(lo, &loop_devices, lo_list) {
-               mutex_lock(&lo->lo_ctl_mutex);
-
-               if (lo->lo_encryption == xfer)
-                       loop_release_xfer(lo);
-
-               mutex_unlock(&lo->lo_ctl_mutex);
-       }
-
+       idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer);
        return 0;
 }
 
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static struct loop_device *loop_alloc(int i)
+static int loop_add(struct loop_device **l, int i)
 {
        struct loop_device *lo;
        struct gendisk *disk;
+       int err;
 
        lo = kzalloc(sizeof(*lo), GFP_KERNEL);
-       if (!lo)
+       if (!lo) {
+               err = -ENOMEM;
                goto out;
+       }
+
+       err = idr_pre_get(&loop_index_idr, GFP_KERNEL);
+       if (err < 0)
+               goto out_free_dev;
+
+       if (i >= 0) {
+               int m;
+
+               /* create specific i in the index */
+               err = idr_get_new_above(&loop_index_idr, lo, i, &m);
+               if (err >= 0 && i != m) {
+                       idr_remove(&loop_index_idr, m);
+                       err = -EEXIST;
+               }
+       } else if (i == -1) {
+               int m;
+
+               /* get next free nr */
+               err = idr_get_new(&loop_index_idr, lo, &m);
+               if (err >= 0)
+                       i = m;
+       } else {
+               err = -EINVAL;
+       }
+       if (err < 0)
+               goto out_free_dev;
 
        lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
        if (!lo->lo_queue)
@@ -1611,81 +1646,158 @@ static struct loop_device *loop_alloc(int i)
        disk->private_data      = lo;
        disk->queue             = lo->lo_queue;
        sprintf(disk->disk_name, "loop%d", i);
-       return lo;
+       add_disk(disk);
+       *l = lo;
+       return lo->lo_number;
 
 out_free_queue:
        blk_cleanup_queue(lo->lo_queue);
 out_free_dev:
        kfree(lo);
 out:
-       return NULL;
+       return err;
 }
 
-static void loop_free(struct loop_device *lo)
+static void loop_remove(struct loop_device *lo)
 {
+       del_gendisk(lo->lo_disk);
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
-       list_del(&lo->lo_list);
        kfree(lo);
 }
 
-static struct loop_device *loop_init_one(int i)
+static int find_free_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
+       struct loop_device **l = data;
+
+       if (lo->lo_state == Lo_unbound) {
+               *l = lo;
+               return 1;
+       }
+       return 0;
+}
+
+static int loop_lookup(struct loop_device **l, int i)
 {
        struct loop_device *lo;
+       int ret = -ENODEV;
 
-       list_for_each_entry(lo, &loop_devices, lo_list) {
-               if (lo->lo_number == i)
-                       return lo;
+       if (i < 0) {
+               int err;
+
+               err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
+               if (err == 1) {
+                       *l = lo;
+                       ret = lo->lo_number;
+               }
+               goto out;
        }
 
-       lo = loop_alloc(i);
+       /* lookup and return a specific i */
+       lo = idr_find(&loop_index_idr, i);
        if (lo) {
-               add_disk(lo->lo_disk);
-               list_add_tail(&lo->lo_list, &loop_devices);
+               *l = lo;
+               ret = lo->lo_number;
        }
-       return lo;
-}
-
-static void loop_del_one(struct loop_device *lo)
-{
-       del_gendisk(lo->lo_disk);
-       loop_free(lo);
+out:
+       return ret;
 }
 
 static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 {
        struct loop_device *lo;
        struct kobject *kobj;
+       int err;
 
-       mutex_lock(&loop_devices_mutex);
-       lo = loop_init_one(MINOR(dev) >> part_shift);
-       kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM);
-       mutex_unlock(&loop_devices_mutex);
+       mutex_lock(&loop_index_mutex);
+       err = loop_lookup(&lo, MINOR(dev) >> part_shift);
+       if (err < 0)
+               err = loop_add(&lo, MINOR(dev) >> part_shift);
+       if (err < 0)
+               kobj = ERR_PTR(err);
+       else
+               kobj = get_disk(lo->lo_disk);
+       mutex_unlock(&loop_index_mutex);
 
        *part = 0;
        return kobj;
 }
 
+static long loop_control_ioctl(struct file *file, unsigned int cmd,
+                              unsigned long parm)
+{
+       struct loop_device *lo;
+       int ret = -ENOSYS;
+
+       mutex_lock(&loop_index_mutex);
+       switch (cmd) {
+       case LOOP_CTL_ADD:
+               ret = loop_lookup(&lo, parm);
+               if (ret >= 0) {
+                       ret = -EEXIST;
+                       break;
+               }
+               ret = loop_add(&lo, parm);
+               break;
+       case LOOP_CTL_REMOVE:
+               ret = loop_lookup(&lo, parm);
+               if (ret < 0)
+                       break;
+               mutex_lock(&lo->lo_ctl_mutex);
+               if (lo->lo_state != Lo_unbound) {
+                       ret = -EBUSY;
+                       mutex_unlock(&lo->lo_ctl_mutex);
+                       break;
+               }
+               if (lo->lo_refcnt > 0) {
+                       ret = -EBUSY;
+                       mutex_unlock(&lo->lo_ctl_mutex);
+                       break;
+               }
+               lo->lo_disk->private_data = NULL;
+               mutex_unlock(&lo->lo_ctl_mutex);
+               idr_remove(&loop_index_idr, lo->lo_number);
+               loop_remove(lo);
+               break;
+       case LOOP_CTL_GET_FREE:
+               ret = loop_lookup(&lo, -1);
+               if (ret >= 0)
+                       break;
+               ret = loop_add(&lo, -1);
+       }
+       mutex_unlock(&loop_index_mutex);
+
+       return ret;
+}
+
+static const struct file_operations loop_ctl_fops = {
+       .open           = nonseekable_open,
+       .unlocked_ioctl = loop_control_ioctl,
+       .compat_ioctl   = loop_control_ioctl,
+       .owner          = THIS_MODULE,
+       .llseek         = noop_llseek,
+};
+
+static struct miscdevice loop_misc = {
+       .minor          = LOOP_CTRL_MINOR,
+       .name           = "loop-control",
+       .fops           = &loop_ctl_fops,
+};
+
+MODULE_ALIAS_MISCDEV(LOOP_CTRL_MINOR);
+MODULE_ALIAS("devname:loop-control");
+
 static int __init loop_init(void)
 {
        int i, nr;
        unsigned long range;
-       struct loop_device *lo, *next;
+       struct loop_device *lo;
+       int err;
 
-       /*
-        * loop module now has a feature to instantiate underlying device
-        * structure on-demand, provided that there is an access dev node.
-        * However, this will not work well with user space tool that doesn't
-        * know about such "feature".  In order to not break any existing
-        * tool, we do the following:
-        *
-        * (1) if max_loop is specified, create that many upfront, and this
-        *     also becomes a hard limit.
-        * (2) if max_loop is not specified, create 8 loop device on module
-        *     load, user can further extend loop device by create dev node
-        *     themselves and have kernel automatically instantiate actual
-        *     device on-demand.
-        */
+       err = misc_register(&loop_misc);
+       if (err < 0)
+               return err;
 
        part_shift = 0;
        if (max_part > 0) {
@@ -1708,57 +1820,60 @@ static int __init loop_init(void)
        if (max_loop > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
+       /*
+        * If max_loop is specified, create that many devices upfront.
+        * This also becomes a hard limit. If max_loop is not specified,
+        * create CONFIG_BLK_DEV_LOOP_MIN_COUNT loop devices at module
+        * init time. Loop devices can be requested on-demand with the
+        * /dev/loop-control interface, or be instantiated by accessing
+        * a 'dead' device node.
+        */
        if (max_loop) {
                nr = max_loop;
                range = max_loop << part_shift;
        } else {
-               nr = 8;
+               nr = CONFIG_BLK_DEV_LOOP_MIN_COUNT;
                range = 1UL << MINORBITS;
        }
 
        if (register_blkdev(LOOP_MAJOR, "loop"))
                return -EIO;
 
-       for (i = 0; i < nr; i++) {
-               lo = loop_alloc(i);
-               if (!lo)
-                       goto Enomem;
-               list_add_tail(&lo->lo_list, &loop_devices);
-       }
-
-       /* point of no return */
-
-       list_for_each_entry(lo, &loop_devices, lo_list)
-               add_disk(lo->lo_disk);
-
        blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
                                  THIS_MODULE, loop_probe, NULL, NULL);
 
+       /* pre-create number of devices given by config or max_loop */
+       mutex_lock(&loop_index_mutex);
+       for (i = 0; i < nr; i++)
+               loop_add(&lo, i);
+       mutex_unlock(&loop_index_mutex);
+
        printk(KERN_INFO "loop: module loaded\n");
        return 0;
+}
 
-Enomem:
-       printk(KERN_INFO "loop: out of memory\n");
-
-       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
-               loop_free(lo);
+static int loop_exit_cb(int id, void *ptr, void *data)
+{
+       struct loop_device *lo = ptr;
 
-       unregister_blkdev(LOOP_MAJOR, "loop");
-       return -ENOMEM;
+       loop_remove(lo);
+       return 0;
 }
 
 static void __exit loop_exit(void)
 {
        unsigned long range;
-       struct loop_device *lo, *next;
 
        range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
 
-       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
-               loop_del_one(lo);
+       idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
+       idr_remove_all(&loop_index_idr);
+       idr_destroy(&loop_index_idr);
 
        blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
        unregister_blkdev(LOOP_MAJOR, "loop");
+
+       misc_deregister(&loop_misc);
 }
 
 module_init(loop_init);
index 773bfa7927775396f80c004b4d6551c485efe4c6..ae3e167e17adc3f18bc4b14fe3b1635d299bfb3e 100644 (file)
@@ -1184,6 +1184,7 @@ static struct of_device_id swim3_match[] =
        {
        .compatible     = "swim3"
        },
+       { /* end of list */ }
 };
 
 static struct macio_driver swim3_driver =
index b536a9cef917516d23448e589a7955ad984e6dd3..9ea8c2576c70e768f22ad8ea2cc423337611fb4f 100644 (file)
@@ -123,8 +123,8 @@ static DEFINE_SPINLOCK(minor_lock);
 #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
 #define EMULATED_HD_DISK_MINOR_OFFSET (0)
 #define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256)
-#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16))
-#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4)
+#define EMULATED_SD_DISK_MINOR_OFFSET (0)
+#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_SD_DISK_MINOR_OFFSET / 256)
 
 #define DEV_NAME       "xvd"   /* name in /dev */
 
@@ -529,7 +529,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
                minor = BLKIF_MINOR_EXT(info->vdevice);
                nr_parts = PARTS_PER_EXT_DISK;
                offset = minor / nr_parts;
-               if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4)
+               if (xen_hvm_domain() && offset < EMULATED_HD_DISK_NAME_OFFSET + 4)
                        printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with "
                                        "emulated IDE disks,\n\t choose an xvd device name"
                                        "from xvde on\n", info->vdevice);
index 75fb965b8f72b1e9fa2a8001f7fb16fb12388d5c..f997c27d79e299579975badce89975aefc9f941a 100644 (file)
@@ -1929,11 +1929,17 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
                goto out;
 
        s->manufact.len = buf[0] << 8 | buf[1];
-       if (s->manufact.len < 0 || s->manufact.len > 2048) {
+       if (s->manufact.len < 0) {
                cdinfo(CD_WARNING, "Received invalid manufacture info length"
                                   " (%d)\n", s->manufact.len);
                ret = -EIO;
        } else {
+               if (s->manufact.len > 2048) {
+                       cdinfo(CD_WARNING, "Received invalid manufacture info "
+                                       "length (%d): truncating to 2048\n",
+                                       s->manufact.len);
+                       s->manufact.len = 2048;
+               }
                memcpy(s->manufact.value, &buf[4], s->manufact.len);
        }
 
index 04f1e7ce02b196868d42253243d79d1044d9b7cc..f6cf448d69b4f468160e19fc29fab0ea473f04b8 100644 (file)
@@ -1670,7 +1670,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
        char *type, *optype, *err, *msg;
        unsigned long error = m->status & 0x1ff0000l;
        u32 optypenum = (m->status >> 4) & 0x07;
-       u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+       u32 core_err_cnt = (m->status >> 38) & 0x7fff;
        u32 dimm = (m->misc >> 16) & 0x3;
        u32 channel = (m->misc >> 18) & 0x3;
        u32 syndrome = m->misc >> 32;
index e6ad3bb6c1a6b5efad00df79995f733be9a9c1f7..4799393247c8ada8a626722e0bea57c0ae99409e 100644 (file)
@@ -216,15 +216,33 @@ struct inbound_phy_packet_event {
        struct fw_cdev_event_phy_packet phy_packet;
 };
 
-static inline void __user *u64_to_uptr(__u64 value)
+#ifdef CONFIG_COMPAT
+static void __user *u64_to_uptr(u64 value)
+{
+       if (is_compat_task())
+               return compat_ptr(value);
+       else
+               return (void __user *)(unsigned long)value;
+}
+
+static u64 uptr_to_u64(void __user *ptr)
+{
+       if (is_compat_task())
+               return ptr_to_compat(ptr);
+       else
+               return (u64)(unsigned long)ptr;
+}
+#else
+static inline void __user *u64_to_uptr(u64 value)
 {
        return (void __user *)(unsigned long)value;
 }
 
-static inline __u64 uptr_to_u64(void __user *ptr)
+static inline u64 uptr_to_u64(void __user *ptr)
 {
-       return (__u64)(unsigned long)ptr;
+       return (u64)(unsigned long)ptr;
 }
+#endif /* CONFIG_COMPAT */
 
 static int fw_device_op_open(struct inode *inode, struct file *file)
 {
index 8ba7f7928f1f1dcd4fcedd33305277064bc8999b..f3b890da1e874b832b6dbab7dd919d94567955cf 100644 (file)
@@ -455,15 +455,20 @@ static struct device_attribute fw_device_attributes[] = {
 static int read_rom(struct fw_device *device,
                    int generation, int index, u32 *data)
 {
-       int rcode;
+       u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4;
+       int i, rcode;
 
        /* device->node_id, accessed below, must not be older than generation */
        smp_rmb();
 
-       rcode = fw_run_transaction(device->card, TCODE_READ_QUADLET_REQUEST,
-                       device->node_id, generation, device->max_speed,
-                       (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4,
-                       data, 4);
+       for (i = 10; i < 100; i += 10) {
+               rcode = fw_run_transaction(device->card,
+                               TCODE_READ_QUADLET_REQUEST, device->node_id,
+                               generation, device->max_speed, offset, data, 4);
+               if (rcode != RCODE_BUSY)
+                       break;
+               msleep(i);
+       }
        be32_to_cpus(data);
 
        return rcode;
index bcf792fac442576181f00596a018cf22a0dd67aa..57cd3a406edf3930954a2c18938ab8e4796ffa16 100644 (file)
@@ -2179,8 +2179,13 @@ static int ohci_enable(struct fw_card *card,
                        ohci_driver_name, ohci)) {
                fw_error("Failed to allocate interrupt %d.\n", dev->irq);
                pci_disable_msi(dev);
-               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-                                 ohci->config_rom, ohci->config_rom_bus);
+
+               if (config_rom) {
+                       dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                         ohci->next_config_rom,
+                                         ohci->next_config_rom_bus);
+                       ohci->next_config_rom = NULL;
+               }
                return -EIO;
        }
 
index a8ab6263e0d75b357d1643a5e009de6e59494307..3c395a59da3539ac2975ba6fac1e2873f13873bd 100644 (file)
@@ -499,7 +499,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
        for (i = 0; i < I915_NUM_RINGS; i++) {
-               if (IS_GEN6(dev)) {
+               if (IS_GEN6(dev) || IS_GEN7(dev)) {
                        seq_printf(m, "Graphics Interrupt mask (%s):    %08x\n",
                                   dev_priv->ring[i].name,
                                   I915_READ_IMR(&dev_priv->ring[i]));
index feb4f164fd1b35264b6673201d68e0f22494f025..7916bd97d5c131314baa113d08a47d566d2a3fb4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <drm/intel-gtt.h>
+#include <linux/backlight.h>
 
 /* General customization:
  */
@@ -690,6 +691,7 @@ typedef struct drm_i915_private {
        int child_dev_num;
        struct child_device_config *child_dev;
        struct drm_connector *int_lvds_connector;
+       struct drm_connector *int_edp_connector;
 
        bool mchbar_need_disable;
 
@@ -723,6 +725,8 @@ typedef struct drm_i915_private {
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 
+       struct backlight_device *backlight;
+
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
index 02f96fd0d52dbea419cf575184196de2bbe66eb0..9cbb0cd8f46ae8ffc4e60a2fb90dde7867e112a3 100644 (file)
@@ -2058,8 +2058,10 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
 
-
-       dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       else
+               dev->driver->get_vblank_timestamp = NULL;
        dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
 
        if (IS_IVYBRIDGE(dev)) {
index d1331f771e2f2f863677cc69bcc11a06d3af0ae4..542453f7498c83e3b58b390254d815247e209da2 100644 (file)
 # define MI_FLUSH_ENABLE                               (1 << 11)
 
 #define GFX_MODE       0x02520
+#define GFX_MODE_GEN7  0x0229c
 #define   GFX_RUN_LIST_ENABLE          (1<<15)
 #define   GFX_TLB_INVALIDATE_ALWAYS    (1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE     (1<<12)
 #define   GFX_PSMI_GRANULARITY         (1<<10)
 #define   GFX_PPGTT_ENABLE             (1<<9)
 
+#define GFX_MODE_ENABLE(bit) (((bit) << 16) | (bit))
+#define GFX_MODE_DISABLE(bit) (((bit) << 16) | (0))
+
 #define SCPD0          0x0209c /* 915+ only */
 #define IER            0x020a0
 #define IIR            0x020a4
 #define   ADPA_PIPE_SELECT_MASK        (1<<30)
 #define   ADPA_PIPE_A_SELECT   0
 #define   ADPA_PIPE_B_SELECT   (1<<30)
+#define   ADPA_PIPE_SELECT(pipe) ((pipe) << 30)
 #define   ADPA_USE_VGA_HVPOLARITY (1<<15)
 #define   ADPA_SETS_HVPOLARITY 0
 #define   ADPA_VSYNC_CNTL_DISABLE (1<<11)
 /* Selects pipe B for LVDS data.  Must be set on pre-965. */
 #define   LVDS_PIPEB_SELECT            (1 << 30)
 #define   LVDS_PIPE_MASK               (1 << 30)
+#define   LVDS_PIPE(pipe)              ((pipe) << 30)
 /* LVDS dithering flag on 965/g4x platform */
 #define   LVDS_ENABLE_DITHER           (1 << 25)
 /* LVDS sync polarity flags. Set to invert (i.e. negative) */
 #define   LVDS_B0B3_POWER_DOWN         (0 << 2)
 #define   LVDS_B0B3_POWER_UP           (3 << 2)
 
-#define LVDS_PIPE_ENABLED(V, P) \
-       (((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))
-
 /* Video Data Island Packet control */
 #define VIDEO_DIP_DATA         0x61178
 #define VIDEO_DIP_CTL          0x61170
 #define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
 #define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
 
-#define ADPA_PIPE_ENABLED(V, P) \
-       (((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))
-
 /* or SDVOB */
 #define HDMIB   0xe1140
 #define  PORT_ENABLE    (1 << 31)
 #define  TRANSCODER_A   (0)
 #define  TRANSCODER_B   (1 << 30)
+#define  TRANSCODER(pipe)      ((pipe) << 30)
 #define  TRANSCODER_MASK   (1 << 30)
 #define  COLOR_FORMAT_8bpc      (0)
 #define  COLOR_FORMAT_12bpc     (3 << 26)
 #define  HSYNC_ACTIVE_HIGH      (1 << 3)
 #define  PORT_DETECTED          (1 << 2)
 
-#define HDMI_PIPE_ENABLED(V, P) \
-       (((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))
-
 /* PCH SDVOB multiplex with HDMIB */
 #define PCH_SDVOB      HDMIB
 
 #define  PORT_TRANS_B_SEL_CPT  (1<<29)
 #define  PORT_TRANS_C_SEL_CPT  (2<<29)
 #define  PORT_TRANS_SEL_MASK   (3<<29)
+#define  PORT_TRANS_SEL_CPT(pipe)      ((pipe) << 29)
 
 #define TRANS_DP_CTL_A         0xe0300
 #define TRANS_DP_CTL_B         0xe1300
index 87677d60d0df21758b9a70c51e5f23388e21a5e6..f10742359ec9a1f6d6f03ec248cefcd78a85254a 100644 (file)
@@ -871,7 +871,8 @@ int i915_restore_state(struct drm_device *dev)
        }
        mutex_unlock(&dev->struct_mutex);
 
-       intel_init_clock_gating(dev);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
index 35364e68a09127528b1d6d6f18bae3e331d78b85..ee1d701317f7a14fa4857c0fdf5ad993244a989a 100644 (file)
@@ -980,8 +980,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
             pipe_name(pipe));
 }
 
-static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
-                           int reg, u32 port_sel, u32 val)
+static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
+                           enum pipe pipe, u32 port_sel, u32 val)
 {
        if ((val & DP_PORT_EN) == 0)
                return false;
@@ -998,11 +998,58 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
        return true;
 }
 
+static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & PORT_ENABLE) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & LVDS_PORT_EN) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & ADPA_DAC_ENABLE) == 0)
+               return false;
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
+                       return false;
+       }
+       return true;
+}
+
 static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
                                   enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val),
+       WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -1011,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
                                     enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       WARN(HDMI_PIPE_ENABLED(val, pipe),
+       WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -1028,13 +1075,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       WARN(ADPA_PIPE_ENABLED(val, pipe),
+       WARN(adpa_pipe_enabled(dev_priv, val, pipe),
             "PCH VGA enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       WARN(LVDS_PIPE_ENABLED(val, pipe),
+       WARN(lvds_pipe_enabled(dev_priv, val, pipe),
             "PCH LVDS enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
@@ -1360,7 +1407,7 @@ static void disable_pch_dp(struct drm_i915_private *dev_priv,
                           enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) {
+       if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
                DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
                I915_WRITE(reg, val & ~DP_PORT_EN);
        }
@@ -1370,7 +1417,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
                             enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       if (HDMI_PIPE_ENABLED(val, pipe)) {
+       if (hdmi_pipe_enabled(dev_priv, val, pipe)) {
                DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
                              reg, pipe);
                I915_WRITE(reg, val & ~PORT_ENABLE);
@@ -1392,12 +1439,13 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       if (ADPA_PIPE_ENABLED(val, pipe))
+       if (adpa_pipe_enabled(dev_priv, val, pipe))
                I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       if (LVDS_PIPE_ENABLED(val, pipe)) {
+       if (lvds_pipe_enabled(dev_priv, val, pipe)) {
+               DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
                I915_WRITE(reg, val & ~LVDS_PORT_EN);
                POSTING_READ(reg);
                udelay(100);
@@ -5049,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static void ironlake_update_pch_refclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_encoder *has_edp_encoder = NULL;
+       u32 temp;
+       bool has_lvds = false;
+
+       /* We need to take the global config into account */
+       list_for_each_entry(crtc, &mode_config->crtc_list, head) {
+               if (!crtc->enabled)
+                       continue;
+
+               list_for_each_entry(encoder, &mode_config->encoder_list,
+                                   base.head) {
+                       if (encoder->base.crtc != crtc)
+                               continue;
+
+                       switch (encoder->type) {
+                       case INTEL_OUTPUT_LVDS:
+                               has_lvds = true;
+                       case INTEL_OUTPUT_EDP:
+                               has_edp_encoder = encoder;
+                               break;
+                       }
+               }
+       }
+
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+       temp &= ~DREF_SSC_SOURCE_MASK;
+       temp |= DREF_SSC_SOURCE_ENABLE;
+       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+       POSTING_READ(PCH_DREF_CONTROL);
+       udelay(200);
+
+       if (has_edp_encoder) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       temp |= DREF_SSC1_ENABLE;
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
+               }
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Enable CPU source on CPU attached eDP */
+               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       if (intel_panel_use_ssc(dev_priv))
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else {
+                       /* Enable SSC on PCH eDP if needed */
+                       if (intel_panel_use_ssc(dev_priv)) {
+                               DRM_ERROR("enabling SSC on PCH\n");
+                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                       }
+               }
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
+}
+
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode,
@@ -5244,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
                             &m_n);
 
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       temp = I915_READ(PCH_DREF_CONTROL);
-       /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-       temp &= ~DREF_SSC_SOURCE_MASK;
-       temp |= DREF_SSC_SOURCE_ENABLE;
-       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-       POSTING_READ(PCH_DREF_CONTROL);
-       udelay(200);
-
-       if (has_edp_encoder) {
-               if (intel_panel_use_ssc(dev_priv)) {
-                       temp |= DREF_SSC1_ENABLE;
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
-               }
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-               /* Enable CPU source on CPU attached eDP */
-               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       if (intel_panel_use_ssc(dev_priv))
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                       else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-               } else {
-                       /* Enable SSC on PCH eDP if needed */
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               DRM_ERROR("enabling SSC on PCH\n");
-                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                       }
-               }
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-       }
+       ironlake_update_pch_refclk(dev);
 
        fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
        if (has_reduced_clock)
index 0feae908bb37f7bc8cbc642ea12f96a6cabf467a..44fef5e1c4906d49547d79fc42296163eea71905 100644 (file)
@@ -1841,6 +1841,11 @@ done:
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
+       struct drm_device *dev = connector->dev;
+
+       if (intel_dpd_is_edp(dev))
+               intel_panel_destroy_backlight(dev);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
        kfree(connector);
@@ -2072,6 +2077,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                                        DRM_MODE_TYPE_PREFERRED;
                        }
                }
+               dev_priv->int_edp_connector = connector;
+               intel_panel_setup_backlight(dev);
        }
 
        intel_dp_add_properties(intel_dp, connector);
index 7b330e76a435afa32ba126d7a7837bb816ceb589..0b2ee9d39980c14df3c22dd37d9328004d9317fe 100644 (file)
@@ -297,9 +297,10 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
-extern void intel_panel_setup_backlight(struct drm_device *dev);
+extern int intel_panel_setup_backlight(struct drm_device *dev);
 extern void intel_panel_enable_backlight(struct drm_device *dev);
 extern void intel_panel_disable_backlight(struct drm_device *dev);
+extern void intel_panel_destroy_backlight(struct drm_device *dev);
 extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
 
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
index 2e8ddfcba40c8c7d751776fb4d0b6818189b9c7e..31da77f5c051b816f705618a950ea9dfe3d50ee9 100644 (file)
@@ -72,14 +72,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
@@ -94,17 +96,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
                DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
                              intel_lvds->pfit_control,
                              intel_lvds->pfit_pgm_ratios);
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-               } else {
-                       I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
-                       I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
-                       intel_lvds->pfit_dirty = false;
-               }
+
+               I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+               I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+               intel_lvds->pfit_dirty = false;
        }
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
        POSTING_READ(lvds_reg);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power on\n");
 
        intel_panel_enable_backlight(dev);
 }
@@ -113,24 +114,25 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        intel_panel_disable_backlight(dev);
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
 
        if (intel_lvds->pfit_control) {
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-
                I915_WRITE(PFIT_CONTROL, 0);
                intel_lvds->pfit_dirty = true;
        }
@@ -398,53 +400,21 @@ out:
 
 static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* We try to do the minimum that is necessary in order to unlock
-        * the registers for mode setting.
-        *
-        * On Ironlake, this is quite simple as we just set the unlock key
-        * and ignore all subtleties. (This may cause some issues...)
-        *
+       /*
         * Prior to Ironlake, we must disable the pipe if we want to adjust
         * the panel fitter. However at all other times we can just reset
         * the registers regardless.
         */
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_CONTROL,
-                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
-       } else if (intel_lvds->pfit_dirty) {
-               I915_WRITE(PP_CONTROL,
-                          (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
-                          & ~POWER_TARGET_ON);
-       } else {
-               I915_WRITE(PP_CONTROL,
-                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
-       }
+       if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty)
+               intel_lvds_disable(intel_lvds);
 }
 
 static void intel_lvds_commit(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* Undo any unlocking done in prepare to prevent accidental
-        * adjustment of the registers.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               u32 val = I915_READ(PCH_PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PCH_PP_CONTROL, val & 0x3);
-       } else {
-               u32 val = I915_READ(PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PP_CONTROL, val & 0x3);
-       }
-
        /* Always do a full power on as we do not know what state
         * we were left in.
         */
@@ -582,6 +552,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       intel_panel_destroy_backlight(dev);
+
        if (dev_priv->lid_notifier.notifier_call)
                acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
        drm_sysfs_connector_remove(connector);
@@ -1040,6 +1012,19 @@ out:
                pwm = I915_READ(BLC_PWM_PCH_CTL1);
                pwm |= PWM_PCH_ENABLE;
                I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else {
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
        }
        dev_priv->lid_notifier.notifier_call = intel_lid_notify;
        if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
@@ -1049,6 +1034,9 @@ out:
        /* keep the LVDS connector */
        dev_priv->int_lvds_connector = connector;
        drm_sysfs_connector_add(connector);
+
+       intel_panel_setup_backlight(dev);
+
        return true;
 
 failed:
index b7c5ddb564d144e43bdeac2727172a1bc6492bc5..b8e8158bb16e8cb9060718d3325bc6d549f4ace9 100644 (file)
@@ -227,7 +227,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
        asle->aslc = asle_stat;
 }
 
-/* Only present on Ironlake+ */
 void intel_opregion_gse_intr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index 05f500cd9c246c0156412e028f5bef0c35acd22b..a9e0c7bcd3179a2d76a1725315735550c8cd3800 100644 (file)
@@ -277,7 +277,7 @@ void intel_panel_enable_backlight(struct drm_device *dev)
        dev_priv->backlight_enabled = true;
 }
 
-void intel_panel_setup_backlight(struct drm_device *dev)
+static void intel_panel_init_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -309,3 +309,73 @@ intel_panel_detect(struct drm_device *dev)
 
        return connector_status_unknown;
 }
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_panel_update_status(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       intel_panel_set_backlight(dev, bd->props.brightness);
+       return 0;
+}
+
+static int intel_panel_get_brightness(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       return intel_panel_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_panel_bl_ops = {
+       .update_status = intel_panel_update_status,
+       .get_brightness = intel_panel_get_brightness,
+};
+
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct backlight_properties props;
+       struct drm_connector *connector;
+
+       intel_panel_init_backlight(dev);
+
+       if (dev_priv->int_lvds_connector)
+               connector = dev_priv->int_lvds_connector;
+       else if (dev_priv->int_edp_connector)
+               connector = dev_priv->int_edp_connector;
+       else
+               return -ENODEV;
+
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = intel_panel_get_max_backlight(dev);
+       dev_priv->backlight =
+               backlight_device_register("intel_backlight",
+                                         &connector->kdev, dev,
+                                         &intel_panel_bl_ops, &props);
+
+       if (IS_ERR(dev_priv->backlight)) {
+               DRM_ERROR("Failed to register backlight: %ld\n",
+                         PTR_ERR(dev_priv->backlight));
+               dev_priv->backlight = NULL;
+               return -ENODEV;
+       }
+       dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (dev_priv->backlight)
+               backlight_device_unregister(dev_priv->backlight);
+}
+#else
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       intel_panel_init_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       return;
+}
+#endif
index 47b9b277703856e6b1f3d76d81ce70be25f3d296..c30626ea9f93a5319f95fb0ef631178b666c2e87 100644 (file)
@@ -290,6 +290,10 @@ static int init_render_ring(struct intel_ring_buffer *ring)
                if (IS_GEN6(dev) || IS_GEN7(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
                I915_WRITE(MI_MODE, mode);
+               if (IS_GEN7(dev))
+                       I915_WRITE(GFX_MODE_GEN7,
+                                  GFX_MODE_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
+                                  GFX_MODE_ENABLE(GFX_REPLAY_MODE));
        }
 
        if (INTEL_INFO(dev)->gen >= 6) {
index 645b84b3d203395b59f35d6a545c0ca488aaedf9..7ad43c6b1db765261e4b81466a9145c48d441834 100644 (file)
@@ -613,6 +613,18 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
        return true;
 }
 
+bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
+{
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
+       if (!radeon_dp_get_link_status(radeon_connector, link_status))
+               return false;
+       if (dp_channel_eq_ok(link_status, dig->dp_lane_count))
+               return false;
+       return true;
+}
+
 struct radeon_dp_link_train_info {
        struct radeon_device *rdev;
        struct drm_encoder *encoder;
index 14dce9f221721128b008e1988b50ac51788ef4de..fb5fa089886829fdf3fe3ecb262e5971aa4f814f 100644 (file)
@@ -743,7 +743,7 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
                    !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
                    !evergreen_check_latency_hiding(&wm) ||
                    (rdev->disp_priority == 2)) {
-                       DRM_INFO("force priority to high\n");
+                       DRM_DEBUG_KMS("force priority to high\n");
                        priority_a_cnt |= PRIORITY_ALWAYS_ON;
                        priority_b_cnt |= PRIORITY_ALWAYS_ON;
                }
index 6d6b5f16bc09461af70ea4eefcd1046999b113aa..7f65940f918f9a093002eb68e5b2c2f22722a486 100644 (file)
@@ -60,18 +60,20 @@ void radeon_connector_hotplug(struct drm_connector *connector)
 
        radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 
-       /* powering up/down the eDP panel generates hpd events which
-        * can interfere with modesetting.
-        */
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+       /* if the connector is already off, don't turn it back on */
+       if (connector->dpms != DRM_MODE_DPMS_ON)
                return;
 
-       /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
-       if (rdev->family >= CHIP_R600) {
-               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+       /* just deal with DP (not eDP) here. */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               int saved_dpms = connector->dpms;
+
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+                   radeon_dp_needs_link_train(radeon_connector))
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                else
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               connector->dpms = saved_dpms;
        }
 }
 
@@ -474,11 +476,19 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+       struct drm_display_mode *t, *mode;
+
+       /* If the EDID preferred mode doesn't match the native mode, use it */
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
+               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       if (mode->hdisplay != native_mode->hdisplay ||
+                           mode->vdisplay != native_mode->vdisplay)
+                               memcpy(native_mode, mode, sizeof(*mode));
+               }
+       }
 
        /* Try to get native mode details from EDID if necessary */
        if (!native_mode->clock) {
-               struct drm_display_mode *t, *mode;
-
                list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
                        if (mode->hdisplay == native_mode->hdisplay &&
                            mode->vdisplay == native_mode->vdisplay) {
@@ -489,6 +499,7 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
                        }
                }
        }
+
        if (!native_mode->clock) {
                DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
                radeon_encoder->rmx_type = RMX_OFF;
index 440e6ecccc40054c5620e38db033da76ee3dd3aa..a3b011b494650fcd2786f0db4be6da79952c3491 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/radeon_drm.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/efi.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "atom.h"
@@ -348,6 +349,9 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
+       if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+               return false;
+
        /* first check CRTCs */
        if (ASIC_IS_DCE41(rdev)) {
                reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
index b293487e5aa3dc2193fee36eb0f9c00fe7080a0c..319d85d7e759b4f0599f2c5df2b9182568bd993d 100644 (file)
@@ -2323,6 +2323,9 @@ radeon_add_atom_encoder(struct drm_device *dev,
        default:
                encoder->possible_crtcs = 0x3;
                break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
        case 6:
                encoder->possible_crtcs = 0x3f;
                break;
index d09031c03e262606677f5abb1d59576066b1f695..68820f5f630354a91826da1f4a8391e8b92b5e86 100644 (file)
@@ -479,6 +479,7 @@ extern void radeon_dp_set_link_config(struct drm_connector *connector,
                                      struct drm_display_mode *mode);
 extern void radeon_dp_link_train(struct drm_encoder *encoder,
                                 struct drm_connector *connector);
+extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
index 43f89ba0a90888d209341378ab626423b94b991f..fe89c4660d555fc821b8908c28a92ec208ca3070 100644 (file)
@@ -717,11 +717,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh;
-       struct neighbour *n;
+       struct neighbour *n = NULL;
        unsigned long flags;
 
-       n = dst_get_neighbour(skb_dst(skb));
-       if (likely(skb_dst(skb) && n)) {
+       if (likely(skb_dst(skb)))
+               n = dst_get_neighbour(skb_dst(skb));
+
+       if (likely(n)) {
                if (unlikely(!*to_ipoib_neigh(n))) {
                        ipoib_path_lookup(skb, dev);
                        return NETDEV_TX_OK;
index 8db008de5392209c6da296d9a2aa7f3729e4ae72..9c61b9c2c597a9e515af791faa6e16f87a95cfc3 100644 (file)
@@ -101,13 +101,17 @@ iscsi_iser_recv(struct iscsi_conn *conn,
 
        /* verify PDU length */
        datalen = ntoh24(hdr->dlength);
-       if (datalen != rx_data_len) {
-               printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n",
-                      datalen, rx_data_len);
+       if (datalen > rx_data_len || (datalen + 4) < rx_data_len) {
+               iser_err("wrong datalen %d (hdr), %d (IB)\n",
+                       datalen, rx_data_len);
                rc = ISCSI_ERR_DATALEN;
                goto error;
        }
 
+       if (datalen != rx_data_len)
+               iser_dbg("aligned datalen (%d) hdr, %d (IB)\n",
+                       datalen, rx_data_len);
+
        /* read AHS */
        ahslen = hdr->hlength * 4;
 
index 342cbc1bdaaecd0af0cd9ab857391c55f226bc59..db6f3ce9f3bf52d2bbfde9475b7b239f0a341bcf 100644 (file)
@@ -89,7 +89,7 @@
        } while (0)
 
 #define SHIFT_4K       12
-#define SIZE_4K        (1UL << SHIFT_4K)
+#define SIZE_4K        (1ULL << SHIFT_4K)
 #define MASK_4K        (~(SIZE_4K-1))
 
                                        /* support up to 512KB in one RDMA */
index 5745b7fe158c0e4178ae240dea6c3c4a8894d60f..f299de6b419bb03cf9486e7f813e1100c4cad4a5 100644 (file)
@@ -412,7 +412,7 @@ int iser_send_control(struct iscsi_conn *conn,
                memcpy(iser_conn->ib_conn->login_buf, task->data,
                                                        task->data_count);
                tx_dsg->addr    = iser_conn->ib_conn->login_dma;
-               tx_dsg->length  = data_seg_len;
+               tx_dsg->length  = task->data_count;
                tx_dsg->lkey    = device->mr->lkey;
                mdesc->num_sge = 2;
        }
index 749fdf0703199cef927004c6fa8b803d28ae1368..753b21aaea6196553fd0f3a541e2115e9b95e479 100644 (file)
@@ -158,47 +158,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
         */
 }
 
-/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
-static int pci_set_payload(struct pci_dev *dev)
-{
-       int pos, ppos;
-       u16 pctl, psz;
-       u16 dctl, dsz, dcap, dmax;
-       struct pci_dev *parent;
-
-       parent = dev->bus->self;
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-       if (!pos)
-               return 0;
-
-       /* Read Device MaxPayload capability and setting */
-       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
-       pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
-       dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
-       dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
-
-       /* Read Parent MaxPayload setting */
-       ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
-       if (!ppos)
-               return 0;
-       pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
-       psz = (pctl &  PCI_EXP_DEVCTL_PAYLOAD) >> 5;
-
-       /* If parent payload > device max payload -> error
-        * If parent payload > device payload -> set speed
-        * If parent payload <= device payload -> do nothing
-        */
-       if (psz > dmax)
-               return -1;
-       else if (psz > dsz) {
-               dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
-               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
-                                     (dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
-                                     (psz << 5));
-       }
-       return 0;
-}
-
 void pci_configure_slot(struct pci_dev *dev)
 {
        struct pci_dev *cdev;
@@ -210,9 +169,7 @@ void pci_configure_slot(struct pci_dev *dev)
                        (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
                return;
 
-       ret = pci_set_payload(dev);
-       if (ret)
-               dev_warn(&dev->dev, "could not set device max payload\n");
+       pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
 
        memset(&hpp, 0, sizeof(hpp));
        ret = pci_get_hp_params(dev, &hpp);
index c94d37ec55c87af38e7b6d1c9ccf46ea9baeb60c..f0929934bb7ac0c8a5d0dca4dbb197fb4700b6d3 100644 (file)
@@ -55,7 +55,7 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
         */
        if (bus->bridge->of_node)
                return of_node_get(bus->bridge->of_node);
-       if (bus->bridge->parent->of_node)
+       if (bus->bridge->parent && bus->bridge->parent->of_node)
                return of_node_get(bus->bridge->parent->of_node);
        return NULL;
 }
index 08a95b369d850c54292c66e45f67dfd197c860ef..0ce67423a0a31ce1c725d5f8c52bd3811baaa253 100644 (file)
@@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
 unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
 
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
+
 /*
  * The default CLS is used if arch didn't set CLS explicitly and not
  * all pci devices agree on the same value.  Arch can override either
@@ -3222,6 +3224,67 @@ out:
 }
 EXPORT_SYMBOL(pcie_set_readrq);
 
+/**
+ * pcie_get_mps - get PCI Express maximum payload size
+ * @dev: PCI device to query
+ *
+ * Returns maximum payload size in bytes
+ *    or appropriate error value.
+ */
+int pcie_get_mps(struct pci_dev *dev)
+{
+       int ret, cap;
+       u16 ctl;
+
+       cap = pci_pcie_cap(dev);
+       if (!cap)
+               return -EINVAL;
+
+       ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+       if (!ret)
+               ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+
+       return ret;
+}
+
+/**
+ * pcie_set_mps - set PCI Express maximum payload size
+ * @dev: PCI device to query
+ * @mps: maximum payload size in bytes
+ *    valid values are 128, 256, 512, 1024, 2048, 4096
+ *
+ * If possible sets maximum payload size
+ */
+int pcie_set_mps(struct pci_dev *dev, int mps)
+{
+       int cap, err = -EINVAL;
+       u16 ctl, v;
+
+       if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
+               goto out;
+
+       v = ffs(mps) - 8;
+       if (v > dev->pcie_mpss) 
+               goto out;
+       v <<= 5;
+
+       cap = pci_pcie_cap(dev);
+       if (!cap)
+               goto out;
+
+       err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+       if (err)
+               goto out;
+
+       if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) {
+               ctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
+               ctl |= v;
+               err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
+       }
+out:
+       return err;
+}
+
 /**
  * pci_select_bars - Make BAR mask from the type of resource
  * @dev: the PCI device for which BAR mask is made
@@ -3505,6 +3568,10 @@ static int __init pci_setup(char *str)
                                pci_hotplug_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
                                pci_hotplug_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "pcie_bus_safe", 13)) {
+                               pcie_bus_config = PCIE_BUS_SAFE;
+                       } else if (!strncmp(str, "pcie_bus_perf", 13)) {
+                               pcie_bus_config = PCIE_BUS_PERFORMANCE;
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);
index c8cee764b0de596ab8e1656a104203d5337e5f62..b74084e9ca12fa52e14f06e3b71d38aca4708b7d 100644 (file)
@@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
 
 #endif /* CONFIG_PCI_IOV */
 
+extern unsigned long pci_cardbus_resource_alignment(struct resource *);
+
 static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
                                         struct resource *res)
 {
@@ -292,6 +294,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
        if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
                return pci_sriov_resource_alignment(dev, resno);
 #endif
+       if (dev->class >> 8  == PCI_CLASS_BRIDGE_CARDBUS)
+               return pci_cardbus_resource_alignment(res);
        return resource_alignment(res);
 }
 
index 795c9026d55fccfa512d9c2393973947af05dab9..8473727b29fabaaa743b3d02ee771822175d02b4 100644 (file)
@@ -856,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
        pdev->pcie_cap = pos;
        pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
        pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+       pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
+       pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
 }
 
 void set_pcie_hotplug_bridge(struct pci_dev *pdev)
@@ -1326,6 +1328,150 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
        return nr;
 }
 
+static int pcie_find_smpss(struct pci_dev *dev, void *data)
+{
+       u8 *smpss = data;
+
+       if (!pci_is_pcie(dev))
+               return 0;
+
+       /* For PCIE hotplug enabled slots not connected directly to a
+        * PCI-E root port, there can be problems when hotplugging
+        * devices.  This is due to the possibility of hotplugging a
+        * device into the fabric with a smaller MPS that the devices
+        * currently running have configured.  Modifying the MPS on the
+        * running devices could cause a fatal bus error due to an
+        * incoming frame being larger than the newly configured MPS.
+        * To work around this, the MPS for the entire fabric must be
+        * set to the minimum size.  Any devices hotplugged into this
+        * fabric will have the minimum MPS set.  If the PCI hotplug
+        * slot is directly connected to the root port and there are not
+        * other devices on the fabric (which seems to be the most
+        * common case), then this is not an issue and MPS discovery
+        * will occur as normal.
+        */
+       if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
+           dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+               *smpss = 0;
+
+       if (*smpss > dev->pcie_mpss)
+               *smpss = dev->pcie_mpss;
+
+       return 0;
+}
+
+static void pcie_write_mps(struct pci_dev *dev, int mps)
+{
+       int rc, dev_mpss;
+
+       dev_mpss = 128 << dev->pcie_mpss;
+
+       if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
+               if (dev->bus->self) {
+                       dev_dbg(&dev->bus->dev, "Bus MPSS %d\n",
+                               128 << dev->bus->self->pcie_mpss);
+
+                       /* For "MPS Force Max", the assumption is made that
+                        * downstream communication will never be larger than
+                        * the MRRS.  So, the MPS only needs to be configured
+                        * for the upstream communication.  This being the case,
+                        * walk from the top down and set the MPS of the child
+                        * to that of the parent bus.
+                        */
+                       mps = 128 << dev->bus->self->pcie_mpss;
+                       if (mps > dev_mpss)
+                               dev_warn(&dev->dev, "MPS configured higher than"
+                                        " maximum supported by the device.  If"
+                                        " a bus issue occurs, try running with"
+                                        " pci=pcie_bus_safe.\n");
+               }
+
+               dev->pcie_mpss = ffs(mps) - 8;
+       }
+
+       rc = pcie_set_mps(dev, mps);
+       if (rc)
+               dev_err(&dev->dev, "Failed attempting to set the MPS\n");
+}
+
+static void pcie_write_mrrs(struct pci_dev *dev, int mps)
+{
+       int rc, mrrs;
+
+       if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
+               int dev_mpss = 128 << dev->pcie_mpss;
+
+               /* For Max performance, the MRRS must be set to the largest
+                * supported value.  However, it cannot be configured larger
+                * than the MPS the device or the bus can support.  This assumes
+                * that the largest MRRS available on the device cannot be
+                * smaller than the device MPSS.
+                */
+               mrrs = mps < dev_mpss ? mps : dev_mpss;
+       } else
+               /* In the "safe" case, configure the MRRS for fairness on the
+                * bus by making all devices have the same size
+                */
+               mrrs = mps;
+
+
+       /* MRRS is a R/W register.  Invalid values can be written, but a
+        * subsiquent read will verify if the value is acceptable or not.
+        * If the MRRS value provided is not acceptable (e.g., too large),
+        * shrink the value until it is acceptable to the HW.
+        */
+       while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
+               rc = pcie_set_readrq(dev, mrrs);
+               if (rc)
+                       dev_err(&dev->dev, "Failed attempting to set the MRRS\n");
+
+               mrrs /= 2;
+       }
+}
+
+static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
+{
+       int mps = 128 << *(u8 *)data;
+
+       if (!pci_is_pcie(dev))
+               return 0;
+
+       dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+                pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
+
+       pcie_write_mps(dev, mps);
+       pcie_write_mrrs(dev, mps);
+
+       dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+                pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
+
+       return 0;
+}
+
+/* pcie_bus_configure_mps requires that pci_walk_bus work in a top-down,
+ * parents then children fashion.  If this changes, then this code will not
+ * work as designed.
+ */
+void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
+{
+       u8 smpss = mpss;
+
+       if (!bus->self)
+               return;
+
+       if (!pci_is_pcie(bus->self))
+               return;
+
+       if (pcie_bus_config == PCIE_BUS_SAFE) {
+               pcie_find_smpss(bus->self, &smpss);
+               pci_walk_bus(bus, pcie_find_smpss, &smpss);
+       }
+
+       pcie_bus_configure_set(bus->self, &smpss);
+       pci_walk_bus(bus, pcie_bus_configure_set, &smpss);
+}
+EXPORT_SYMBOL_GPL(pcie_bus_configure_settings);
+
 unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 {
        unsigned int devfn, pass, max = bus->secondary;
index 8a1d3c7863a89d5514f18357e8a5b6726452335e..784da9d3602985606d850d9d07f51b65f21e3f05 100644 (file)
@@ -34,6 +34,7 @@ struct resource_list_x {
        resource_size_t start;
        resource_size_t end;
        resource_size_t add_size;
+       resource_size_t min_align;
        unsigned long flags;
 };
 
@@ -65,7 +66,7 @@ void pci_realloc(void)
  */
 static void add_to_list(struct resource_list_x *head,
                 struct pci_dev *dev, struct resource *res,
-                resource_size_t add_size)
+                resource_size_t add_size, resource_size_t min_align)
 {
        struct resource_list_x *list = head;
        struct resource_list_x *ln = list->next;
@@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head,
        tmp->end = res->end;
        tmp->flags = res->flags;
        tmp->add_size = add_size;
+       tmp->min_align = min_align;
        list->next = tmp;
 }
 
 static void add_to_failed_list(struct resource_list_x *head,
                                struct pci_dev *dev, struct resource *res)
 {
-       add_to_list(head, dev, res, 0);
+       add_to_list(head, dev, res,
+                       0 /* dont care */,
+                       0 /* dont care */);
 }
 
 static void __dev_sort_resources(struct pci_dev *dev,
@@ -121,18 +125,18 @@ static inline void reset_resource(struct resource *res)
 }
 
 /**
- * adjust_resources_sorted() - satisfy any additional resource requests
+ * reassign_resources_sorted() - satisfy any additional resource requests
  *
- * @add_head : head of the list tracking requests requiring additional
+ * @realloc_head : head of the list tracking requests requiring additional
  *             resources
  * @head     : head of the list tracking requests with allocated
  *             resources
  *
- * Walk through each element of the add_head and try to procure
+ * Walk through each element of the realloc_head and try to procure
  * additional resources for the element, provided the element
  * is in the head list.
  */
-static void adjust_resources_sorted(struct resource_list_x *add_head,
+static void reassign_resources_sorted(struct resource_list_x *realloc_head,
                struct resource_list *head)
 {
        struct resource *res;
@@ -141,8 +145,8 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
        resource_size_t add_size;
        int idx;
 
-       prev = add_head;
-       for (list = add_head->next; list;) {
+       prev = realloc_head;
+       for (list = realloc_head->next; list;) {
                res = list->res;
                /* skip resource that has been reset */
                if (!res->flags)
@@ -159,13 +163,17 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
 
                idx = res - &list->dev->resource[0];
                add_size=list->add_size;
-               if (!resource_size(res) && add_size) {
-                        res->end = res->start + add_size - 1;
-                        if(pci_assign_resource(list->dev, idx))
+               if (!resource_size(res)) {
+                       res->start = list->start;
+                       res->end = res->start + add_size - 1;
+                       if(pci_assign_resource(list->dev, idx))
                                reset_resource(res);
-               } else if (add_size) {
-                       adjust_resource(res, res->start,
-                               resource_size(res) + add_size);
+               } else {
+                       resource_size_t align = list->min_align;
+                       res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
+                       if (pci_reassign_resource(list->dev, idx, add_size, align))
+                               dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
+                                                       res);
                }
 out:
                tmp = list;
@@ -210,16 +218,16 @@ static void assign_requested_resources_sorted(struct resource_list *head,
 }
 
 static void __assign_resources_sorted(struct resource_list *head,
-                                struct resource_list_x *add_head,
+                                struct resource_list_x *realloc_head,
                                 struct resource_list_x *fail_head)
 {
        /* Satisfy the must-have resource requests */
        assign_requested_resources_sorted(head, fail_head);
 
-       /* Try to satisfy any additional nice-to-have resource
+       /* Try to satisfy any additional optional resource
                requests */
-       if (add_head)
-               adjust_resources_sorted(add_head, head);
+       if (realloc_head)
+               reassign_resources_sorted(realloc_head, head);
        free_list(resource_list, head);
 }
 
@@ -235,7 +243,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,
 }
 
 static void pbus_assign_resources_sorted(const struct pci_bus *bus,
-                                        struct resource_list_x *add_head,
+                                        struct resource_list_x *realloc_head,
                                         struct resource_list_x *fail_head)
 {
        struct pci_dev *dev;
@@ -245,7 +253,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
        list_for_each_entry(dev, &bus->devices, bus_list)
                __dev_sort_resources(dev, &head);
 
-       __assign_resources_sorted(&head, add_head, fail_head);
+       __assign_resources_sorted(&head, realloc_head, fail_head);
 }
 
 void pci_setup_cardbus(struct pci_bus *bus)
@@ -540,13 +548,27 @@ static resource_size_t calculate_memsize(resource_size_t size,
        return size;
 }
 
+static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
+                                       struct resource *res)
+{
+       struct resource_list_x *list;
+
+       /* check if it is in realloc_head list */
+       for (list = realloc_head->next; list && list->res != res;
+                       list = list->next);
+       if (list)
+               return list->add_size;
+
+       return 0;
+}
+
 /**
  * pbus_size_io() - size the io window of a given bus
  *
  * @bus : the bus
  * @min_size : the minimum io window that must to be allocated
  * @add_size : additional optional io window
- * @add_head : track the additional io window on this list
+ * @realloc_head : track the additional io window on this list
  *
  * Sizing the IO windows of the PCI-PCI bridge is trivial,
  * since these windows have 4K granularity and the IO ranges
@@ -554,11 +576,12 @@ static resource_size_t calculate_memsize(resource_size_t size,
  * We must be careful with the ISA aliasing though.
  */
 static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
-               resource_size_t add_size, struct resource_list_x *add_head)
+               resource_size_t add_size, struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
        unsigned long size = 0, size0 = 0, size1 = 0;
+       resource_size_t children_add_size = 0;
 
        if (!b_res)
                return;
@@ -579,11 +602,16 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                                size += r_size;
                        else
                                size1 += r_size;
+
+                       if (realloc_head)
+                               children_add_size += get_res_add_size(realloc_head, r);
                }
        }
        size0 = calculate_iosize(size, min_size, size1,
                        resource_size(b_res), 4096);
-       size1 = (!add_head || (add_head && !add_size)) ? size0 :
+       if (children_add_size > add_size)
+               add_size = children_add_size;
+       size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
                calculate_iosize(size, min_size+add_size, size1,
                        resource_size(b_res), 4096);
        if (!size0 && !size1) {
@@ -598,8 +626,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        b_res->start = 4096;
        b_res->end = b_res->start + size0 - 1;
        b_res->flags |= IORESOURCE_STARTALIGN;
-       if (size1 > size0 && add_head)
-               add_to_list(add_head, bus->self, b_res, size1-size0);
+       if (size1 > size0 && realloc_head)
+               add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
 }
 
 /**
@@ -608,7 +636,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
  * @bus : the bus
  * @min_size : the minimum memory window that must to be allocated
  * @add_size : additional optional memory window
- * @add_head : track the additional memory window on this list
+ * @realloc_head : track the additional memory window on this list
  *
  * Calculate the size of the bus and minimal alignment which
  * guarantees that all child resources fit in this size.
@@ -616,7 +644,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                         unsigned long type, resource_size_t min_size,
                        resource_size_t add_size,
-                       struct resource_list_x *add_head)
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        resource_size_t min_align, align, size, size0, size1;
@@ -624,6 +652,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        int order, max_order;
        struct resource *b_res = find_free_bus_resource(bus, type);
        unsigned int mem64_mask = 0;
+       resource_size_t children_add_size = 0;
 
        if (!b_res)
                return 0;
@@ -645,6 +674,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                        if (r->parent || (r->flags & mask) != type)
                                continue;
                        r_size = resource_size(r);
+#ifdef CONFIG_PCI_IOV
+                       /* put SRIOV requested res to the optional list */
+                       if (realloc_head && i >= PCI_IOV_RESOURCES &&
+                                       i <= PCI_IOV_RESOURCE_END) {
+                               r->end = r->start - 1;
+                               add_to_list(realloc_head, dev, r, r_size, 0/* dont' care */);
+                               children_add_size += r_size;
+                               continue;
+                       }
+#endif
                        /* For bridges size != alignment */
                        align = pci_resource_alignment(dev, r);
                        order = __ffs(align) - 20;
@@ -665,6 +704,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                        if (order > max_order)
                                max_order = order;
                        mem64_mask &= r->flags & IORESOURCE_MEM_64;
+
+                       if (realloc_head)
+                               children_add_size += get_res_add_size(realloc_head, r);
                }
        }
        align = 0;
@@ -681,7 +723,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                align += aligns[order];
        }
        size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
-       size1 = (!add_head || (add_head && !add_size)) ? size0 :
+       if (children_add_size > add_size)
+               add_size = children_add_size;
+       size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
                calculate_memsize(size, min_size+add_size, 0,
                                resource_size(b_res), min_align);
        if (!size0 && !size1) {
@@ -695,12 +739,22 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        b_res->start = min_align;
        b_res->end = size0 + min_align - 1;
        b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
-       if (size1 > size0 && add_head)
-               add_to_list(add_head, bus->self, b_res, size1-size0);
+       if (size1 > size0 && realloc_head)
+               add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
        return 1;
 }
 
-static void pci_bus_size_cardbus(struct pci_bus *bus)
+unsigned long pci_cardbus_resource_alignment(struct resource *res)
+{
+       if (res->flags & IORESOURCE_IO)
+               return pci_cardbus_io_size;
+       if (res->flags & IORESOURCE_MEM)
+               return pci_cardbus_mem_size;
+       return 0;
+}
+
+static void pci_bus_size_cardbus(struct pci_bus *bus,
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *bridge = bus->self;
        struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
@@ -711,12 +765,14 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
         * a fixed amount of bus space for CardBus bridges.
         */
        b_res[0].start = 0;
-       b_res[0].end = pci_cardbus_io_size - 1;
        b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
+       if (realloc_head)
+               add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
 
        b_res[1].start = 0;
-       b_res[1].end = pci_cardbus_io_size - 1;
        b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
+       if (realloc_head)
+               add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
 
        /*
         * Check whether prefetchable memory is supported
@@ -736,21 +792,31 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
         */
        if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
                b_res[2].start = 0;
-               b_res[2].end = pci_cardbus_mem_size - 1;
                b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
 
                b_res[3].start = 0;
-               b_res[3].end = pci_cardbus_mem_size - 1;
                b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
        } else {
                b_res[3].start = 0;
-               b_res[3].end = pci_cardbus_mem_size * 2 - 1;
                b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
+               if (realloc_head)
+                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
        }
+
+       /* set the size of the resource to zero, so that the resource does not
+        * get assigned during required-resource allocation cycle but gets assigned
+        * during the optional-resource allocation cycle.
+        */
+       b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
+       b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
 }
 
 void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-                       struct resource_list_x *add_head)
+                       struct resource_list_x *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
@@ -763,12 +829,12 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
 
                switch (dev->class >> 8) {
                case PCI_CLASS_BRIDGE_CARDBUS:
-                       pci_bus_size_cardbus(b);
+                       pci_bus_size_cardbus(b, realloc_head);
                        break;
 
                case PCI_CLASS_BRIDGE_PCI:
                default:
-                       __pci_bus_size_bridges(b, add_head);
+                       __pci_bus_size_bridges(b, realloc_head);
                        break;
                }
        }
@@ -792,7 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                 * Follow thru
                 */
        default:
-               pbus_size_io(bus, 0, additional_io_size, add_head);
+               pbus_size_io(bus, 0, additional_io_size, realloc_head);
                /* If the bridge supports prefetchable range, size it
                   separately. If it doesn't, or its prefetchable window
                   has already been allocated by arch code, try
@@ -800,11 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                   resources. */
                mask = IORESOURCE_MEM;
                prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-               if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head))
+               if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
                        mask = prefmask; /* Success, size non-prefetch only. */
                else
                        additional_mem_size += additional_mem_size;
-               pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head);
+               pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
                break;
        }
 }
@@ -816,20 +882,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
 static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                        struct resource_list_x *add_head,
+                                        struct resource_list_x *realloc_head,
                                         struct resource_list_x *fail_head)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
 
-       pbus_assign_resources_sorted(bus, add_head, fail_head);
+       pbus_assign_resources_sorted(bus, realloc_head, fail_head);
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                b = dev->subordinate;
                if (!b)
                        continue;
 
-               __pci_bus_assign_resources(b, add_head, fail_head);
+               __pci_bus_assign_resources(b, realloc_head, fail_head);
 
                switch (dev->class >> 8) {
                case PCI_CLASS_BRIDGE_PCI:
@@ -1039,7 +1105,7 @@ void __init
 pci_assign_unassigned_resources(void)
 {
        struct pci_bus *bus;
-       struct resource_list_x add_list; /* list of resources that
+       struct resource_list_x realloc_list; /* list of resources that
                                        want additional resources */
        int tried_times = 0;
        enum release_type rel_type = leaf_only;
@@ -1052,7 +1118,7 @@ pci_assign_unassigned_resources(void)
 
 
        head.next = NULL;
-       add_list.next = NULL;
+       realloc_list.next = NULL;
 
        pci_try_num = max_depth + 1;
        printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
@@ -1062,12 +1128,12 @@ again:
        /* Depth first, calculate sizes and alignments of all
           subordinate buses. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_size_bridges(bus, &add_list);
+               __pci_bus_size_bridges(bus, &realloc_list);
 
        /* Depth last, allocate resources and update the hardware. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_assign_resources(bus, &add_list, &head);
-       BUG_ON(add_list.next);
+               __pci_bus_assign_resources(bus, &realloc_list, &head);
+       BUG_ON(realloc_list.next);
        tried_times++;
 
        /* any device complain? */
index 319f359906e8198628e3d8a7ce60447dd82c3c0f..51a9095c7da4812ddfd843c615083eca61ea9889 100644 (file)
@@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
 }
 #endif /* CONFIG_PCI_QUIRKS */
 
+
+
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
-                                int resno)
+               int resno, resource_size_t size, resource_size_t align)
 {
        struct resource *res = dev->resource + resno;
-       resource_size_t size, min, align;
+       resource_size_t min;
        int ret;
 
-       size = resource_size(res);
        min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
-       align = pci_resource_alignment(dev, res);
 
        /* First, try exact prefetching match.. */
        ret = pci_bus_alloc_resource(bus, res, size, align, min,
@@ -154,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
                ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
                                             pcibios_align_resource, dev);
        }
+       return ret;
+}
 
-       if (ret < 0 && dev->fw_addr[resno]) {
-               struct resource *root, *conflict;
-               resource_size_t start, end;
+static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, 
+               int resno, resource_size_t size)
+{
+       struct resource *root, *conflict;
+       resource_size_t start, end;
+       int ret = 0;
 
-               /*
-                * If we failed to assign anything, let's try the address
-                * where firmware left it.  That at least has a chance of
-                * working, which is better than just leaving it disabled.
-                */
+       if (res->flags & IORESOURCE_IO)
+               root = &ioport_resource;
+       else
+               root = &iomem_resource;
+
+       start = res->start;
+       end = res->end;
+       res->start = dev->fw_addr[resno];
+       res->end = res->start + size - 1;
+       dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
+                resno, res);
+       conflict = request_resource_conflict(root, res);
+       if (conflict) {
+               dev_info(&dev->dev,
+                        "BAR %d: %pR conflicts with %s %pR\n", resno,
+                        res, conflict->name, conflict);
+               res->start = start;
+               res->end = end;
+               ret = 1;
+       }
+       return ret;
+}
+
+static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align)
+{
+       struct resource *res = dev->resource + resno;
+       struct pci_bus *bus;
+       int ret;
+       char *type;
 
-               if (res->flags & IORESOURCE_IO)
-                       root = &ioport_resource;
+       bus = dev->bus;
+       while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
+               if (!bus->parent || !bus->self->transparent)
+                       break;
+               bus = bus->parent;
+       }
+
+       if (ret) {
+               if (res->flags & IORESOURCE_MEM)
+                       if (res->flags & IORESOURCE_PREFETCH)
+                               type = "mem pref";
+                       else
+                               type = "mem";
+               else if (res->flags & IORESOURCE_IO)
+                       type = "io";
                else
-                       root = &iomem_resource;
-
-               start = res->start;
-               end = res->end;
-               res->start = dev->fw_addr[resno];
-               res->end = res->start + size - 1;
-               dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
-                        resno, res);
-               conflict = request_resource_conflict(root, res);
-               if (conflict) {
-                       dev_info(&dev->dev,
-                                "BAR %d: %pR conflicts with %s %pR\n", resno,
-                                res, conflict->name, conflict);
-                       res->start = start;
-                       res->end = end;
-               } else
-                       ret = 0;
+                       type = "unknown";
+               dev_info(&dev->dev,
+                        "BAR %d: can't assign %s (size %#llx)\n",
+                        resno, type, (unsigned long long) resource_size(res));
        }
 
+       return ret;
+}
+
+int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
+                       resource_size_t min_align)
+{
+       struct resource *res = dev->resource + resno;
+       resource_size_t new_size;
+       int ret;
+
+       if (!res->parent) {
+               dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
+                        "\n", resno, res);
+               return -EINVAL;
+       }
+
+       new_size = resource_size(res) + addsize + min_align;
+       ret = _pci_assign_resource(dev, resno, new_size, min_align);
        if (!ret) {
                res->flags &= ~IORESOURCE_STARTALIGN;
                dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
                if (resno < PCI_BRIDGE_RESOURCES)
                        pci_update_resource(dev, resno);
        }
-
        return ret;
 }
 
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct resource *res = dev->resource + resno;
-       resource_size_t align;
+       resource_size_t align, size;
        struct pci_bus *bus;
        int ret;
-       char *type;
 
        align = pci_resource_alignment(dev, res);
        if (!align) {
@@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        }
 
        bus = dev->bus;
-       while ((ret = __pci_assign_resource(bus, dev, resno))) {
-               if (bus->parent && bus->self->transparent)
-                       bus = bus->parent;
-               else
-                       bus = NULL;
-               if (bus)
-                       continue;
-               break;
-       }
+       size = resource_size(res);
+       ret = _pci_assign_resource(dev, resno, size, align);
 
-       if (ret) {
-               if (res->flags & IORESOURCE_MEM)
-                       if (res->flags & IORESOURCE_PREFETCH)
-                               type = "mem pref";
-                       else
-                               type = "mem";
-               else if (res->flags & IORESOURCE_IO)
-                       type = "io";
-               else
-                       type = "unknown";
-               dev_info(&dev->dev,
-                        "BAR %d: can't assign %s (size %#llx)\n",
-                        resno, type, (unsigned long long) resource_size(res));
-       }
+       /*
+        * If we failed to assign anything, let's try the address
+        * where firmware left it.  That at least has a chance of
+        * working, which is better than just leaving it disabled.
+        */
+       if (ret < 0 && dev->fw_addr[resno])
+               ret = pci_revert_fw_address(res, dev, resno, size);
 
+       if (!ret) {
+               res->flags &= ~IORESOURCE_STARTALIGN;
+               dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
+               if (resno < PCI_BRIDGE_RESOURCES)
+                       pci_update_resource(dev, resno);
+       }
        return ret;
 }
 
+
 /* Sort resources by alignment */
 void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 {
index 3195dbd3ec3468910396c029e42d9613e206b283..44e91e598f8d975ae7570b80366a67540611c8da 100644 (file)
@@ -639,7 +639,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_unregister);
 static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
 {
        /*
-        * We unconditionally cancel the timer here, because otherwise
+        * We always cancel the timer here first, because otherwise
         * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
         * when we manage to start the timer before the callback
         * returns HRTIMER_RESTART.
@@ -708,7 +708,7 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
        int err = 0;
        unsigned long flags;
 
-       if (freq <= 0 || freq > 5000)
+       if (freq <= 0 || freq > RTC_MAX_FREQ)
                return -EINVAL;
 retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
index 02e17c9c8637e5d3b61a63214b65dae28adb6afa..fd211f3467c41931904bcb155bbd98d0c00e1af4 100644 (file)
@@ -711,10 +711,11 @@ struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dbi_output->base.base;
+       /* Review this if we ever get MIPI-HDMI bridges or similar */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs);
 
        /* Attach to given connector */
index dc6242c51d0bc69f3332313a617b8c6ce54d9f88..f0fa986fd9341923ec7bbb99eeca1859a48f5271 100644 (file)
@@ -42,9 +42,6 @@
 #include "mdfld_dsi_output.h"
 #include "mdfld_output.h"
 
-#define DRM_MODE_ENCODER_MIPI  5
-
-
 /*
  * DBI encoder which inherits from mdfld_dsi_encoder
  */
index 6e03a91e947ea6cd5687f6eeca9a59dbd90df96e..e685f1217baa89d303243daec92e158d43ffca7d 100644 (file)
@@ -777,10 +777,15 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dpi_output->base.base;
+       /*
+        * On existing hardware this will be a panel of some form,
+        * if future devices also have HDMI bridges this will need
+        * revisiting
+        */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder,
                                p_funcs->encoder_helper_funcs);
        
index 7536095c30a0653c566dafa788020920a6461ea7..9050c0f78b15b1c964ed7f35a576bda9f9bdf96d 100644 (file)
@@ -955,7 +955,9 @@ void mdfld_dsi_output_init(struct drm_device *dev,
        psb_output->type = (pipe == 0) ? INTEL_OUTPUT_MIPI : INTEL_OUTPUT_MIPI2;
 
        connector = &psb_output->base;
-       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, DRM_MODE_CONNECTOR_MIPI);
+       /* Revisit type if MIPI/HDMI bridges ever appear on Medfield */
+       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
+                                               DRM_MODE_CONNECTOR_LVDS);
        drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
        
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
index 38165e8367e5943f61485cad6409363d8c71a2fa..09e9687431f16a634de396ec0b83ae0bb0e78f81 100644 (file)
@@ -21,8 +21,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#define DRM_MODE_ENCODER_MIPI  5
-
 /* Medfield DSI controller registers */
 
 #define MIPIA_DEVICE_READY_REG                         0xb000
index 72f487a2a1b7a9d95e5e5323c8d634f776d5ed54..fd4732dd783a81c945d7109f9233a395d0a25e91 100644 (file)
@@ -35,7 +35,6 @@
 
 /* Append new drm mode definition here, align with libdrm definition */
 #define DRM_MODE_SCALE_NO_SCALE        2
-#define DRM_MODE_CONNECTOR_MIPI         15
 
 enum {
        CHIP_PSB_8108 = 0,              /* Poulsbo */
index 1b4afd81f872306bb4f5ffd9b860fb5f3c0adc6f..6ea852e251629518cc8d808a087bbc9d4c87fb31 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/module.h>
 #include <linux/workqueue.h>
 #include <xen/balloon.h>
 #include <xen/tmem.h>
index 54b8c28bebc8f8b4b63dcc1f010bbf035a09cbd6..720d885e8dcaa87b54f61f0fa8b027109528758b 100644 (file)
@@ -474,17 +474,22 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
                befs_data_stream *data = &befs_ino->i_data.ds;
                befs_off_t len = data->size;
 
-               befs_debug(sb, "Follow long symlink");
-
-               link = kmalloc(len, GFP_NOFS);
-               if (!link) {
-                       link = ERR_PTR(-ENOMEM);
-               } else if (befs_read_lsymlink(sb, data, link, len) != len) {
-                       kfree(link);
-                       befs_error(sb, "Failed to read entire long symlink");
+               if (len == 0) {
+                       befs_error(sb, "Long symlink with illegal length");
                        link = ERR_PTR(-EIO);
                } else {
-                       link[len - 1] = '\0';
+                       befs_debug(sb, "Follow long symlink");
+
+                       link = kmalloc(len, GFP_NOFS);
+                       if (!link) {
+                               link = ERR_PTR(-ENOMEM);
+                       } else if (befs_read_lsymlink(sb, data, link, len) != len) {
+                               kfree(link);
+                               befs_error(sb, "Failed to read entire long symlink");
+                               link = ERR_PTR(-EIO);
+                       } else {
+                               link[len - 1] = '\0';
+                       }
                }
        } else {
                link = befs_ino->i_data.symlink;
index 0469263e327eebd66f36b6ba9a4e8a1ba67850d5..03912c5c6f498221b965baef0fafed10904677e6 100644 (file)
@@ -1415,17 +1415,15 @@ void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)            \
 static inline u##bits btrfs_##name(struct extent_buffer *eb)           \
 {                                                                      \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        u##bits res = le##bits##_to_cpu(p->member);                     \
-       kunmap_atomic(p, KM_USER0);                                     \
        return res;                                                     \
 }                                                                      \
 static inline void btrfs_set_##name(struct extent_buffer *eb,          \
                                    u##bits val)                        \
 {                                                                      \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        p->member = cpu_to_le##bits(val);                               \
-       kunmap_atomic(p, KM_USER0);                                     \
 }
 
 #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)             \
@@ -2367,8 +2365,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-int btrfs_drop_snapshot(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, int update_ref);
+void btrfs_drop_snapshot(struct btrfs_root *root,
+                        struct btrfs_block_rsv *block_rsv, int update_ref);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
index 66bac226944e05ae82edb56a9fd43116f31a901a..f5be06a2462f4b01b5bba3834c1527a3a0c5bf18 100644 (file)
@@ -1782,6 +1782,9 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 
 
                for (i = 0; i < multi->num_stripes; i++, stripe++) {
+                       if (!stripe->dev->can_discard)
+                               continue;
+
                        ret = btrfs_issue_discard(stripe->dev->bdev,
                                                  stripe->physical,
                                                  stripe->length);
@@ -1789,11 +1792,16 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
                                discarded_bytes += stripe->length;
                        else if (ret != -EOPNOTSUPP)
                                break;
+
+                       /*
+                        * Just in case we get back EOPNOTSUPP for some reason,
+                        * just ignore the return value so we don't screw up
+                        * people calling discard_extent.
+                        */
+                       ret = 0;
                }
                kfree(multi);
        }
-       if (discarded_bytes && ret == -EOPNOTSUPP)
-               ret = 0;
 
        if (actual_bytes)
                *actual_bytes = discarded_bytes;
@@ -6269,8 +6277,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
  * also make sure backrefs for the shared block and all lower level
  * blocks are properly updated.
  */
-int btrfs_drop_snapshot(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, int update_ref)
+void btrfs_drop_snapshot(struct btrfs_root *root,
+                        struct btrfs_block_rsv *block_rsv, int update_ref)
 {
        struct btrfs_path *path;
        struct btrfs_trans_handle *trans;
@@ -6283,13 +6291,16 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        int level;
 
        path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       if (!path) {
+               err = -ENOMEM;
+               goto out;
+       }
 
        wc = kzalloc(sizeof(*wc), GFP_NOFS);
        if (!wc) {
                btrfs_free_path(path);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out;
        }
 
        trans = btrfs_start_transaction(tree_root, 0);
@@ -6318,7 +6329,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                path->lowest_level = 0;
                if (ret < 0) {
                        err = ret;
-                       goto out;
+                       goto out_free;
                }
                WARN_ON(ret > 0);
 
@@ -6425,11 +6436,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                free_extent_buffer(root->commit_root);
                kfree(root);
        }
-out:
+out_free:
        btrfs_end_transaction_throttle(trans, tree_root);
        kfree(wc);
        btrfs_free_path(path);
-       return err;
+out:
+       if (err)
+               btrfs_std_error(root->fs_info, err);
+       return;
 }
 
 /*
@@ -6720,6 +6734,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        struct btrfs_space_info *space_info;
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        struct btrfs_device *device;
+       u64 min_free;
+       u64 dev_min = 1;
+       u64 dev_nr = 0;
+       int index;
        int full = 0;
        int ret = 0;
 
@@ -6729,8 +6747,10 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        if (!block_group)
                return -1;
 
+       min_free = btrfs_block_group_used(&block_group->item);
+
        /* no bytes used, we're good */
-       if (!btrfs_block_group_used(&block_group->item))
+       if (!min_free)
                goto out;
 
        space_info = block_group->space_info;
@@ -6746,10 +6766,9 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
         * all of the extents from this block group.  If we can, we're good
         */
        if ((space_info->total_bytes != block_group->key.offset) &&
-          (space_info->bytes_used + space_info->bytes_reserved +
-           space_info->bytes_pinned + space_info->bytes_readonly +
-           btrfs_block_group_used(&block_group->item) <
-           space_info->total_bytes)) {
+           (space_info->bytes_used + space_info->bytes_reserved +
+            space_info->bytes_pinned + space_info->bytes_readonly +
+            min_free < space_info->total_bytes)) {
                spin_unlock(&space_info->lock);
                goto out;
        }
@@ -6766,9 +6785,31 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        if (full)
                goto out;
 
+       /*
+        * index:
+        *      0: raid10
+        *      1: raid1
+        *      2: dup
+        *      3: raid0
+        *      4: single
+        */
+       index = get_block_group_index(block_group);
+       if (index == 0) {
+               dev_min = 4;
+               /* Divide by 2 */
+               min_free >>= 1;
+       } else if (index == 1) {
+               dev_min = 2;
+       } else if (index == 2) {
+               /* Multiply by 2 */
+               min_free <<= 1;
+       } else if (index == 3) {
+               dev_min = fs_devices->rw_devices;
+               do_div(min_free, dev_min);
+       }
+
        mutex_lock(&root->fs_info->chunk_mutex);
        list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
-               u64 min_free = btrfs_block_group_used(&block_group->item);
                u64 dev_offset;
 
                /*
@@ -6779,7 +6820,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
                        ret = find_free_dev_extent(NULL, device, min_free,
                                                   &dev_offset, NULL);
                        if (!ret)
+                               dev_nr++;
+
+                       if (dev_nr >= dev_min)
                                break;
+
                        ret = -1;
                }
        }
index 658d66959abe9eca7608f650d73bd9952a053ac4..e7872e485f13156459a9f0a4b14296e177f371b3 100644 (file)
@@ -150,6 +150,8 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        spin_lock(&root->fs_info->defrag_inodes_lock);
        if (!BTRFS_I(inode)->in_defrag)
                __btrfs_add_inode_defrag(inode, defrag);
+       else
+               kfree(defrag);
        spin_unlock(&root->fs_info->defrag_inodes_lock);
        return 0;
 }
@@ -1638,11 +1640,15 @@ static long btrfs_fallocate(struct file *file, int mode,
 
        cur_offset = alloc_start;
        while (1) {
+               u64 actual_end;
+
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
                BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), alloc_end);
+               actual_end = min_t(u64, extent_map_end(em), offset + len);
                last_byte = (last_byte + mask) & ~mask;
+
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
@@ -1655,6 +1661,16 @@ static long btrfs_fallocate(struct file *file, int mode,
                                free_extent_map(em);
                                break;
                        }
+               } else if (actual_end > inode->i_size &&
+                          !(mode & FALLOC_FL_KEEP_SIZE)) {
+                       /*
+                        * We didn't need to allocate any more space, but we
+                        * still extended the size of the file so we need to
+                        * update i_size.
+                        */
+                       inode->i_ctime = CURRENT_TIME;
+                       i_size_write(inode, actual_end);
+                       btrfs_ordered_update_i_size(inode, actual_end, NULL);
                }
                free_extent_map(em);
 
@@ -1804,10 +1820,14 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
                }
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (offset > inode->i_sb->s_maxbytes)
-               return -EINVAL;
+       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (offset > inode->i_sb->s_maxbytes) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* Special lock needed here? */
        if (offset != file->f_pos) {
index 6377713f639c978db84f64dec2dc9541e8c8287e..6a265b9f85f2cb282940f127bb39d9c56cb5082f 100644 (file)
@@ -1168,9 +1168,9 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
                div64_u64(extent_bytes, (sizeof(struct btrfs_free_space)));
 }
 
-static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
-                             struct btrfs_free_space *info, u64 offset,
-                             u64 bytes)
+static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
+                                      struct btrfs_free_space *info,
+                                      u64 offset, u64 bytes)
 {
        unsigned long start, count;
 
@@ -1181,6 +1181,13 @@ static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
        bitmap_clear(info->bitmap, start, count);
 
        info->bytes -= bytes;
+}
+
+static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_free_space *info, u64 offset,
+                             u64 bytes)
+{
+       __bitmap_clear_bits(ctl, info, offset, bytes);
        ctl->free_space -= bytes;
 }
 
@@ -1984,7 +1991,7 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
                return 0;
 
        ret = search_start;
-       bitmap_clear_bits(ctl, entry, ret, bytes);
+       __bitmap_clear_bits(ctl, entry, ret, bytes);
 
        return ret;
 }
@@ -2039,7 +2046,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                                continue;
                        }
                } else {
-
                        ret = entry->offset;
 
                        entry->offset += bytes;
index 15fceefbca0a02b9d1c9ddf3a4da224228c2ec40..0ccc7438ad3477163a2fe6d642f2ba40cb9e1533 100644 (file)
@@ -7354,11 +7354,15 @@ static int btrfs_set_page_dirty(struct page *page)
 static int btrfs_permission(struct inode *inode, int mask)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       umode_t mode = inode->i_mode;
 
-       if (btrfs_root_readonly(root) && (mask & MAY_WRITE))
-               return -EROFS;
-       if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
-               return -EACCES;
+       if (mask & MAY_WRITE &&
+           (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
+               if (btrfs_root_readonly(root))
+                       return -EROFS;
+               if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
+                       return -EACCES;
+       }
        return generic_permission(inode, mask);
 }
 
index 7cf013349941f7cb8509ee075d94f9099778c905..970977aab224909cb08be4045455514631653e9d 100644 (file)
@@ -2236,6 +2236,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                btrfs_wait_ordered_range(src, off, len);
        }
 
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, off,
+                                  ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
+
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
index babee65f8edaf779e26bc134ad7d02e8541ff8f2..786639fca067992f75f546e4fc68bc3f2ac2e4fb 100644 (file)
@@ -799,14 +799,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                                  struct extent_buffer *eb, int slot,
                                  struct btrfs_key *key)
 {
-       struct inode *dir;
-       int ret;
        struct btrfs_inode_ref *ref;
+       struct btrfs_dir_item *di;
+       struct inode *dir;
        struct inode *inode;
-       char *name;
-       int namelen;
        unsigned long ref_ptr;
        unsigned long ref_end;
+       char *name;
+       int namelen;
+       int ret;
        int search_done = 0;
 
        /*
@@ -909,6 +910,25 @@ again:
        }
        btrfs_release_path(path);
 
+       /* look for a conflicting sequence number */
+       di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
+                                        btrfs_inode_ref_index(eb, ref),
+                                        name, namelen, 0);
+       if (di && !IS_ERR(di)) {
+               ret = drop_one_dir_item(trans, root, path, dir, di);
+               BUG_ON(ret);
+       }
+       btrfs_release_path(path);
+
+       /* look for a conflicing name */
+       di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),
+                                  name, namelen, 0);
+       if (di && !IS_ERR(di)) {
+               ret = drop_one_dir_item(trans, root, path, dir, di);
+               BUG_ON(ret);
+       }
+       btrfs_release_path(path);
+
 insert:
        /* insert our name */
        ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
index 53875ae73ad4f634548e8d1d315056822c9cbd4b..f2a4cc79da61da62740d1de33552037f27b072a2 100644 (file)
@@ -142,6 +142,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        unsigned long limit;
        unsigned long last_waited = 0;
        int force_reg = 0;
+       int sync_pending = 0;
        struct blk_plug plug;
 
        /*
@@ -229,6 +230,22 @@ loop_lock:
 
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
 
+               /*
+                * if we're doing the sync list, record that our
+                * plug has some sync requests on it
+                *
+                * If we're doing the regular list and there are
+                * sync requests sitting around, unplug before
+                * we add more
+                */
+               if (pending_bios == &device->pending_sync_bios) {
+                       sync_pending = 1;
+               } else if (sync_pending) {
+                       blk_finish_plug(&plug);
+                       blk_start_plug(&plug);
+                       sync_pending = 0;
+               }
+
                submit_bio(cur->bi_rw, cur);
                num_run++;
                batch_run++;
@@ -500,6 +517,9 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                        fs_devices->rw_devices--;
                }
 
+               if (device->can_discard)
+                       fs_devices->num_can_discard--;
+
                new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
                BUG_ON(!new_device);
                memcpy(new_device, device, sizeof(*new_device));
@@ -508,6 +528,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                new_device->bdev = NULL;
                new_device->writeable = 0;
                new_device->in_fs_metadata = 0;
+               new_device->can_discard = 0;
                list_replace_rcu(&device->dev_list, &new_device->dev_list);
 
                call_rcu(&device->rcu, free_device);
@@ -547,6 +568,7 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                                fmode_t flags, void *holder)
 {
+       struct request_queue *q;
        struct block_device *bdev;
        struct list_head *head = &fs_devices->devices;
        struct btrfs_device *device;
@@ -603,6 +625,12 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        seeding = 0;
                }
 
+               q = bdev_get_queue(bdev);
+               if (blk_queue_discard(q)) {
+                       device->can_discard = 1;
+                       fs_devices->num_can_discard++;
+               }
+
                device->bdev = bdev;
                device->in_fs_metadata = 0;
                device->mode = flags;
@@ -835,6 +863,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
 
        max_hole_start = search_start;
        max_hole_size = 0;
+       hole_size = 0;
 
        if (search_start >= search_end) {
                ret = -ENOSPC;
@@ -917,7 +946,14 @@ next:
                cond_resched();
        }
 
-       hole_size = search_end- search_start;
+       /*
+        * At this point, search_start should be the end of
+        * allocated dev extents, and when shrinking the device,
+        * search_end may be smaller than search_start.
+        */
+       if (search_end > search_start)
+               hole_size = search_end - search_start;
+
        if (hole_size > max_hole_size) {
                max_hole_start = search_start;
                max_hole_size = hole_size;
@@ -1543,6 +1579,7 @@ error:
 
 int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 {
+       struct request_queue *q;
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device;
        struct block_device *bdev;
@@ -1612,6 +1649,9 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        lock_chunks(root);
 
+       q = bdev_get_queue(bdev);
+       if (blk_queue_discard(q))
+               device->can_discard = 1;
        device->writeable = 1;
        device->work.func = pending_bios_fn;
        generate_random_uuid(device->uuid);
@@ -1647,6 +1687,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        root->fs_info->fs_devices->num_devices++;
        root->fs_info->fs_devices->open_devices++;
        root->fs_info->fs_devices->rw_devices++;
+       if (device->can_discard)
+               root->fs_info->fs_devices->num_can_discard++;
        root->fs_info->fs_devices->total_rw_bytes += device->total_bytes;
 
        if (!blk_queue_nonrot(bdev_get_queue(bdev)))
@@ -2413,9 +2455,10 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                        total_avail = device->total_bytes - device->bytes_used;
                else
                        total_avail = 0;
-               /* avail is off by max(alloc_start, 1MB), but that is the same
-                * for all devices, so it doesn't hurt the sorting later on
-                */
+
+               /* If there is no space on this device, skip it. */
+               if (total_avail == 0)
+                       continue;
 
                ret = find_free_dev_extent(trans, device,
                                           max_stripe_size * dev_stripes,
index 7c12d61ae7aed7936d07886d8abfb4a8028dea4b..6d866db4e1774ab08e73b8f6c5ad6d8aaa08861b 100644 (file)
@@ -48,6 +48,7 @@ struct btrfs_device {
        int writeable;
        int in_fs_metadata;
        int missing;
+       int can_discard;
 
        spinlock_t io_lock;
 
@@ -104,6 +105,7 @@ struct btrfs_fs_devices {
        u64 rw_devices;
        u64 missing_devices;
        u64 total_rw_bytes;
+       u64 num_can_discard;
        struct block_device *latest_bdev;
 
        /* all of the devices in the FS, protected by a mutex
index 2fe3cf13b2e92b968221703f0d462a94c834ca29..6d40656e1e2994ad4fedbdcb9645b2367dbce3b7 100644 (file)
@@ -176,7 +176,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
-                               atomic_read(&server->inSend),
+                               atomic_read(&server->in_send),
                                atomic_read(&server->num_waiters));
 #endif
 
index 21de1d6d5849e21977ce9c23bb480439693f2d1e..d0f59faefb7893f2189cca07e660fb424bd3d629 100644 (file)
@@ -991,24 +991,6 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        return pntsd;
 }
 
-static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
-               struct cifs_ntsd *pnntsd, u32 acllen)
-{
-       int xid, rc;
-       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
-
-       if (IS_ERR(tlink))
-               return PTR_ERR(tlink);
-
-       xid = GetXid();
-       rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
-       FreeXid(xid);
-       cifs_put_tlink(tlink);
-
-       cFYI(DBG2, "SetCIFSACL rc = %d", rc);
-       return rc;
-}
-
 static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
                struct cifs_ntsd *pnntsd, u32 acllen)
 {
@@ -1047,18 +1029,10 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
                                struct inode *inode, const char *path)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsFileInfo *open_file;
-       int rc;
 
        cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
 
-       open_file = find_readable_file(CIFS_I(inode), true);
-       if (!open_file)
-               return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
-
-       rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
-       cifsFileInfo_put(open_file);
-       return rc;
+       return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
index cb71dc1f94d1e38dc042bf79e68614032553486a..95da8027983d2a6b47b7eecafb18da75e8335249 100644 (file)
@@ -125,5 +125,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "1.74"
+#define CIFS_VERSION   "1.75"
 #endif                         /* _CIFSFS_H */
index 38ce6d44b1451ef420bc7e233b1afac107b7b932..95dad9d14cf10211156e1896c0e97d270d76ab2f 100644 (file)
@@ -291,7 +291,7 @@ struct TCP_Server_Info {
        struct fscache_cookie   *fscache; /* client index cache cookie */
 #endif
 #ifdef CONFIG_CIFS_STATS2
-       atomic_t inSend; /* requests trying to send */
+       atomic_t in_send; /* requests trying to send */
        atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
 #endif
 };
@@ -672,12 +672,54 @@ struct mid_q_entry {
        bool multiEnd:1;        /* both received */
 };
 
-struct oplock_q_entry {
-       struct list_head qhead;
-       struct inode *pinode;
-       struct cifs_tcon *tcon;
-       __u16 netfid;
-};
+/*     Make code in transport.c a little cleaner by moving
+       update of optional stats into function below */
+#ifdef CONFIG_CIFS_STATS2
+
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->in_send);
+}
+
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->in_send);
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->num_waiters);
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->num_waiters);
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+       mid->when_sent = jiffies;
+}
+#else
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+}
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+}
+#endif
 
 /* for pending dnotify requests */
 struct dir_notify_req {
index 80c2e3add3a2714748336560b249b77e348c4278..633c246b67752efe0f7460cb01e8ac62309314e8 100644 (file)
@@ -2878,7 +2878,8 @@ cleanup_volume_info_contents(struct smb_vol *volume_info)
        kfree(volume_info->username);
        kzfree(volume_info->password);
        kfree(volume_info->UNC);
-       kfree(volume_info->UNCip);
+       if (volume_info->UNCip != volume_info->UNC + 2)
+               kfree(volume_info->UNCip);
        kfree(volume_info->domainname);
        kfree(volume_info->iocharset);
        kfree(volume_info->prepath);
index ae576fbb5142e508010d53d1506b72fd954575e7..72d448bf96ce57d8f6ed770277da46a3e3d7ace4 100644 (file)
@@ -105,8 +105,8 @@ cifs_bp_rename_retry:
        }
        rcu_read_unlock();
        if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
-               cERROR(1, "did not end path lookup where expected namelen is %d",
-                       namelen);
+               cFYI(1, "did not end path lookup where expected. namelen=%d "
+                       "dfsplen=%d", namelen, dfsplen);
                /* presumably this is only possible if racing with a rename
                of one of the parent directories  (we can not lock the dentries
                above us to prevent this, but retrying should be harmless) */
index c1b9c4b107398bd31504f594f294c5bb6dc7ef60..10ca6b2c26b7ff939e286b08533420b7cca1a539 100644 (file)
@@ -266,15 +266,11 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
        while (1) {
                if (atomic_read(&server->inFlight) >= cifs_max_pending) {
                        spin_unlock(&GlobalMid_Lock);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_inc(&server->num_waiters);
-#endif
+                       cifs_num_waiters_inc(server);
                        wait_event(server->request_q,
                                   atomic_read(&server->inFlight)
                                     < cifs_max_pending);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_dec(&server->num_waiters);
-#endif
+                       cifs_num_waiters_dec(server);
                        spin_lock(&GlobalMid_Lock);
                } else {
                        if (server->tcpStatus == CifsExiting) {
@@ -381,15 +377,13 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid->callback = callback;
        mid->callback_data = cbdata;
        mid->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&server->inSend);
-#endif
+
+       cifs_in_send_inc(server);
        rc = smb_sendv(server, iov, nvec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&server->inSend);
-       mid->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(server);
+       cifs_save_when_sent(mid);
        mutex_unlock(&server->srv_mutex);
+
        if (rc)
                goto out_err;
 
@@ -575,14 +569,10 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_sendv(ses->server, iov, n_vec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
 
        mutex_unlock(&ses->server->srv_mutex);
 
@@ -703,14 +693,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0)
@@ -843,14 +830,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0) {
index bb85757689b6af513dd556559a407049a1fc9782..5802fa1dab18f4a8aac358bd79f3ae92109daf02 100644 (file)
@@ -289,10 +289,10 @@ static inline int ext4_should_order_data(struct inode *inode)
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-       if (!S_ISREG(inode->i_mode))
-               return 0;
        if (EXT4_JOURNAL(inode) == NULL)
                return 1;
+       if (!S_ISREG(inode->i_mode))
+               return 0;
        if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
                return 0;
        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
index b8602cde5b5af7d11f2fe3e62cc88661b8fc52b9..0962642119c0475953fc70da38a5ed9bbea417a2 100644 (file)
@@ -800,12 +800,17 @@ ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
        }
 
 retry:
-       if (rw == READ && ext4_should_dioread_nolock(inode))
+       if (rw == READ && ext4_should_dioread_nolock(inode)) {
+               if (unlikely(!list_empty(&ei->i_completed_io_list))) {
+                       mutex_lock(&inode->i_mutex);
+                       ext4_flush_completed_IO(inode);
+                       mutex_unlock(&inode->i_mutex);
+               }
                ret = __blockdev_direct_IO(rw, iocb, inode,
                                 inode->i_sb->s_bdev, iov,
                                 offset, nr_segs,
                                 ext4_get_block, NULL, NULL, 0);
-       else {
+       else {
                ret = blockdev_direct_IO(rw, iocb, inode, iov,
                                 offset, nr_segs, ext4_get_block);
 
index d47264cafee00e2f95e90460d67c42c2bc1d7656..c4da98a959ae06deb04e25663ce8b697b0b31458 100644 (file)
@@ -120,6 +120,12 @@ void ext4_evict_inode(struct inode *inode)
        int err;
 
        trace_ext4_evict_inode(inode);
+
+       mutex_lock(&inode->i_mutex);
+       ext4_flush_completed_IO(inode);
+       mutex_unlock(&inode->i_mutex);
+       ext4_ioend_wait(inode);
+
        if (inode->i_nlink) {
                /*
                 * When journalling data dirty buffers are tracked only in the
@@ -983,6 +989,8 @@ static int ext4_journalled_write_end(struct file *file,
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
 
+       BUG_ON(!ext4_handle_valid(handle));
+
        if (copied < len) {
                if (!PageUptodate(page))
                        copied = 0;
@@ -1283,7 +1291,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                        else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT))
                                err = ext4_bio_write_page(&io_submit, page,
                                                          len, mpd->wbc);
-                       else
+                       else if (buffer_uninit(page_bufs)) {
+                               ext4_set_bh_endio(page_bufs, inode);
+                               err = block_write_full_page_endio(page,
+                                       noalloc_get_block_write,
+                                       mpd->wbc, ext4_end_io_buffer_write);
+                       } else
                                err = block_write_full_page(page,
                                        noalloc_get_block_write, mpd->wbc);
 
@@ -1699,6 +1712,8 @@ static int __ext4_journalled_writepage(struct page *page,
                goto out;
        }
 
+       BUG_ON(!ext4_handle_valid(handle));
+
        ret = walk_page_buffers(handle, page_bufs, 0, len, NULL,
                                do_journal_get_write_access);
 
@@ -2668,8 +2683,15 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
                goto out;
        }
 
-       io_end->flag = EXT4_IO_END_UNWRITTEN;
+       /*
+        * It may be over-defensive here to check EXT4_IO_END_UNWRITTEN now,
+        * but being more careful is always safe for the future change.
+        */
        inode = io_end->inode;
+       if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+               io_end->flag |= EXT4_IO_END_UNWRITTEN;
+               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
index 430c401d089514b6297d5ad88ea2d3c00b9dbb7b..78839af7ce29303118a590381dc7eda9a350f15c 100644 (file)
@@ -334,8 +334,10 @@ submit_and_retry:
        if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
            (io_end->pages[io_end->num_io_pages-1] != io_page))
                goto submit_and_retry;
-       if (buffer_uninit(bh))
-               io->io_end->flag |= EXT4_IO_END_UNWRITTEN;
+       if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+               io_end->flag |= EXT4_IO_END_UNWRITTEN;
+               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+       }
        io->io_end->size += bh->b_size;
        io->io_next_block++;
        ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
index 4687fea0c00f24498ff58c80e7d39d9c086bd62a..44d0c8db2239f958d08d4de4462cdc6ca936d1e1 100644 (file)
@@ -919,7 +919,6 @@ static void ext4_i_callback(struct rcu_head *head)
 
 static void ext4_destroy_inode(struct inode *inode)
 {
-       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
index 4ad64732cbced5460d238d637f54f596e4ab0a07..5efbd5d7701a1d63721f646958d92f36830807f0 100644 (file)
@@ -1231,7 +1231,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
        struct super_block *sb = dir->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
-       struct msdos_dir_entry *de;
+       struct msdos_dir_entry *uninitialized_var(de);
        int err, free_slots, i, nr_bhs;
        loff_t pos, i_pos;
 
index 5942fec22c65ddacec9efd25467ae039784884c6..1726d7303047e1966bc4991b5264113a2dcb7a0d 100644 (file)
@@ -1188,9 +1188,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 out:
        /* UTF-8 doesn't provide FAT semantics */
        if (!strcmp(opts->iocharset, "utf8")) {
-               fat_msg(sb, KERN_ERR, "utf8 is not a recommended IO charset"
+               fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
                       " for FAT filesystems, filesystem will be "
-                      "case sensitive!\n");
+                      "case sensitive!");
        }
 
        /* If user doesn't specify allow_utime, it's initialized from dmask. */
@@ -1367,6 +1367,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->free_clusters = -1;        /* Don't know yet */
        sbi->free_clus_valid = 0;
        sbi->prev_free = FAT_START_ENT;
+       sb->s_maxbytes = 0xffffffff;
 
        if (!sbi->fat_length && b->fat32_length) {
                struct fat_boot_fsinfo *fsinfo;
@@ -1377,8 +1378,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
                sbi->fat_length = le32_to_cpu(b->fat32_length);
                sbi->root_cluster = le32_to_cpu(b->root_cluster);
 
-               sb->s_maxbytes = 0xffffffff;
-
                /* MC - if info_sector is 0, don't multiply by 0 */
                sbi->fsinfo_sector = le16_to_cpu(b->info_sector);
                if (sbi->fsinfo_sector == 0)
index adcf92d3b6035f0396f4a3428aa91f0fddae1055..7971f37534a359e0dcfed248cb56e56a14c7fac7 100644 (file)
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
                /*
                 * Wait for outstanding transactions to be written to log:
                 */
-               jfs_flush_journal(log, 1);
+               jfs_flush_journal(log, 2);
 
        /*
         * close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
         *
         * remove file system from log active file system list.
         */
-       jfs_flush_journal(log, 1);
+       jfs_flush_journal(log, 2);
 
        /*
         * Make sure all metadata makes it to disk
index e56564d2ef95a37608106fb439723ff3e3c1e90d..9561c8fc8bdb6d7fed807d94f6cb5c2e3bb52276 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/namei.h>
 #include <linux/bio.h>         /* struct bio */
 #include <linux/buffer_head.h> /* various write calls */
+#include <linux/prefetch.h>
 
 #include "blocklayout.h"
 
index b257383bb565a1331a68197a53d45545d436225e..07df5f1d85e5188b16d51f13049dd925870b5238 100644 (file)
@@ -38,6 +38,7 @@ enum nfs4_callback_opnum {
 struct cb_process_state {
        __be32                  drc_status;
        struct nfs_client       *clp;
+       int                     slotid;
 };
 
 struct cb_compound_hdr_arg {
@@ -166,7 +167,6 @@ extern unsigned nfs4_callback_layoutrecall(
        void *dummy, struct cb_process_state *cps);
 
 extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
-extern void nfs4_cb_take_slot(struct nfs_client *clp);
 
 struct cb_devicenotifyitem {
        uint32_t                cbd_notify_type;
index 74780f9f852c6d3c5a01d71c3e2461ace4322963..43926add945b0a4a88625b23062e1cdd393a743d 100644 (file)
@@ -348,7 +348,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
        /* Normal */
        if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
                slot->seq_nr++;
-               return htonl(NFS4_OK);
+               goto out_ok;
        }
 
        /* Replay */
@@ -367,11 +367,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
        /* Wraparound */
        if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
                slot->seq_nr = 1;
-               return htonl(NFS4_OK);
+               goto out_ok;
        }
 
        /* Misordered request */
        return htonl(NFS4ERR_SEQ_MISORDERED);
+out_ok:
+       tbl->highest_used_slotid = args->csa_slotid;
+       return htonl(NFS4_OK);
 }
 
 /*
@@ -433,26 +436,37 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
                              struct cb_sequenceres *res,
                              struct cb_process_state *cps)
 {
+       struct nfs4_slot_table *tbl;
        struct nfs_client *clp;
        int i;
        __be32 status = htonl(NFS4ERR_BADSESSION);
 
-       cps->clp = NULL;
-
        clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
        if (clp == NULL)
                goto out;
 
+       tbl = &clp->cl_session->bc_slot_table;
+
+       spin_lock(&tbl->slot_tbl_lock);
        /* state manager is resetting the session */
        if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) {
-               status = NFS4ERR_DELAY;
+               spin_unlock(&tbl->slot_tbl_lock);
+               status = htonl(NFS4ERR_DELAY);
+               /* Return NFS4ERR_BADSESSION if we're draining the session
+                * in order to reset it.
+                */
+               if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
+                       status = htonl(NFS4ERR_BADSESSION);
                goto out;
        }
 
        status = validate_seqid(&clp->cl_session->bc_slot_table, args);
+       spin_unlock(&tbl->slot_tbl_lock);
        if (status)
                goto out;
 
+       cps->slotid = args->csa_slotid;
+
        /*
         * Check for pending referring calls.  If a match is found, a
         * related callback was received before the response to the original
@@ -469,7 +483,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
        res->csr_slotid = args->csa_slotid;
        res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
-       nfs4_cb_take_slot(clp);
 
 out:
        cps->clp = clp; /* put in nfs4_callback_compound */
index c6c86a77e043fe938c40df750314116b8a3fcbb0..918ad647afeaf4fe62840ea8d3146bb6ed87f406 100644 (file)
@@ -754,26 +754,15 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
         * Let the state manager know callback processing done.
         * A single slot, so highest used slotid is either 0 or -1
         */
-       tbl->highest_used_slotid--;
+       tbl->highest_used_slotid = -1;
        nfs4_check_drain_bc_complete(session);
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
-       if (clp && clp->cl_session)
-               nfs4_callback_free_slot(clp->cl_session);
-}
-
-/* A single slot, so highest used slotid is either 0 or -1 */
-void nfs4_cb_take_slot(struct nfs_client *clp)
-{
-       struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       tbl->highest_used_slotid++;
-       BUG_ON(tbl->highest_used_slotid != 0);
-       spin_unlock(&tbl->slot_tbl_lock);
+       if (cps->slotid != -1)
+               nfs4_callback_free_slot(cps->clp->cl_session);
 }
 
 #else /* CONFIG_NFS_V4_1 */
@@ -784,7 +773,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
        return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 }
 
-static void nfs4_cb_free_slot(struct nfs_client *clp)
+static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
 }
 #endif /* CONFIG_NFS_V4_1 */
@@ -866,6 +855,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        struct cb_process_state cps = {
                .drc_status = 0,
                .clp = NULL,
+               .slotid = -1,
        };
        unsigned int nops = 0;
 
@@ -906,7 +896,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 
        *hdr_res.status = status;
        *hdr_res.nops = htonl(nops);
-       nfs4_cb_free_slot(cps.clp);
+       nfs4_cb_free_slot(&cps);
        nfs_put_client(cps.clp);
        dprintk("%s: done, status = %u\n", __func__, ntohl(status));
        return rpc_success;
index 9383ca7245bc7f3ef5a5eeeb9a3b64248f933079..d0cda12fddc325c104ff643455ebae50afbb1ac9 100644 (file)
@@ -479,7 +479,6 @@ static int _io_check(struct objio_state *ios, bool is_write)
        for (i = 0; i <  ios->numdevs; i++) {
                struct osd_sense_info osi;
                struct osd_request *or = ios->per_dev[i].or;
-               unsigned dev;
                int ret;
 
                if (!or)
@@ -500,9 +499,8 @@ static int _io_check(struct objio_state *ios, bool is_write)
 
                        continue; /* we recovered */
                }
-               dev = ios->per_dev[i].dev;
-               objlayout_io_set_result(&ios->ol_state, dev,
-                                       &ios->layout->comps[dev].oc_object_id,
+               objlayout_io_set_result(&ios->ol_state, i,
+                                       &ios->layout->comps[i].oc_object_id,
                                        osd_pri_2_pnfs_err(osi.osd_err_pri),
                                        ios->per_dev[i].offset,
                                        ios->per_dev[i].length,
@@ -589,22 +587,19 @@ static void _calc_stripe_info(struct objio_state *ios, u64 file_offset,
 }
 
 static int _add_stripe_unit(struct objio_state *ios,  unsigned *cur_pg,
-               unsigned pgbase, struct _objio_per_comp *per_dev, int cur_len,
+               unsigned pgbase, struct _objio_per_comp *per_dev, int len,
                gfp_t gfp_flags)
 {
        unsigned pg = *cur_pg;
+       int cur_len = len;
        struct request_queue *q =
                        osd_request_queue(_io_od(ios, per_dev->dev));
 
-       per_dev->length += cur_len;
-
        if (per_dev->bio == NULL) {
-               unsigned stripes = ios->layout->num_comps /
-                                                    ios->layout->mirrors_p1;
-               unsigned pages_in_stripe = stripes *
+               unsigned pages_in_stripe = ios->layout->group_width *
                                      (ios->layout->stripe_unit / PAGE_SIZE);
                unsigned bio_size = (ios->ol_state.nr_pages + pages_in_stripe) /
-                                   stripes;
+                                   ios->layout->group_width;
 
                if (BIO_MAX_PAGES_KMALLOC < bio_size)
                        bio_size = BIO_MAX_PAGES_KMALLOC;
@@ -632,6 +627,7 @@ static int _add_stripe_unit(struct objio_state *ios,  unsigned *cur_pg,
        }
        BUG_ON(cur_len);
 
+       per_dev->length += len;
        *cur_pg = pg;
        return 0;
 }
@@ -650,7 +646,7 @@ static int _prepare_one_group(struct objio_state *ios, u64 length,
        int ret = 0;
 
        while (length) {
-               struct _objio_per_comp *per_dev = &ios->per_dev[dev];
+               struct _objio_per_comp *per_dev = &ios->per_dev[dev - first_dev];
                unsigned cur_len, page_off = 0;
 
                if (!per_dev->length) {
@@ -670,8 +666,8 @@ static int _prepare_one_group(struct objio_state *ios, u64 length,
                                cur_len = stripe_unit;
                        }
 
-                       if (max_comp < dev)
-                               max_comp = dev;
+                       if (max_comp < dev - first_dev)
+                               max_comp = dev - first_dev;
                } else {
                        cur_len = stripe_unit;
                }
@@ -806,7 +802,7 @@ static int _read_mirrors(struct objio_state *ios, unsigned cur_comp)
        struct _objio_per_comp *per_dev = &ios->per_dev[cur_comp];
        unsigned dev = per_dev->dev;
        struct pnfs_osd_object_cred *cred =
-                       &ios->layout->comps[dev];
+                       &ios->layout->comps[cur_comp];
        struct osd_obj_id obj = {
                .partition = cred->oc_object_id.oid_partition_id,
                .id = cred->oc_object_id.oid_object_id,
@@ -904,7 +900,7 @@ static int _write_mirrors(struct objio_state *ios, unsigned cur_comp)
        for (; cur_comp < last_comp; ++cur_comp, ++dev) {
                struct osd_request *or = NULL;
                struct pnfs_osd_object_cred *cred =
-                                       &ios->layout->comps[dev];
+                                       &ios->layout->comps[cur_comp];
                struct osd_obj_id obj = {
                        .partition = cred->oc_object_id.oid_partition_id,
                        .id = cred->oc_object_id.oid_object_id,
index 16fc758e91233a7c931cdda1d05148ad8dc5ae44..b3918f7ac34d0eaa0f778fa0bb170fe5dedddcfe 100644 (file)
@@ -170,6 +170,9 @@ int pnfs_osd_xdr_decode_layout_map(struct pnfs_osd_layout *layout,
        p = _osd_xdr_decode_data_map(p, &layout->olo_map);
        layout->olo_comps_index = be32_to_cpup(p++);
        layout->olo_num_comps = be32_to_cpup(p++);
+       dprintk("%s: olo_comps_index=%d olo_num_comps=%d\n", __func__,
+               layout->olo_comps_index, layout->olo_num_comps);
+
        iter->total_comps = layout->olo_num_comps;
        return 0;
 }
index fb2d63f13f4c0aa7d5caf5d2bce8171f22f5b07b..aea9e45efce63572eee4daafc2ecfffcdd104b6e 100644 (file)
@@ -39,7 +39,7 @@
 })
 
 #define __page_to_pfn(pg)                                              \
-({     struct page *__pg = (pg);                                       \
+({     const struct page *__pg = (pg);                                 \
        struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));     \
        (unsigned long)(__pg - __pgdat->node_mem_map) +                 \
         __pgdat->node_start_pfn;                                       \
@@ -57,7 +57,7 @@
  * section[i].section_mem_map == mem_map's address - start_pfn;
  */
 #define __page_to_pfn(pg)                                      \
-({     struct page *__pg = (pg);                               \
+({     const struct page *__pg = (pg);                         \
        int __sec = page_to_section(__pg);                      \
        (unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec))); \
 })
index 6395692b2e7a9dec9725dcf42dbf244585f7c83e..32f0076e844b7da4768a709b95a4bba1b135195d 100644 (file)
@@ -125,7 +125,11 @@ enum rq_flag_bits {
        __REQ_SYNC,             /* request is sync (sync write or read) */
        __REQ_META,             /* metadata io request */
        __REQ_DISCARD,          /* request to discard sectors */
+       __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
+
        __REQ_NOIDLE,           /* don't anticipate more IO after this one */
+       __REQ_FUA,              /* forced unit access */
+       __REQ_FLUSH,            /* request for cache flush */
 
        /* bio only flags */
        __REQ_RAHEAD,           /* read ahead, can fail anytime */
@@ -135,7 +139,6 @@ enum rq_flag_bits {
        /* request only flags */
        __REQ_SORTED,           /* elevator knows about this request */
        __REQ_SOFTBARRIER,      /* may not be passed by ioscheduler */
-       __REQ_FUA,              /* forced unit access */
        __REQ_NOMERGE,          /* don't touch this for merging */
        __REQ_STARTED,          /* drive already may have started this one */
        __REQ_DONTPREP,         /* don't call prep for this one */
@@ -146,11 +149,9 @@ enum rq_flag_bits {
        __REQ_PREEMPT,          /* set for "ide_preempt" requests */
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_COPY_USER,        /* contains copies of user pages */
-       __REQ_FLUSH,            /* request for cache flush */
        __REQ_FLUSH_SEQ,        /* request for flush sequence */
        __REQ_IO_STAT,          /* account I/O stat */
        __REQ_MIXED_MERGE,      /* merge of different types, fail separately */
-       __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
        __REQ_NR_BITS,          /* stops here */
 };
 
index 0e67c45b3bc95ec70c38836cd8801bb4e568f804..84b15d54f8c23887aef4600dd6f87fed0a99104e 100644 (file)
@@ -30,6 +30,7 @@ struct request_pm_state;
 struct blk_trace;
 struct request;
 struct sg_io_hdr;
+struct bsg_job;
 
 #define BLKDEV_MIN_RQ  4
 #define BLKDEV_MAX_RQ  128     /* Default maximum */
@@ -117,6 +118,7 @@ struct request {
                struct {
                        unsigned int            seq;
                        struct list_head        list;
+                       rq_end_io_fn            *saved_end_io;
                } flush;
        };
 
@@ -209,6 +211,7 @@ typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *,
 typedef void (softirq_done_fn)(struct request *);
 typedef int (dma_drain_needed_fn)(struct request *);
 typedef int (lld_busy_fn) (struct request_queue *q);
+typedef int (bsg_job_fn) (struct bsg_job *);
 
 enum blk_eh_timer_return {
        BLK_EH_NOT_HANDLED,
@@ -375,6 +378,8 @@ struct request_queue {
        struct mutex            sysfs_lock;
 
 #if defined(CONFIG_BLK_DEV_BSG)
+       bsg_job_fn              *bsg_job_fn;
+       int                     bsg_job_size;
        struct bsg_class_device bsg_dev;
 #endif
 
index 8c7c2de7631a6fb59ab8f4e86334516a7f07e7d1..8e9e4bc6d73b4b5351748afca97a2b4a43b66654 100644 (file)
@@ -14,7 +14,7 @@
 enum blktrace_cat {
        BLK_TC_READ     = 1 << 0,       /* reads */
        BLK_TC_WRITE    = 1 << 1,       /* writes */
-       BLK_TC_BARRIER  = 1 << 2,       /* barrier */
+       BLK_TC_FLUSH    = 1 << 2,       /* flush */
        BLK_TC_SYNC     = 1 << 3,       /* sync IO */
        BLK_TC_SYNCIO   = BLK_TC_SYNC,
        BLK_TC_QUEUE    = 1 << 4,       /* queueing/merging */
@@ -28,8 +28,9 @@ enum blktrace_cat {
        BLK_TC_META     = 1 << 12,      /* metadata */
        BLK_TC_DISCARD  = 1 << 13,      /* discard requests */
        BLK_TC_DRV_DATA = 1 << 14,      /* binary per-driver data */
+       BLK_TC_FUA      = 1 << 15,      /* fua requests */
 
-       BLK_TC_END      = 1 << 15,      /* only 16-bits, reminder */
+       BLK_TC_END      = 1 << 15,      /* we've run out of bits! */
 };
 
 #define BLK_TC_SHIFT           (16)
diff --git a/include/linux/bsg-lib.h b/include/linux/bsg-lib.h
new file mode 100644 (file)
index 0000000..f55ab8c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  BSG helper library
+ *
+ *  Copyright (C) 2008   James Smart, Emulex Corporation
+ *  Copyright (C) 2011   Red Hat, Inc.  All rights reserved.
+ *  Copyright (C) 2011   Mike Christie
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _BLK_BSG_
+#define _BLK_BSG_
+
+#include <linux/blkdev.h>
+
+struct request;
+struct device;
+struct scatterlist;
+struct request_queue;
+
+struct bsg_buffer {
+       unsigned int payload_len;
+       int sg_cnt;
+       struct scatterlist *sg_list;
+};
+
+struct bsg_job {
+       struct device *dev;
+       struct request *req;
+
+       /* Transport/driver specific request/reply structs */
+       void *request;
+       void *reply;
+
+       unsigned int request_len;
+       unsigned int reply_len;
+       /*
+        * On entry : reply_len indicates the buffer size allocated for
+        * the reply.
+        *
+        * Upon completion : the message handler must set reply_len
+        *  to indicates the size of the reply to be returned to the
+        *  caller.
+        */
+
+       /* DMA payloads for the request/response */
+       struct bsg_buffer request_payload;
+       struct bsg_buffer reply_payload;
+
+       void *dd_data;          /* Used for driver-specific storage */
+};
+
+void bsg_job_done(struct bsg_job *job, int result,
+                 unsigned int reply_payload_rcv_len);
+int bsg_setup_queue(struct device *dev, struct request_queue *q, char *name,
+                   bsg_job_fn *job_fn, int dd_job_size);
+void bsg_request_fn(struct request_queue *q);
+void bsg_remove_queue(struct request_queue *q);
+void bsg_goose_queue(struct request_queue *q);
+
+#endif
index 06d25c189cc5679d0933747efa4a00b9758a4dca..b80506bdd733ee181f202ddb6322529d42299d1b 100644 (file)
@@ -63,7 +63,7 @@ static inline u32 hash_32(u32 val, unsigned int bits)
        return hash >> (32 - bits);
 }
 
-static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
+static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
 }
index 87a06f345bd2c5820e61ec5a5f9e4d5a77e55d77..59517300a315978e6f41398dc69a6a4f84c0f19e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/topology.h>
 #include <linux/wait.h>
+#include <linux/module.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -547,7 +548,15 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
        return d->msi_desc;
 }
 
-int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
+int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+               struct module *owner);
+
+static inline int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt,
+               int node)
+{
+       return __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE);
+}
+
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
 
index 2d921b35212c42bbac394430b50fd90914439e24..150134ac709ab28372eb874f9afed2741f150988 100644 (file)
@@ -66,6 +66,7 @@ struct irq_desc {
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *dir;
 #endif
+       struct module           *owner;
        const char              *name;
 } ____cacheline_internodealigned_in_smp;
 
index 66c194e2d9b9c072fc201b864506ae12c010112d..683d698901198935d12370c82dbdcb8e0b90cb0e 100644 (file)
@@ -64,7 +64,6 @@ struct loop_device {
 
        struct request_queue    *lo_queue;
        struct gendisk          *lo_disk;
-       struct list_head        lo_list;
 };
 
 #endif /* __KERNEL__ */
@@ -161,4 +160,8 @@ int loop_unregister_transfer(int number);
 #define LOOP_CHANGE_FD         0x4C06
 #define LOOP_SET_CAPACITY      0x4C07
 
+/* /dev/loop-control interface */
+#define LOOP_CTL_ADD           0x4C80
+#define LOOP_CTL_REMOVE                0x4C81
+#define LOOP_CTL_GET_FREE      0x4C82
 #endif
index 18fd13028ba1aab8207a1baa9c5b1527435d3a01..c309b1ecdc1c8b089725258cce9613e5ff7d9bbc 100644 (file)
@@ -40,6 +40,7 @@
 #define BTRFS_MINOR            234
 #define AUTOFS_MINOR           235
 #define MAPPER_CTRL_MINOR      236
+#define LOOP_CTRL_MINOR                237
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index fd599f4bb84611df04ff505b794bae4ed77a53ee..7438071b44aa7d3c5f12a60824941de05940eb42 100644 (file)
@@ -685,7 +685,7 @@ static inline void set_page_section(struct page *page, unsigned long section)
        page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
 }
 
-static inline unsigned long page_to_section(struct page *page)
+static inline unsigned long page_to_section(const struct page *page)
 {
        return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
 }
@@ -720,7 +720,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
 
 static __always_inline void *lowmem_page_address(const struct page *page)
 {
-       return __va(PFN_PHYS(page_to_pfn((struct page *)page)));
+       return __va(PFN_PHYS(page_to_pfn(page)));
 }
 
 #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
@@ -737,7 +737,7 @@ static __always_inline void *lowmem_page_address(const struct page *page)
 #endif
 
 #if defined(HASHED_PAGE_VIRTUAL)
-void *page_address(struct page *page);
+void *page_address(const struct page *page);
 void set_page_address(struct page *page, void *virtual);
 void page_address_init(void);
 #endif
index f27893b3b724205b3411e9081b99b4ca8e4429c2..8c230cbcbb486dd7cafb28cce85a1b0ee76a4995 100644 (file)
@@ -251,7 +251,8 @@ struct pci_dev {
        u8              revision;       /* PCI revision, low byte of class word */
        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */
        u8              pcie_cap;       /* PCI-E capability offset */
-       u8              pcie_type;      /* PCI-E device/port type */
+       u8              pcie_type:4;    /* PCI-E device/port type */
+       u8              pcie_mpss:3;    /* PCI-E Max Payload Size Supported */
        u8              rom_base_reg;   /* which config register controls the ROM */
        u8              pin;            /* which interrupt pin this device uses */
 
@@ -617,6 +618,16 @@ struct pci_driver {
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
+extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+
+enum pcie_bus_config_types {
+       PCIE_BUS_PERFORMANCE,
+       PCIE_BUS_SAFE,
+       PCIE_BUS_PEER2PEER,
+};
+
+extern enum pcie_bus_config_types pcie_bus_config;
+
 extern struct bus_type pci_bus_type;
 
 /* Do NOT directly access these two variables, unless you are arch specific pci
@@ -796,10 +807,13 @@ int pcix_get_mmrbc(struct pci_dev *dev);
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
 int pcie_get_readrq(struct pci_dev *dev);
 int pcie_set_readrq(struct pci_dev *dev, int rq);
+int pcie_get_mps(struct pci_dev *dev);
+int pcie_set_mps(struct pci_dev *dev, int mps);
 int __pci_reset_function(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
+int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
 int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 
 /* ROM control related routines */
index 21097cb086fe68c42d1be61f13c9d9c48d8802e8..f9ec1736a116a3f157d0abb49234be0597572c2c 100644 (file)
@@ -72,8 +72,6 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
-extern void pm_genpd_poweroff_unused(void);
-extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
 #else
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
                                      struct device *dev)
@@ -101,8 +99,14 @@ static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
        return -ENOSYS;
 }
-static inline void pm_genpd_poweroff_unused(void) {}
+#endif
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
+extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
+extern void pm_genpd_poweroff_unused(void);
+#else
 static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
+static inline void pm_genpd_poweroff_unused(void) {}
 #endif
 
 #endif /* _LINUX_PM_DOMAIN_H */
index b27ebea25660bff86dbdf2f86040f26904ab45c7..93f4d035076bc8f295fde5b0a6b5b89e4c5df9ff 100644 (file)
@@ -97,6 +97,9 @@ struct rtc_pll_info {
 #define RTC_AF 0x20    /* Alarm interrupt */
 #define RTC_UF 0x10    /* Update interrupt for 1Hz RTC */
 
+
+#define RTC_MAX_FREQ   8192
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
index bf366547da252077cf168522a1ff22735a10d3a5..05c5e61f0a7ca23b03a6a965a375323ea2b37036 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/blkdev.h>
 #include <linux/tracepoint.h>
 
+#define RWBS_LEN       8
+
 DECLARE_EVENT_CLASS(block_rq_with_error,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -19,7 +21,7 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                __field(  sector_t,     sector                  )
                __field(  unsigned int, nr_sector               )
                __field(  int,          errors                  )
-               __array(  char,         rwbs,   6               )
+               __array(  char,         rwbs,   RWBS_LEN        )
                __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
        ),
 
@@ -104,7 +106,7 @@ DECLARE_EVENT_CLASS(block_rq,
                __field(  sector_t,     sector                  )
                __field(  unsigned int, nr_sector               )
                __field(  unsigned int, bytes                   )
-               __array(  char,         rwbs,   6               )
+               __array(  char,         rwbs,   RWBS_LEN        )
                __array(  char,         comm,   TASK_COMM_LEN   )
                __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
        ),
@@ -183,7 +185,7 @@ TRACE_EVENT(block_bio_bounce,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
        ),
 
@@ -222,7 +224,7 @@ TRACE_EVENT(block_bio_complete,
                __field( sector_t,      sector          )
                __field( unsigned,      nr_sector       )
                __field( int,           error           )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
@@ -249,7 +251,7 @@ DECLARE_EVENT_CLASS(block_bio,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
        ),
 
@@ -321,7 +323,7 @@ DECLARE_EVENT_CLASS(block_get_rq,
                __field( dev_t,         dev                     )
                __field( sector_t,      sector                  )
                __field( unsigned int,  nr_sector               )
-               __array( char,          rwbs,   6               )
+               __array( char,          rwbs,   RWBS_LEN        )
                __array( char,          comm,   TASK_COMM_LEN   )
         ),
 
@@ -456,7 +458,7 @@ TRACE_EVENT(block_split,
                __field( dev_t,         dev                             )
                __field( sector_t,      sector                          )
                __field( sector_t,      new_sector                      )
-               __array( char,          rwbs,           6               )
+               __array( char,          rwbs,           RWBS_LEN        )
                __array( char,          comm,           TASK_COMM_LEN   )
        ),
 
@@ -498,7 +500,7 @@ TRACE_EVENT(block_bio_remap,
                __field( unsigned int,  nr_sector       )
                __field( dev_t,         old_dev         )
                __field( sector_t,      old_sector      )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
@@ -542,7 +544,7 @@ TRACE_EVENT(block_rq_remap,
                __field( unsigned int,  nr_sector       )
                __field( dev_t,         old_dev         )
                __field( sector_t,      old_sector      )
-               __array( char,          rwbs,   6       )
+               __array( char,          rwbs,   RWBS_LEN)
        ),
 
        TP_fast_assign(
index 3a2cab407b93fd77024c2dff4165034b04ca832f..e38544dddb18a143e2a63f2827a56e45f8b1aa53 100644 (file)
@@ -246,7 +246,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
                gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
 
        for (i = gc->irq_base; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                if (flags & IRQ_GC_INIT_NESTED_LOCK)
@@ -301,7 +301,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
        raw_spin_unlock(&gc_lock);
 
        for (; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                /* Remove handler first. That will mask the irq line */
index 4c60a50e66b237922381c5b0d0d82d55b436b6dc..039b889ea053abf0ac72cd77809490d202ad0121 100644 (file)
@@ -70,7 +70,8 @@ static inline void desc_smp_init(struct irq_desc *desc, int node) { }
 static inline int desc_node(struct irq_desc *desc) { return 0; }
 #endif
 
-static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
+static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
+               struct module *owner)
 {
        int cpu;
 
@@ -86,6 +87,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
        desc->name = NULL;
+       desc->owner = owner;
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
        desc_smp_init(desc, node);
@@ -128,7 +130,7 @@ static void free_masks(struct irq_desc *desc)
 static inline void free_masks(struct irq_desc *desc) { }
 #endif
 
-static struct irq_desc *alloc_desc(int irq, int node)
+static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
 {
        struct irq_desc *desc;
        gfp_t gfp = GFP_KERNEL;
@@ -147,7 +149,7 @@ static struct irq_desc *alloc_desc(int irq, int node)
        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
 
-       desc_set_defaults(irq, desc, node);
+       desc_set_defaults(irq, desc, node, owner);
 
        return desc;
 
@@ -173,13 +175,14 @@ static void free_desc(unsigned int irq)
        kfree(desc);
 }
 
-static int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                      struct module *owner)
 {
        struct irq_desc *desc;
        int i;
 
        for (i = 0; i < cnt; i++) {
-               desc = alloc_desc(start + i, node);
+               desc = alloc_desc(start + i, node, owner);
                if (!desc)
                        goto err;
                mutex_lock(&sparse_irq_lock);
@@ -227,7 +230,7 @@ int __init early_irq_init(void)
                nr_irqs = initcnt;
 
        for (i = 0; i < initcnt; i++) {
-               desc = alloc_desc(i, node);
+               desc = alloc_desc(i, node, NULL);
                set_bit(i, allocated_irqs);
                irq_insert_desc(i, desc);
        }
@@ -261,7 +264,7 @@ int __init early_irq_init(void)
                alloc_masks(&desc[i], GFP_KERNEL, node);
                raw_spin_lock_init(&desc[i].lock);
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               desc_set_defaults(i, &desc[i], node);
+               desc_set_defaults(i, &desc[i], node, NULL);
        }
        return arch_early_irq_init();
 }
@@ -276,8 +279,16 @@ static void free_desc(unsigned int irq)
        dynamic_irq_cleanup(irq);
 }
 
-static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                             struct module *owner)
 {
+       u32 i;
+
+       for (i = 0; i < cnt; i++) {
+               struct irq_desc *desc = irq_to_desc(start + i);
+
+               desc->owner = owner;
+       }
        return start;
 }
 
@@ -333,11 +344,13 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
  * @from:      Start the search from this irq number
  * @cnt:       Number of consecutive irqs to allocate.
  * @node:      Preferred node on which the irq descriptor should be allocated
+ * @owner:     Owning module (can be NULL)
  *
  * Returns the first irq number or error code
  */
 int __ref
-irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
+__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+                 struct module *owner)
 {
        int start, ret;
 
@@ -366,13 +379,13 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
 
        bitmap_set(allocated_irqs, start, cnt);
        mutex_unlock(&sparse_irq_lock);
-       return alloc_descs(start, cnt, node);
+       return alloc_descs(start, cnt, node, owner);
 
 err:
        mutex_unlock(&sparse_irq_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(irq_alloc_descs);
+EXPORT_SYMBOL_GPL(__irq_alloc_descs);
 
 /**
  * irq_reserve_irqs - mark irqs allocated
@@ -440,7 +453,7 @@ void dynamic_irq_cleanup(unsigned int irq)
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc_set_defaults(irq, desc, desc_node(desc));
+       desc_set_defaults(irq, desc, desc_node(desc), NULL);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
index 0a7840aeb0fb9efbc18a6e6e8e6f01de17ed91cd..2e9425889fa8874f742820b0f886f1cf0ee0a77c 100644 (file)
@@ -883,6 +883,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
        if (desc->irq_data.chip == &no_irq_chip)
                return -ENOSYS;
+       if (!try_module_get(desc->owner))
+               return -ENODEV;
        /*
         * Some drivers like serial.c use request_irq() heavily,
         * so we have to be careful not to interfere with a
@@ -906,8 +908,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        nested = irq_settings_is_nested_thread(desc);
        if (nested) {
-               if (!new->thread_fn)
-                       return -EINVAL;
+               if (!new->thread_fn) {
+                       ret = -EINVAL;
+                       goto out_mput;
+               }
                /*
                 * Replace the primary handler which was provided from
                 * the driver for non nested interrupt handling by the
@@ -929,8 +933,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
                t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                                   new->name);
-               if (IS_ERR(t))
-                       return PTR_ERR(t);
+               if (IS_ERR(t)) {
+                       ret = PTR_ERR(t);
+                       goto out_mput;
+               }
                /*
                 * We keep the reference to the task struct even if
                 * the thread dies to avoid that the interrupt code
@@ -1095,6 +1101,8 @@ out_thread:
                        kthread_stop(t);
                put_task_struct(t);
        }
+out_mput:
+       module_put(desc->owner);
        return ret;
 }
 
@@ -1203,6 +1211,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                put_task_struct(action->thread);
        }
 
+       module_put(desc->owner);
        return action;
 }
 
@@ -1322,6 +1331,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                if (!thread_fn)
                        return -EINVAL;
                handler = irq_default_primary_handler;
+               irqflags |= IRQF_ONESHOT;
        }
 
        action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
index 8c24294e477fe6578cb16ae8c3e270b0633cc6c7..91d67ce3a8d520a5cdc43d7abe6534c59710e79d 100644 (file)
@@ -3111,7 +3111,13 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
                if (!class)
                        class = look_up_lock_class(lock, 0);
 
-               if (DEBUG_LOCKS_WARN_ON(!class))
+               /*
+                * If look_up_lock_class() failed to find a class, we're trying
+                * to test if we hold a lock that has never yet been acquired.
+                * Clearly if the lock hasn't been acquired _ever_, we're not
+                * holding it either, so report failure.
+                */
+               if (!class)
                        return 0;
 
                if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock))
index b1914cb9095c98bfc9c95705c15e0c3e015820a4..3744c594b19b18b779b8d1f8660788a1e0aeacbf 100644 (file)
@@ -231,3 +231,7 @@ config PM_CLK
 config PM_GENERIC_DOMAINS
        bool
        depends on PM
+
+config PM_GENERIC_DOMAINS_RUNTIME
+       def_bool y
+       depends on PM_RUNTIME && PM_GENERIC_DOMAINS
index 6957aa298dfa45581b45832b7251a2ee4029000e..7c910a5593a6d850a4f43617faa27ea01c951b42 100644 (file)
@@ -206,6 +206,8 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
        what |= MASK_TC_BIT(rw, RAHEAD);
        what |= MASK_TC_BIT(rw, META);
        what |= MASK_TC_BIT(rw, DISCARD);
+       what |= MASK_TC_BIT(rw, FLUSH);
+       what |= MASK_TC_BIT(rw, FUA);
 
        pid = tsk->pid;
        if (act_log_check(bt, what, sector, pid))
@@ -1054,6 +1056,9 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)
                goto out;
        }
 
+       if (tc & BLK_TC_FLUSH)
+               rwbs[i++] = 'F';
+
        if (tc & BLK_TC_DISCARD)
                rwbs[i++] = 'D';
        else if (tc & BLK_TC_WRITE)
@@ -1063,10 +1068,10 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)
        else
                rwbs[i++] = 'N';
 
+       if (tc & BLK_TC_FUA)
+               rwbs[i++] = 'F';
        if (tc & BLK_TC_AHEAD)
                rwbs[i++] = 'A';
-       if (tc & BLK_TC_BARRIER)
-               rwbs[i++] = 'B';
        if (tc & BLK_TC_SYNC)
                rwbs[i++] = 'S';
        if (tc & BLK_TC_META)
@@ -1132,7 +1137,7 @@ typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act);
 
 static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
 {
-       char rwbs[6];
+       char rwbs[RWBS_LEN];
        unsigned long long ts  = iter->ts;
        unsigned long nsec_rem = do_div(ts, NSEC_PER_SEC);
        unsigned secs          = (unsigned long)ts;
@@ -1148,7 +1153,7 @@ static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
 
 static int blk_log_action(struct trace_iterator *iter, const char *act)
 {
-       char rwbs[6];
+       char rwbs[RWBS_LEN];
        const struct blk_io_trace *t = te_blk_io_trace(iter->ent);
 
        fill_rwbs(rwbs, t);
@@ -1561,7 +1566,7 @@ static const struct {
 } mask_maps[] = {
        { BLK_TC_READ,          "read"          },
        { BLK_TC_WRITE,         "write"         },
-       { BLK_TC_BARRIER,       "barrier"       },
+       { BLK_TC_FLUSH,         "flush"         },
        { BLK_TC_SYNC,          "sync"          },
        { BLK_TC_QUEUE,         "queue"         },
        { BLK_TC_REQUEUE,       "requeue"       },
@@ -1573,6 +1578,7 @@ static const struct {
        { BLK_TC_META,          "meta"          },
        { BLK_TC_DISCARD,       "discard"       },
        { BLK_TC_DRV_DATA,      "drv_data"      },
+       { BLK_TC_FUA,           "fua"           },
 };
 
 static int blk_trace_str2mask(const char *str)
@@ -1788,6 +1794,9 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
 {
        int i = 0;
 
+       if (rw & REQ_FLUSH)
+               rwbs[i++] = 'F';
+
        if (rw & WRITE)
                rwbs[i++] = 'W';
        else if (rw & REQ_DISCARD)
@@ -1797,6 +1806,8 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
        else
                rwbs[i++] = 'N';
 
+       if (rw & REQ_FUA)
+               rwbs[i++] = 'F';
        if (rw & REQ_RAHEAD)
                rwbs[i++] = 'A';
        if (rw & REQ_SYNC)
index 693394daa2ed79439d4210c7f5c0bd345ff3692b..5ef672c07f752a68938623651b8caa574285222c 100644 (file)
@@ -326,7 +326,7 @@ static struct page_address_slot {
        spinlock_t lock;                        /* Protect this bucket's list */
 } ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];
 
-static struct page_address_slot *page_slot(struct page *page)
+static struct page_address_slot *page_slot(const struct page *page)
 {
        return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)];
 }
@@ -337,7 +337,7 @@ static struct page_address_slot *page_slot(struct page *page)
  *
  * Returns the page's virtual address.
  */
-void *page_address(struct page *page)
+void *page_address(const struct page *page)
 {
        unsigned long flags;
        void *ret;
index 3fd1a7e24928fdbc08e45f727ed34b3625d7effc..552b97afbca5346a96ca6187602ba0326ce4ef28 100644 (file)
@@ -1073,10 +1073,10 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
        sdev->pcmid = -1;
        list_del(&ldev->list);
        layouts_list_items--;
+       kfree(ldev);
  outnodev:
        of_node_put(sound);
        layout_device = NULL;
-       kfree(ldev);
        return -ENODEV;
 }
 
index 200c9a1d48b7c7d8dc238edf0113730d4c0a5919..a872d0a829767d50bbeeaa3ee7f9ba7be40de683 100644 (file)
@@ -1909,6 +1909,7 @@ static unsigned int ad1981_jacks_whitelist[] = {
        0x103c0944, /* HP nc6220 */
        0x103c0934, /* HP nc8220 */
        0x103c006d, /* HP nx9105 */
+       0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */
        0x17340088, /* FSC Scenic-W */
        0 /* end */
 };
index be58bf2f3aec7a9d32ce17d3b238f2f7705cbff8..2e5876ce71fe6c3c2613934653bcaafe7a0875e1 100644 (file)
@@ -476,8 +476,8 @@ static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 
 static const struct alc_config_preset alc268_presets[] = {
        [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc267_quanta_il1_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -492,8 +492,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_3ST] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_base_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
                .dac_nids = alc268_dac_nids,
@@ -507,8 +507,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .input_mux = &alc268_capture_source,
        },
        [ALC268_TOSHIBA] = {
-               .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_toshiba_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_toshiba_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -525,8 +525,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER] = {
-               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_acer_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -543,8 +543,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER_DMIC] = {
-               .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_acer_dmic_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -561,9 +561,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ACER_ASPIRE_ONE] = {
-               .mixers = { alc268_acer_aspire_one_mixer,
-                           alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc268_acer_aspire_one_mixer, alc268_beep_mixer},
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_aspire_one_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -579,8 +578,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_DELL] = {
-               .mixers = { alc268_dell_mixer, alc268_beep_mixer,
-                           alc268_capture_nosrc_mixer },
+               .mixers = { alc268_dell_mixer, alc268_beep_mixer},
+               .cap_mixer = alc268_capture_nosrc_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_dell_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -596,8 +595,8 @@ static const struct alc_config_preset alc268_presets[] = {
                .init_hook = alc_inithook,
        },
        [ALC268_ZEPTO] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
-                           alc268_beep_mixer },
+               .mixers = { alc268_base_mixer, alc268_beep_mixer },
+               .cap_mixer = alc268_capture_alt_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_toshiba_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -616,7 +615,8 @@ static const struct alc_config_preset alc268_presets[] = {
        },
 #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST] = {
-               .mixers = { alc268_test_mixer, alc268_capture_mixer },
+               .mixers = { alc268_test_mixer },
+               .cap_mixer = alc268_capture_mixer,
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_volume_init_verbs,
                                alc268_beep_init_verbs },
index 28ce17d09c338eb1c744561d32ca6473b6b4ca10..c34f730f481568042b334e4973ae0569f5fdea9b 100644 (file)
@@ -144,25 +144,17 @@ static int cea_sampling_frequencies[8] = {
        SNDRV_PCM_RATE_192000,  /* 7: 192000Hz */
 };
 
-static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
                                        int byte_index)
 {
        unsigned int val;
 
        val = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_HDMI_ELDD, byte_index);
-
 #ifdef BE_PARANOID
        printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
 #endif
-
-       if ((val & AC_ELDD_ELD_VALID) == 0) {
-               snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
-                                                               byte_index);
-               val = 0;
-       }
-
-       return val & AC_ELDD_ELD_DATA;
+       return val;
 }
 
 #define GRAB_BITS(buf, byte, lowbit, bits)             \
@@ -344,11 +336,26 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        if (!buf)
                return -ENOMEM;
 
-       for (i = 0; i < size; i++)
-               buf[i] = hdmi_get_eld_byte(codec, nid, i);
+       for (i = 0; i < size; i++) {
+               unsigned int val = hdmi_get_eld_data(codec, nid, i);
+               if (!(val & AC_ELDD_ELD_VALID)) {
+                       if (!i) {
+                               snd_printd(KERN_INFO
+                                          "HDMI: invalid ELD data\n");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       snd_printd(KERN_INFO
+                                 "HDMI: invalid ELD data byte %d\n", i);
+                       val = 0;
+               } else
+                       val &= AC_ELDD_ELD_DATA;
+               buf[i] = val;
+       }
 
        ret = hdmi_update_eld(eld, buf, size);
 
+error:
        kfree(buf);
        return ret;
 }
index 47d6ffc9b5b5c34e4834fb25d163e2384ca0117e..d6c93d92b550559513b83de36c90a4c3ecad7699 100644 (file)
@@ -375,7 +375,7 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
                         unsigned int *idxp)
 {
-       int i;
+       int i, idx;
        hda_nid_t nid;
 
        nid = codec->start_nid;
@@ -384,9 +384,11 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
                type = get_wcaps_type(get_wcaps(codec, nid));
                if (type != AC_WID_AUD_IN)
                        continue;
-               *idxp = snd_hda_get_conn_index(codec, nid, pin, false);
-               if (*idxp >= 0)
+               idx = snd_hda_get_conn_index(codec, nid, pin, false);
+               if (idx >= 0) {
+                       *idxp = idx;
                        return nid;
+               }
        }
        return 0;
 }
index 9a1aa09f47fe1b9191cfba2f924c96ece962fc5c..fcb11af9ad24f76a489f35472933238075b7bad5 100644 (file)
@@ -1784,6 +1784,7 @@ static const char * const alc_slave_vols[] = {
        "Speaker Playback Volume",
        "Mono Playback Volume",
        "Line-Out Playback Volume",
+       "PCM Playback Volume",
        NULL,
 };
 
@@ -1798,6 +1799,7 @@ static const char * const alc_slave_sws[] = {
        "Mono Playback Switch",
        "IEC958 Playback Switch",
        "Line-Out Playback Switch",
+       "PCM Playback Switch",
        NULL,
 };
 
index aa52b3e13bb5348c81f6e0b74cede4cd90960455..2cf87f5afed4e2fbc93cdcdf4d72277b8afae52f 100644 (file)
@@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev)
 
        for (i = 0; i < N_URBS; i++) {
                usb_kill_urb(dev->data_urbs_in[i]);
-               usb_kill_urb(dev->data_urbs_out[i]);
+
+               if (test_bit(i, &dev->outurb_active_mask))
+                       usb_kill_urb(dev->data_urbs_out[i]);
        }
+
+       dev->outurb_active_mask = 0;
 }
 
 static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
@@ -612,8 +616,8 @@ static void read_completed(struct urb *urb)
 {
        struct snd_usb_caiaq_cb_info *info = urb->context;
        struct snd_usb_caiaqdev *dev;
-       struct urb *out;
-       int frame, len, send_it = 0, outframe = 0;
+       struct urb *out = NULL;
+       int i, frame, len, send_it = 0, outframe = 0;
        size_t offset = 0;
 
        if (urb->status || !info)
@@ -624,7 +628,17 @@ static void read_completed(struct urb *urb)
        if (!dev->streaming)
                return;
 
-       out = dev->data_urbs_out[info->index];
+       /* find an unused output urb that is unused */
+       for (i = 0; i < N_URBS; i++)
+               if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) {
+                       out = dev->data_urbs_out[i];
+                       break;
+               }
+
+       if (!out) {
+               log("Unable to find an output urb to use\n");
+               goto requeue;
+       }
 
        /* read the recently received packet and send back one which has
         * the same layout */
@@ -655,8 +669,12 @@ static void read_completed(struct urb *urb)
                out->number_of_packets = outframe;
                out->transfer_flags = URB_ISO_ASAP;
                usb_submit_urb(out, GFP_ATOMIC);
+       } else {
+               struct snd_usb_caiaq_cb_info *oinfo = out->context;
+               clear_bit(oinfo->index, &dev->outurb_active_mask);
        }
 
+requeue:
        /* re-submit inbound urb */
        for (frame = 0; frame < FRAMES_PER_URB; frame++) {
                urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
@@ -678,6 +696,8 @@ static void write_completed(struct urb *urb)
                dev->output_running = 1;
                wake_up(&dev->prepare_wait_queue);
        }
+
+       clear_bit(info->index, &dev->outurb_active_mask);
 }
 
 static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)
@@ -829,6 +849,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        if (!dev->data_cb_info)
                return -ENOMEM;
 
+       dev->outurb_active_mask = 0;
+       BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8));
+
        for (i = 0; i < N_URBS; i++) {
                dev->data_cb_info[i].dev = dev;
                dev->data_cb_info[i].index = i;
index b2b310194ffa4c27640ccdb624885500dd562ed5..3f9c6339ae90fa54dd41cad9920e8d60223ddcd6 100644 (file)
@@ -96,6 +96,7 @@ struct snd_usb_caiaqdev {
        int input_panic, output_panic, warned;
        char *audio_in_buf, *audio_out_buf;
        unsigned int samplerates, bpp;
+       unsigned long outurb_active_mask;
 
        struct snd_pcm_substream *sub_playback[MAX_STREAMS];
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
index c04d7c71ac88836c32ee3fd3e533472de573c953..cdd19d7fe500b2a6315b3023212f1313032c5999 100644 (file)
@@ -152,6 +152,7 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p,
        if (p && p->dB) {
                cval->dBmin = p->dB->min;
                cval->dBmax = p->dB->max;
+               cval->initialized = 1;
        }
 }
 
@@ -1092,7 +1093,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                                " Switch" : " Volume");
                if (control == UAC_FU_VOLUME) {
                        check_mapped_dB(map, cval);
-                       if (cval->dBmin < cval->dBmax) {
+                       if (cval->dBmin < cval->dBmax || !cval->initialized) {
                                kctl->tlv.c = mixer_vol_tlv;
                                kctl->vd[0].access |= 
                                        SNDRV_CTL_ELEM_ACCESS_TLV_READ |
index 5f2a5c7046dfd6d07b973a454ddc28332786b4ec..710ae3d0a489ba9aac850cf9c28baff6b267d9b6 100644 (file)
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used,
 {
        int ret = 0;
 
-       if (str)
-               ret = parse_line_range_desc(str, &params.line_range);
-       INIT_LIST_HEAD(&params.line_range.line_list);
+       if (!str)
+               return 0;
+
+       if (params.show_lines) {
+               pr_warning("Warning: more than one --line options are"
+                          " detected. Only the first one is valid.\n");
+               return 0;
+       }
+
        params.show_lines = true;
+       ret = parse_line_range_desc(str, &params.line_range);
+       INIT_LIST_HEAD(&params.line_range.line_list);
 
        return ret;
 }
index f6426b496f4aa0ee59c25a84622fc12c2dec32ff..6b0519f885e4ecc436e9344a3c2f94865eafbd92 100644 (file)
@@ -45,7 +45,7 @@ static int                    freq                            =   1000;
 static int                     output;
 static int                     pipe_output                     =      0;
 static const char              *output_name                    = NULL;
-static int                     group                           =      0;
+static bool                    group                           =  false;
 static int                     realtime_prio                   =      0;
 static bool                    nodelay                         =  false;
 static bool                    raw_samples                     =  false;
@@ -753,6 +753,8 @@ const struct option record_options[] = {
                    "child tasks do not inherit counters"),
        OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
        OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
+       OPT_BOOLEAN(0, "group", &group,
+                   "put the counters into a counter group"),
        OPT_BOOLEAN('g', "call-graph", &call_graph,
                    "do call-graph (stack chain/backtrace) recording"),
        OPT_INCR('v', "verbose", &verbose,
index 1ad04ce29c3479828c8a91b2a13efbaaf871a3f2..5deb17d9e79506028921b512f734b4a6becc4f32 100644 (file)
@@ -193,6 +193,7 @@ static int                  big_num_opt                     =  -1;
 static const char              *cpu_list;
 static const char              *csv_sep                        = NULL;
 static bool                    csv_output                      = false;
+static bool                    group                           = false;
 
 static volatile int done = 0;
 
@@ -280,14 +281,14 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
        attr->inherit = !no_inherit;
 
        if (system_wide)
-               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false);
+               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
 
        if (target_pid == -1 && target_tid == -1) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
 
-       return perf_evsel__open_per_thread(evsel, evsel_list->threads, false);
+       return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
 }
 
 /*
@@ -1043,6 +1044,8 @@ static const struct option options[] = {
                    "stat events on existing thread id"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
+       OPT_BOOLEAN('g', "group", &group,
+                   "put the counters into a counter group"),
        OPT_BOOLEAN('c', "scale", &scale,
                    "scale/normalize counters"),
        OPT_INCR('v', "verbose", &verbose,
index fddf40f30d3ebc3670858946610687144c67a361..ee51e9b4dc0996709059723a07ff67fbf9f7da82 100644 (file)
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
        return *lineno ?: -ENOENT;
 }
 
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
+
+/**
+ * cu_walk_functions_at - Walk on function DIEs at given address
+ * @cu_die: A CU DIE
+ * @addr: An address
+ * @callback: A callback which called with found DIEs
+ * @data: A user data
+ *
+ * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
+ * should be subprogram or inlined-subroutines.
+ */
+int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                   int (*callback)(Dwarf_Die *, void *), void *data)
+{
+       Dwarf_Die die_mem;
+       Dwarf_Die *sc_die;
+       int ret = -ENOENT;
+
+       /* Inlined function could be recursive. Trace it until fail */
+       for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
+            sc_die != NULL;
+            sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
+                                    &die_mem)) {
+               ret = callback(sc_die, data);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+
+}
+
 /**
  * die_compare_name - Compare diename and tname
  * @dw_die: a DIE
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
        return 0;
 }
 
+/* Get attribute and translate it as a sdata */
+static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
+                             Dwarf_Sword *result)
+{
+       Dwarf_Attribute attr;
+
+       if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formsdata(&attr, result) != 0)
+               return -ENOENT;
+
+       return 0;
+}
+
 /**
  * die_is_signed_type - Check whether a type DIE is signed or not
  * @tp_die: a DIE of a type
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
        return 0;
 }
 
+/* Get the call file index number in CU DIE */
+static int die_get_call_fileno(Dwarf_Die *in_die)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/* Get the declared file index number in CU DIE */
+static int die_get_decl_fileno(Dwarf_Die *pdie)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/**
+ * die_get_call_file - Get callsite file name of inlined function instance
+ * @in_die: a DIE of an inlined function instance
+ *
+ * Get call-site file name of @in_die. This means from which file the inline
+ * function is called.
+ */
+const char *die_get_call_file(Dwarf_Die *in_die)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Files *files;
+       int idx;
+
+       idx = die_get_call_fileno(in_die);
+       if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
+           dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
+               return NULL;
+
+       return dwarf_filesrc(files, idx, NULL, NULL);
+}
+
+
 /**
  * die_find_child - Generic DIE search function in DIE tree
  * @rt_die: a root DIE
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
        return die_mem;
 }
 
+struct __instance_walk_param {
+       void    *addr;
+       int     (*callback)(Dwarf_Die *, void *);
+       void    *data;
+       int     retval;
+};
+
+static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
+{
+       struct __instance_walk_param *iwp = data;
+       Dwarf_Attribute attr_mem;
+       Dwarf_Die origin_mem;
+       Dwarf_Attribute *attr;
+       Dwarf_Die *origin;
+       int tmp;
+
+       attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
+       if (attr == NULL)
+               return DIE_FIND_CB_CONTINUE;
+
+       origin = dwarf_formref_die(attr, &origin_mem);
+       if (origin == NULL || origin->addr != iwp->addr)
+               return DIE_FIND_CB_CONTINUE;
+
+       /* Ignore redundant instances */
+       if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
+               dwarf_decl_line(origin, &tmp);
+               if (die_get_call_lineno(inst) == tmp) {
+                       tmp = die_get_decl_fileno(origin);
+                       if (die_get_call_fileno(inst) == tmp)
+                               return DIE_FIND_CB_CONTINUE;
+               }
+       }
+
+       iwp->retval = iwp->callback(inst, iwp->data);
+
+       return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
+}
+
+/**
+ * die_walk_instances - Walk on instances of given DIE
+ * @or_die: an abstract original DIE
+ * @callback: a callback function which is called with instance DIE
+ * @data: user data
+ *
+ * Walk on the instances of give @in_die. @in_die must be an inlined function
+ * declartion. This returns the return value of @callback if it returns
+ * non-zero value, or -ENOENT if there is no instance.
+ */
+int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
+                      void *data)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Die die_mem;
+       struct __instance_walk_param iwp = {
+               .addr = or_die->addr,
+               .callback = callback,
+               .data = data,
+               .retval = -ENOENT,
+       };
+
+       if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
+               return -ENOENT;
+
+       die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
+
+       return iwp.retval;
+}
+
 /* Line walker internal parameters */
 struct __line_walk_param {
-       const char *fname;
+       bool recursive;
        line_walk_callback_t callback;
        void *data;
        int retval;
@@ -385,39 +544,56 @@ struct __line_walk_param {
 static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
 {
        struct __line_walk_param *lw = data;
-       Dwarf_Addr addr;
+       Dwarf_Addr addr = 0;
+       const char *fname;
        int lineno;
 
        if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+               fname = die_get_call_file(in_die);
                lineno = die_get_call_lineno(in_die);
-               if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
-                       lw->retval = lw->callback(lw->fname, lineno, addr,
-                                                 lw->data);
+               if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
                        if (lw->retval != 0)
                                return DIE_FIND_CB_END;
                }
        }
-       return DIE_FIND_CB_SIBLING;
+       if (!lw->recursive)
+               /* Don't need to search recursively */
+               return DIE_FIND_CB_SIBLING;
+
+       if (addr) {
+               fname = dwarf_decl_file(in_die);
+               if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
+                       if (lw->retval != 0)
+                               return DIE_FIND_CB_END;
+               }
+       }
+
+       /* Continue to search nested inlined function call-sites */
+       return DIE_FIND_CB_CONTINUE;
 }
 
 /* Walk on lines of blocks included in given DIE */
-static int __die_walk_funclines(Dwarf_Die *sp_die,
+static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
                                line_walk_callback_t callback, void *data)
 {
        struct __line_walk_param lw = {
+               .recursive = recursive,
                .callback = callback,
                .data = data,
                .retval = 0,
        };
        Dwarf_Die die_mem;
        Dwarf_Addr addr;
+       const char *fname;
        int lineno;
 
        /* Handle function declaration line */
-       lw.fname = dwarf_decl_file(sp_die);
-       if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+       fname = dwarf_decl_file(sp_die);
+       if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
            dwarf_entrypc(sp_die, &addr) == 0) {
-               lw.retval = callback(lw.fname, lineno, addr, data);
+               lw.retval = callback(fname, lineno, addr, data);
                if (lw.retval != 0)
                        goto done;
        }
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 {
        struct __line_walk_param *lw = data;
 
-       lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data);
+       lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
        if (lw->retval != 0)
                return DWARF_CB_ABORT;
 
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 
 /**
  * die_walk_lines - Walk on lines inside given DIE
- * @rt_die: a root DIE (CU or subprogram)
+ * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
  * @callback: callback routine
  * @data: user data
  *
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
        size_t nlines, i;
 
        /* Get the CU die */
-       if (dwarf_tag(rt_die) == DW_TAG_subprogram)
+       if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
                cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
        else
                cu_die = rt_die;
        if (!cu_die) {
-               pr_debug2("Failed to get CU from subprogram\n");
+               pr_debug2("Failed to get CU from given DIE.\n");
                return -EINVAL;
        }
 
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
         * subroutines. We have to check functions list or given function.
         */
        if (rt_die != cu_die)
-               ret = __die_walk_funclines(rt_die, callback, data);
+               /*
+                * Don't need walk functions recursively, because nested
+                * inlined functions don't have lines of the specified DIE.
+                */
+               ret = __die_walk_funclines(rt_die, false, callback, data);
        else {
                struct __line_walk_param param = {
                        .callback = callback,
index bc3b21167e709cd42b98ea46e51e8a7fe3795154..6ce1717784b7ab42a14d58431c3026df749f0620 100644 (file)
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
 extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
                            const char **fname, int *lineno);
 
+/* Walk on funcitons at given address */
+extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                       int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Compare diename and tname */
 extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
 
 /* Get callsite line number of inline-function instance */
 extern int die_get_call_lineno(Dwarf_Die *in_die);
 
+/* Get callsite file name of inlined function instance */
+extern const char *die_get_call_file(Dwarf_Die *in_die);
+
 /* Get type die */
 extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
 
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
 extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                                      Dwarf_Die *die_mem);
 
+/* Walk on the instances of given DIE */
+extern int die_walk_instances(Dwarf_Die *in_die,
+                             int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Walker on lines (Note: line number will not be sorted) */
 typedef int (* line_walk_callback_t) (const char *fname, int lineno,
                                      Dwarf_Addr addr, void *data);
index e03e7bc8205e10650ac30abaedfcc5239062e2f3..c12bd476c6f7b404436269f4963c937cd18a69e8 100644 (file)
@@ -85,10 +85,19 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
        struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
 
        if (evsel == NULL)
-               return -ENOMEM;
+               goto error;
+
+       /* use strdup() because free(evsel) assumes name is allocated */
+       evsel->name = strdup("cycles");
+       if (!evsel->name)
+               goto error_free;
 
        perf_evlist__add(evlist, evsel);
        return 0;
+error_free:
+       perf_evsel__delete(evsel);
+error:
+       return -ENOMEM;
 }
 
 void perf_evlist__disable(struct perf_evlist *evlist)
index d4f3101773db555a19c05611cf1f45e824fc321d..b6c1ad123ca9769cee8fd5845661382b7c09fdf2 100644 (file)
@@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
                        return -1;
 
                bev.header = old_bev.header;
-               bev.pid    = 0;
+
+               /*
+                * As the pid is the missing value, we need to fill
+                * it properly. The header.misc value give us nice hint.
+                */
+               bev.pid = HOST_KERNEL_ID;
+               if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
+                   bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
+                       bev.pid = DEFAULT_GUEST_KERNEL_ID;
+
                memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
                __event_process_build_id(&bev, filename, session);
 
index 791f9dd27ebffd3166f6535c629c0595d073b3db..547628e97f3d2ac4aacf85485f8e5d790575c042 100644 (file)
@@ -5,7 +5,9 @@
 #define __always_inline        inline
 #endif
 #define __user
+#ifndef __attribute_const__
 #define __attribute_const__
+#endif
 
 #define __used         __attribute__((__unused__))
 
index 4ea7e19f52515d61a1bd02ccac9e4942bad60dfa..928918b796b2bd355799cf25926d926fea002bad 100644 (file)
@@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
                return EVT_FAILED;
        n = hex2u64(str + 1, &config);
        if (n > 0) {
-               *strp = str + n + 1;
+               const char *end = str + n + 1;
+               if (*end != '\0' && *end != ',' && *end != ':')
+                       return EVT_FAILED;
+
+               *strp = end;
                attr->type = PERF_TYPE_RAW;
                attr->config = config;
                return EVT_HANDLED;
@@ -1097,6 +1101,4 @@ void print_events(const char *event_glob)
        printf("\n");
 
        print_tracepoint_events(NULL, NULL);
-
-       exit(129);
 }
index 3e44a3e36519cb0f6d1ee708d88b90f467d38032..555fc3864b9024e9dc43a847ec0ba8d38f3bb065 100644 (file)
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
        return ret;
 }
 
-/* Find a variable in a subprogram die */
-static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Find a variable in a scope DIE */
+static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die vr_die, *scopes;
+       Dwarf_Die vr_die;
        char buf[32], *ptr;
-       int ret, nscopes;
+       int ret = 0;
 
        if (!is_c_varname(pf->pvar->var)) {
                /* Copy raw parameters */
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (pf->tvar->name == NULL)
                return -ENOMEM;
 
-       pr_debug("Searching '%s' variable in context.\n",
-                pf->pvar->var);
+       pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
        /* Search child die for local variables and parameters. */
-       if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
-               ret = convert_variable(&vr_die, pf);
-       else {
-               /* Search upper class */
-               nscopes = dwarf_getscopes_die(sp_die, &scopes);
-               while (nscopes-- > 1) {
-                       pr_debug("Searching variables in %s\n",
-                                dwarf_diename(&scopes[nscopes]));
-                       /* We should check this scope, so give dummy address */
-                       if (die_find_variable_at(&scopes[nscopes],
-                                                pf->pvar->var, 0,
-                                                &vr_die)) {
-                               ret = convert_variable(&vr_die, pf);
-                               goto found;
-                       }
-               }
-               if (scopes)
-                       free(scopes);
-               ret = -ENOENT;
+       if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
+               /* Search again in global variables */
+               if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
+                       ret = -ENOENT;
        }
-found:
+       if (ret == 0)
+               ret = convert_variable(&vr_die, pf);
+
        if (ret < 0)
                pr_warning("Failed to find '%s' in this function.\n",
                           pf->pvar->var);
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
        return 0;
 }
 
-/* Call probe_finder callback with real subprogram DIE */
-static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Call probe_finder callback with scope DIE */
+static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die die_mem;
        Dwarf_Attribute fb_attr;
        size_t nops;
        int ret;
 
-       /* If no real subprogram, find a real one */
-       if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-               sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
-               if (!sp_die) {
+       if (!sc_die) {
+               pr_err("Caller must pass a scope DIE. Program error.\n");
+               return -EINVAL;
+       }
+
+       /* If not a real subprogram, find a real one */
+       if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
+               if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
                        pr_warning("Failed to find probe point in any "
                                   "functions.\n");
                        return -ENOENT;
                }
-       }
+       } else
+               memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
 
-       /* Get the frame base attribute/ops */
-       dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
+       /* Get the frame base attribute/ops from subprogram */
+       dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
        ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
        if (ret <= 0 || nops == 0) {
                pf->fb_ops = NULL;
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
 
        /* Call finder's callback handler */
-       ret = pf->callback(sp_die, pf);
+       ret = pf->callback(sc_die, pf);
 
        /* *pf->fb_ops will be cached in libdw. Don't free it. */
        pf->fb_ops = NULL;
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        return ret;
 }
 
+struct find_scope_param {
+       const char *function;
+       const char *file;
+       int line;
+       int diff;
+       Dwarf_Die *die_mem;
+       bool found;
+};
+
+static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
+{
+       struct find_scope_param *fsp = data;
+       const char *file;
+       int lno;
+
+       /* Skip if declared file name does not match */
+       if (fsp->file) {
+               file = dwarf_decl_file(fn_die);
+               if (!file || strcmp(fsp->file, file) != 0)
+                       return 0;
+       }
+       /* If the function name is given, that's what user expects */
+       if (fsp->function) {
+               if (die_compare_name(fn_die, fsp->function)) {
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+                       return 1;
+               }
+       } else {
+               /* With the line number, find the nearest declared DIE */
+               dwarf_decl_line(fn_die, &lno);
+               if (lno < fsp->line && fsp->diff > fsp->line - lno) {
+                       /* Keep a candidate and continue */
+                       fsp->diff = fsp->line - lno;
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+               }
+       }
+       return 0;
+}
+
+/* Find an appropriate scope fits to given conditions */
+static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
+{
+       struct find_scope_param fsp = {
+               .function = pf->pev->point.function,
+               .file = pf->fname,
+               .line = pf->lno,
+               .diff = INT_MAX,
+               .die_mem = die_mem,
+               .found = false,
+       };
+
+       cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
+
+       return fsp.found ? die_mem : NULL;
+}
+
 static int probe_point_line_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
                return 0;
 
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /* Continue if no error, because the line will be in inline function */
        return ret < 0 ? ret : 0;
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
        pr_debug("Probe line found: line:%d addr:0x%llx\n",
                 lineno, (unsigned long long)addr);
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       pf->lno = lineno;
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /*
         * Continue if no error, because the lazy pattern will match
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
-/* Callback parameter with return value */
-struct dwarf_callback_param {
-       void *data;
-       int retval;
-};
-
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
-       struct probe_finder *pf = param->data;
+       struct probe_finder *pf = data;
        struct perf_probe_point *pp = &pf->pev->point;
        Dwarf_Addr addr;
+       int ret;
 
        if (pp->lazy_line)
-               param->retval = find_probe_point_lazy(in_die, pf);
+               ret = find_probe_point_lazy(in_die, pf);
        else {
                /* Get probe address */
                if (dwarf_entrypc(in_die, &addr) != 0) {
                        pr_warning("Failed to get entry address of %s.\n",
                                   dwarf_diename(in_die));
-                       param->retval = -ENOENT;
-                       return DWARF_CB_ABORT;
+                       return -ENOENT;
                }
                pf->addr = addr;
                pf->addr += pp->offset;
                pr_debug("found inline addr: 0x%jx\n",
                         (uintmax_t)pf->addr);
 
-               param->retval = call_probe_finder(in_die, pf);
-               if (param->retval < 0)
-                       return DWARF_CB_ABORT;
+               ret = call_probe_finder(in_die, pf);
        }
 
-       return DWARF_CB_OK;
+       return ret;
 }
 
+/* Callback parameter with return value for libdw */
+struct dwarf_callback_param {
+       void *data;
+       int retval;
+};
+
 /* Search function from function name */
 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
                }
-       } else {
-               struct dwarf_callback_param _param = {.data = (void *)pf,
-                                                     .retval = 0};
+       } else
                /* Inlined function: search instances */
-               dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
-                                           &_param);
-               param->retval = _param.retval;
-       }
+               param->retval = die_walk_instances(sp_die,
+                                       probe_point_inline_cb, (void *)pf);
 
        return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
 }
@@ -1060,7 +1116,7 @@ found:
 }
 
 /* Add a found probe point into trace event list */
-static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct trace_event_finder *tf =
                        container_of(pf, struct trace_event_finder, pf);
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        tev = &tf->tevs[tf->ntevs++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &tev->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &tev->point);
        if (ret < 0)
                return ret;
 
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        for (i = 0; i < pf->pev->nargs; i++) {
                pf->pvar = &pf->pev->args[i];
                pf->tvar = &tev->args[i];
-               ret = find_variable(sp_die, pf);
+               /* Variable should be found from scope DIE */
+               ret = find_variable(sc_die, pf);
                if (ret != 0)
                        return ret;
        }
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 }
 
 /* Add a found vars into available variables list */
-static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct available_var_finder *af =
                        container_of(pf, struct available_var_finder, pf);
        struct variable_list *vl;
-       Dwarf_Die die_mem, *scopes = NULL;
-       int ret, nscopes;
+       Dwarf_Die die_mem;
+       int ret;
 
        /* Check number of tevs */
        if (af->nvls == af->max_vls) {
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        vl = &af->vls[af->nvls++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &vl->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &vl->point);
        if (ret < 0)
                return ret;
 
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (vl->vars == NULL)
                return -ENOMEM;
        af->child = true;
-       die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+       die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
 
        /* Find external variables */
        if (!af->externs)
                goto out;
        /* Don't need to search child DIE for externs. */
        af->child = false;
-       nscopes = dwarf_getscopes_die(sp_die, &scopes);
-       while (nscopes-- > 1)
-               die_find_child(&scopes[nscopes], collect_variables_cb,
-                              (void *)af, &die_mem);
-       if (scopes)
-               free(scopes);
+       die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
 
 out:
        if (strlist__empty(vl->vars)) {
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
+       find_line_range_by_line(in_die, data);
 
-       param->retval = find_line_range_by_line(in_die, param->data);
-       return DWARF_CB_ABORT;  /* No need to find other instances */
+       /*
+        * We have to check all instances of inlined function, because
+        * some execution paths can be optimized out depends on the
+        * function argument of instances
+        */
+       return 0;
 }
 
 /* Search function from function name */
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
                pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
                lr->start = lf->lno_s;
                lr->end = lf->lno_e;
-               if (dwarf_func_inline(sp_die)) {
-                       struct dwarf_callback_param _param;
-                       _param.data = (void *)lf;
-                       _param.retval = 0;
-                       dwarf_func_inline_instances(sp_die,
-                                                   line_range_inline_cb,
-                                                   &_param);
-                       param->retval = _param.retval;
-               } else
+               if (dwarf_func_inline(sp_die))
+                       param->retval = die_walk_instances(sp_die,
+                                               line_range_inline_cb, lf);
+               else
                        param->retval = find_line_range_by_line(sp_die, lf);
                return DWARF_CB_ABORT;
        }
index c478b42a2473f68ea1dcb786c1a5892c70913866..1132c8f0ce890b09bab27520a59a4bf1ad7fe765 100644 (file)
@@ -57,7 +57,7 @@ struct probe_finder {
        struct perf_probe_event *pev;           /* Target probe event */
 
        /* Callback when a probe point is found */
-       int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
+       int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
 
        /* For function searching */
        int                     lno;            /* Line number */
index a8b53714542a1524811a44120e330bf4d2ba94f7..469c0264ed298d138698d93206419b87fbb3dd99 100644 (file)
@@ -1506,7 +1506,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
                struct stat st;
 
-               if (stat(dso->name, &st) < 0)
+               if (lstat(dso->name, &st) < 0)
                        return -1;
 
                if (st.st_uid && (st.st_uid != geteuid())) {
@@ -2181,27 +2181,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
        return ret;
 }
 
-struct dso *dso__new_kernel(const char *name)
+static struct dso*
+dso__kernel_findnew(struct machine *machine, const char *name,
+                   const char *short_name, int dso_type)
 {
-       struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
-
-       if (dso != NULL) {
-               dso__set_short_name(dso, "[kernel]");
-               dso->kernel = DSO_TYPE_KERNEL;
-       }
-
-       return dso;
-}
+       /*
+        * The kernel dso could be created by build_id processing.
+        */
+       struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
 
-static struct dso *dso__new_guest_kernel(struct machine *machine,
-                                       const char *name)
-{
-       char bf[PATH_MAX];
-       struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
-                                                             sizeof(bf)));
+       /*
+        * We need to run this in all cases, since during the build_id
+        * processing we had no idea this was the kernel dso.
+        */
        if (dso != NULL) {
-               dso__set_short_name(dso, "[guest.kernel]");
-               dso->kernel = DSO_TYPE_GUEST_KERNEL;
+               dso__set_short_name(dso, short_name);
+               dso->kernel = dso_type;
        }
 
        return dso;
@@ -2219,24 +2214,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
                dso->has_build_id = true;
 }
 
-static struct dso *machine__create_kernel(struct machine *machine)
+static struct dso *machine__get_kernel(struct machine *machine)
 {
        const char *vmlinux_name = NULL;
        struct dso *kernel;
 
        if (machine__is_host(machine)) {
                vmlinux_name = symbol_conf.vmlinux_name;
-               kernel = dso__new_kernel(vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = "[kernel.kallsyms]";
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[kernel]",
+                                            DSO_TYPE_KERNEL);
        } else {
+               char bf[PATH_MAX];
+
                if (machine__is_default_guest(machine))
                        vmlinux_name = symbol_conf.default_guest_vmlinux_name;
-               kernel = dso__new_guest_kernel(machine, vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = machine__mmap_name(machine, bf,
+                                                         sizeof(bf));
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[guest.kernel]",
+                                            DSO_TYPE_GUEST_KERNEL);
        }
 
-       if (kernel != NULL) {
+       if (kernel != NULL && (!kernel->has_build_id))
                dso__read_running_kernel_build_id(kernel, machine);
-               dsos__add(&machine->kernel_dsos, kernel);
-       }
+
        return kernel;
 }
 
@@ -2340,7 +2347,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
 
 int machine__create_kernel_maps(struct machine *machine)
 {
-       struct dso *kernel = machine__create_kernel(machine);
+       struct dso *kernel = machine__get_kernel(machine);
 
        if (kernel == NULL ||
            __machine__create_kernel_maps(machine, kernel) < 0)
index 325ee36a9d29d63d82973d262816f91a064813f2..4f377d92e75a4c686279c99fa15e200f1ac6d5bc 100644 (file)
@@ -155,7 +155,6 @@ struct dso {
 };
 
 struct dso *dso__new(const char *name);
-struct dso *dso__new_kernel(const char *name);
 void dso__delete(struct dso *dso);
 
 int dso__name_len(const struct dso *dso);
index 5a06538532af5315dd48b27cc142856a4818c327..88403cf8396ad6294d4be6585fdfd92eaf5b4a6a 100644 (file)
@@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top)
                },
        };
 
-       ui_helpline__push("Press <- or ESC to exit");
        return perf_top_browser__run(&browser);
 }