OSDN Git Service

Merge branch 'akpm' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Apr 2020 00:57:48 +0000 (17:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Apr 2020 00:57:48 +0000 (17:57 -0700)
Merge yet more updates from Andrew Morton:

 - Almost all of the rest of MM (memcg, slab-generic, slab, pagealloc,
   gup, hugetlb, pagemap, memremap)

 - Various other things (hfs, ocfs2, kmod, misc, seqfile)

* akpm: (34 commits)
  ipc/util.c: sysvipc_find_ipc() should increase position index
  kernel/gcov/fs.c: gcov_seq_next() should increase position index
  fs/seq_file.c: seq_read(): add info message about buggy .next functions
  drivers/dma/tegra20-apb-dma.c: fix platform_get_irq.cocci warnings
  change email address for Pali Rohár
  selftests: kmod: test disabling module autoloading
  selftests: kmod: fix handling test numbers above 9
  docs: admin-guide: document the kernel.modprobe sysctl
  fs/filesystems.c: downgrade user-reachable WARN_ONCE() to pr_warn_once()
  kmod: make request_module() return an error when autoloading is disabled
  mm/memremap: set caching mode for PCI P2PDMA memory to WC
  mm/memory_hotplug: add pgprot_t to mhp_params
  powerpc/mm: thread pgprot_t through create_section_mapping()
  x86/mm: introduce __set_memory_prot()
  x86/mm: thread pgprot_t through init_memory_mapping()
  mm/memory_hotplug: rename mhp_restrictions to mhp_params
  mm/memory_hotplug: drop the flags field from struct mhp_restrictions
  mm/special: create generic fallbacks for pte_special() and pte_mkspecial()
  mm/vma: introduce VM_ACCESS_FLAGS
  mm/vma: define a default value for VM_DATA_DEFAULT_FLAGS
  ...

225 files changed:
Documentation/admin-guide/binderfs.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/sysrq.rst
Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt [deleted file]
Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
Documentation/driver-api/usb/writing_usb_driver.rst
Documentation/driver-api/w1.rst
Documentation/filesystems/orangefs.rst
Documentation/filesystems/qnx6.rst
Documentation/firmware-guide/acpi/namespace.rst
arch/s390/include/asm/qdio.h
arch/s390/mm/fault.c
arch/x86/kernel/acpi/boot.c
arch/x86/xen/setup.c
arch/x86/xen/xen-head.S
arch/xtensa/Kconfig
arch/xtensa/boot/Makefile
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/time.c
block/blk-cgroup.c
block/blk-mq.c
block/partitions/core.c
drivers/acpi/ec.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_imx.c
drivers/ata/libata-pmp.c
drivers/block/loop.c
drivers/block/xen-blkfront.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_ssif.c
drivers/char/ipmi/kcs_bmc_aspeed.c
drivers/cpuidle/cpuidle-haltpoll.c
drivers/firmware/edd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c
drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/include/dal_asic_id.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.h
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/exynos/exynos_dp.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/configfs.c
drivers/nvme/target/fc.c
drivers/nvme/target/fcloop.c
drivers/nvme/target/rdma.c
drivers/pwm/Kconfig
drivers/pwm/core.c
drivers/pwm/pwm-bcm2835.c
drivers/pwm/pwm-imx-tpm.c
drivers/pwm/pwm-imx27.c
drivers/pwm/pwm-jz4740.c
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-mxs.c
drivers/pwm/pwm-omap-dmtimer.c
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-rcar.c
drivers/pwm/pwm-renesas-tpu.c
drivers/pwm/pwm-sun4i.c
drivers/pwm/pwm-tegra.c
drivers/s390/cio/device.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/qdio_debug.h
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/cio/vfio_ccw_drv.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aic7xxx/aic7xxx_core.c
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/constants.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.h
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_nvmet.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sr.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/target/target_core_xcopy.c
drivers/target/target_core_xcopy.h
drivers/xen/events/events_2l.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/events/events_internal.h
drivers/xen/evtchn.c
drivers/xen/gntdev-common.h
drivers/xen/gntdev.c
drivers/xen/pvcalls-back.c
drivers/xen/pvcalls-front.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c
drivers/xen/xenbus/xenbus_client.c
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c
fs/orangefs/file.c
fs/orangefs/inode.c
fs/orangefs/orangefs-kernel.h
fs/proc/base.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_export.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_priv.h
include/clocksource/timer-ti-dm.h
include/drm/bridge/analogix_dp.h
include/drm/drm_legacy.h
include/linux/blk-cgroup.h
include/linux/nvme-fc-driver.h
include/linux/pid.h
include/linux/platform_data/pwm_omap_dmtimer.h [deleted file]
include/linux/printk.h
include/linux/pwm.h
include/sound/soc-dai.h
include/xen/events.h
include/xen/interface/event_channel.h
include/xen/xenbus.h
init/main.c
kernel/pid.c
kernel/power/user.c
kernel/printk/internal.h
kernel/printk/printk.c
kernel/printk/printk_safe.c
mm/backing-dev.c
sound/core/oss/pcm_plugin.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/prodigy_hifi.c
sound/soc/amd/raven/acp3x-i2s.c
sound/soc/amd/raven/acp3x.h
sound/soc/bcm/bcm63xx-pcm-whistler.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5682.c
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst/sst_pvt.c
sound/soc/intel/boards/bdw-rt5650.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/haswell.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/loader.c
sound/soc/stm/stm32_sai_sub.c
sound/usb/mixer_maps.c
sound/usb/quirks-table.h
sound/usb/quirks.c

index c009671..8243af9 100644 (file)
@@ -33,6 +33,12 @@ max
   a per-instance limit. If ``max=<count>`` is set then only ``<count>`` number
   of binder devices can be allocated in this binderfs instance.
 
+stats
+  Using ``stats=global`` enables global binder statistics.
+  ``stats=global`` is only available for a binderfs instance mounted in the
+  initial user namespace. An attempt to use the option to mount a binderfs
+  instance in another user namespace will return a permission error.
+
 Allocating binder Devices
 -------------------------
 
index d7df9a8..f2a93c8 100644 (file)
        coredump_filter=
                        [KNL] Change the default value for
                        /proc/<pid>/coredump_filter.
-                       See also Documentation/filesystems/proc.txt.
+                       See also Documentation/filesystems/proc.rst.
 
        coresight_cpu_debug.enable
                        [ARM,ARM64]
                        edid/1680x1050.bin, or edid/1920x1080.bin is given
                        and no file with the same name exists. Details and
                        instructions how to build your own EDID data are
-                       available in Documentation/driver-api/edid.rst. An EDID
+                       available in Documentation/admin-guide/edid.rst. An EDID
                        data set will only be used for a particular connector,
                        if its name and a colon are prepended to the EDID
                        name. Each connector may use a unique EDID data
                        Documentation/admin-guide/dynamic-debug-howto.rst
                        for details.
 
-       nompx           [X86] Disables Intel Memory Protection Extensions.
-                       See Documentation/x86/intel_mpx.rst for more
-                       information about the feature.
-
        nopku           [X86] Disable Memory Protection Keys CPU feature found
                        in some Intel CPUs.
 
index 72b2cfb..a46209f 100644 (file)
@@ -48,9 +48,10 @@ always allowed (by a user with admin privileges).
 How do I use the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-On x86   - You press the key combo :kbd:`ALT-SysRq-<command key>`.
+On x86
+       You press the key combo :kbd:`ALT-SysRq-<command key>`.
 
-.. note::
+       .. note::
           Some
            keyboards may not have a key labeled 'SysRq'. The 'SysRq' key is
            also known as the 'Print Screen' key. Also some keyboards cannot
@@ -58,14 +59,15 @@ On x86   - You press the key combo :kbd:`ALT-SysRq-<command key>`.
           have better luck with press :kbd:`Alt`, press :kbd:`SysRq`,
           release :kbd:`SysRq`, press :kbd:`<command key>`, release everything.
 
-On SPARC - You press :kbd:`ALT-STOP-<command key>`, I believe.
+On SPARC
+       You press :kbd:`ALT-STOP-<command key>`, I believe.
 
 On the serial console (PC style standard serial ports only)
         You send a ``BREAK``, then within 5 seconds a command key. Sending
         ``BREAK`` twice is interpreted as a normal BREAK.
 
 On PowerPC
-       Press :kbd:`ALT - Print Screen` (or :kbd:`F13`) - :kbd:`<command key>`,
+       Press :kbd:`ALT - Print Screen` (or :kbd:`F13`) - :kbd:`<command key>`.
         :kbd:`Print Screen` (or :kbd:`F13`) - :kbd:`<command key>` may suffice.
 
 On other
@@ -73,7 +75,7 @@ On other
         let me know so I can add them to this section.
 
 On all
-       write a character to /proc/sysrq-trigger.  e.g.::
+       Write a character to /proc/sysrq-trigger.  e.g.::
 
                echo t > /proc/sysrq-trigger
 
@@ -282,7 +284,7 @@ Just ask them on the linux-kernel mailing list:
 Credits
 ~~~~~~~
 
-Written by Mydraal <vulpyne@vulpyne.net>
-Updated by Adam Sulmicki <adam@cfar.umd.edu>
-Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59
-Added to by Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+Written by Mydraal <vulpyne@vulpyne.net>
+Updated by Adam Sulmicki <adam@cfar.umd.edu>
+Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59
+Added to by Crutcher Dunnavant <crutcher+kernel@datastacks.com>
index d98a9bf..193e71c 100644 (file)
@@ -1,9 +1,10 @@
-* Aspeed KCS (Keyboard Controller Style) IPMI interface
+# Aspeed KCS (Keyboard Controller Style) IPMI interface
 
 The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
 (Baseboard Management Controllers) and the KCS interface can be
 used to perform in-band IPMI communication with their host.
 
+## v1
 Required properties:
 - compatible : should be one of
     "aspeed,ast2400-kcs-bmc"
@@ -12,14 +13,21 @@ Required properties:
 - kcs_chan : The LPC channel number in the controller
 - kcs_addr : The host CPU IO map address
 
+## v2
+Required properties:
+- compatible : should be one of
+    "aspeed,ast2400-kcs-bmc-v2"
+    "aspeed,ast2500-kcs-bmc-v2"
+- reg : The address and size of the IDR, ODR and STR registers
+- interrupts : interrupt generated by the controller
+- aspeed,lpc-io-reg : The host CPU LPC IO address for the device
 
 Example:
 
-    kcs3: kcs3@0 {
-        compatible = "aspeed,ast2500-kcs-bmc";
-        reg = <0x0 0x80>;
+    kcs3: kcs@24 {
+        compatible = "aspeed,ast2500-kcs-bmc-v2";
+        reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
+        aspeed,lpc-reg = <0xca2>;
         interrupts = <8>;
-        kcs_chan = <3>;
-        kcs_addr = <0xCA2>;
         status = "okay";
     };
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt
deleted file mode 100644 (file)
index 472bd46..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-* PWM controlled by ChromeOS EC
-
-Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
-(EC) and controlled via a host-command interface.
-
-An EC PWM node should be only found as a sub-node of the EC node (see
-Documentation/devicetree/bindings/mfd/cros-ec.txt).
-
-Required properties:
-- compatible: Must contain "google,cros-ec-pwm"
-- #pwm-cells: Should be 1. The cell specifies the PWM index.
-
-Example:
-       cros-ec@0 {
-               compatible = "google,cros-ec-spi";
-
-               ...
-
-               cros_ec_pwm: ec-pwm {
-                       compatible = "google,cros-ec-pwm";
-                       #pwm-cells = <1>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml
new file mode 100644 (file)
index 0000000..24c217b
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/google,cros-ec-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM controlled by ChromeOS EC
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - '"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>'
+
+description: |
+  Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
+  (EC) and controlled via a host-command interface.
+  An EC PWM node should be only found as a sub-node of the EC node (see
+  Documentation/devicetree/bindings/mfd/cros-ec.txt).
+
+properties:
+  compatible:
+    const: google,cros-ec-pwm
+  "#pwm-cells":
+    description: The cell specifies the PWM index.
+    const: 1
+
+required:
+  - compatible
+  - '#pwm-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    cros-ec@0 {
+        compatible = "google,cros-ec-spi";
+        cros_ec_pwm: ec-pwm {
+            compatible = "google,cros-ec-pwm";
+            #pwm-cells = <1>;
+        };
+    };
index 0a69ead..74c41e3 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
   - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132
   - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
   - "nvidia,tegra186-pwm": for Tegra186
+  - "nvidia,tegra194-pwm": for Tegra194
 - reg: physical base address and length of the controller's registers
 - #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
index efce847..83f44f0 100644 (file)
@@ -49,7 +49,7 @@ required:
 examples:
   - |
     #include <dt-bindings/gpio/gpio.h>
-    i2c@0 {
+    i2c {
       #address-cells = <1>;
       #size-cells = <0>;
 
index 4fe1c06..0b3d9ff 100644 (file)
@@ -314,11 +314,8 @@ http://www.linux-usb.org/
 Linux Hotplug Project:
 http://linux-hotplug.sourceforge.net/
 
-Linux USB Working Devices List:
-http://www.qbik.ch/usb/devices/
-
-linux-usb-devel Mailing List Archives:
-http://marc.theaimsgroup.com/?l=linux-usb-devel
+linux-usb Mailing List Archives:
+https://lore.kernel.org/linux-usb/
 
 Programming Guide for Linux USB Device Drivers:
 http://lmu.web.psi.ch/docu/manuals/software_manuals/linux_sl/usb_linux_programming_guide.pdf
index 9963cca..bda3ad6 100644 (file)
@@ -7,9 +7,6 @@ W1: Dallas' 1-wire bus
 W1 API internal to the kernel
 =============================
 
-W1 API internal to the kernel
------------------------------
-
 include/linux/w1.h
 ~~~~~~~~~~~~~~~~~~
 
index 7d6d4ca..e413697 100644 (file)
@@ -41,16 +41,6 @@ Documentation
 
 http://www.orangefs.org/documentation/
 
-
-Userspace Filesystem Source
-===========================
-
-http://www.orangefs.org/download
-
-Orangefs versions prior to 2.9.3 would not be compatible with the
-upstream version of the kernel client.
-
-
 Running ORANGEFS On a Single Server
 ===================================
 
@@ -94,6 +84,14 @@ Mount the filesystem::
 
     mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
 
+Userspace Filesystem Source
+===========================
+
+http://www.orangefs.org/download
+
+Orangefs versions prior to 2.9.3 would not be compatible with the
+upstream version of the kernel client.
+
 
 Building ORANGEFS on a Single Server
 ====================================
@@ -107,18 +105,24 @@ default, we will probably be changing the default to LMDB soon.
 
 ::
 
-    ./configure --prefix=/opt/ofs --with-db-backend=lmdb
+    ./configure --prefix=/opt/ofs --with-db-backend=lmdb --disable-usrint
 
     make
 
     make install
 
-Create an orangefs config file::
+Create an orangefs config file by running pvfs2-genconfig and
+specifying a target config file. Pvfs2-genconfig will prompt you
+through. Generally it works fine to take the defaults, but you
+should use your server's hostname, rather than "localhost" when
+it comes to that question::
 
     /opt/ofs/bin/pvfs2-genconfig /etc/pvfs2.conf
 
 Create an /etc/pvfs2tab file::
 
+Localhost is fine for your pvfs2tab file:
+
     echo tcp://localhost:3334/orangefs /pvfsmnt pvfs2 defaults,noauto 0 0 > \
        /etc/pvfs2tab
 
@@ -132,7 +136,7 @@ Bootstrap the server::
 
 Start the server::
 
-    /opt/osf/sbin/pvfs2-server /etc/pvfs2.conf
+    /opt/ofs/sbin/pvfs2-server /etc/pvfs2.conf
 
 Now the server should be running. Pvfs2-ls is a simple
 test to verify that the server is running::
@@ -142,11 +146,11 @@ test to verify that the server is running::
 If stuff seems to be working, load the kernel module and
 turn on the client core::
 
-    /opt/ofs/sbin/pvfs2-client -p /opt/osf/sbin/pvfs2-client-core
+    /opt/ofs/sbin/pvfs2-client -p /opt/ofs/sbin/pvfs2-client-core
 
 Mount your filesystem::
 
-    mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
+    mount -t pvfs2 tcp://`hostname`:3334/orangefs /pvfsmnt
 
 
 Running xfstests
index b713083..fd13433 100644 (file)
@@ -185,7 +185,7 @@ tree structures are treated as system blocks.
 
 The rational behind that is that a write request can work on a new snapshot
 (system area of the inactive - resp. lower serial numbered superblock) while
-at the same time there is still a complete stable filesystem structer in the
+at the same time there is still a complete stable filesystem structure in the
 other half of the system area.
 
 When finished with writing (a sync write is completed, the maximum sync leap
index 3eb763d..6193582 100644 (file)
@@ -56,13 +56,13 @@ are illustrated in the following diagram::
                   +- - - -+                  |  +-------------------| |
                   | Entry | - - - - - - - -+ |  | Definition Blocks | |
                   +- - - -+                | |  +-------------------+ |
-                                          | |  +- - - - - - - - - -+ |
-                                          +-|->|       SSDT        | |
+                                           | |  +- - - - - - - - - -+ |
+                                           +-|->|       SSDT        | |
                                              |  +-------------------+ |
                                              |  | Definition Blocks | |
                                              |  +- - - - - - - - - -+ |
                                              +------------------------+
-                                                         |
+                                                          |
                                              OSPM Loading |
                                                          \|/
                                                    +----------------+
index e577f85..86a3796 100644 (file)
@@ -325,7 +325,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
 
 /**
  * struct qdio_initialize - qdio initialization data
- * @cdev: associated ccw device
  * @q_format: queue format
  * @qdr_ac: feature flags to set
  * @adapter_name: name for the adapter
@@ -341,12 +340,11 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
  * @irq_poll: Data IRQ polling handler (NULL when not supported)
  * @scan_threshold: # of in-use buffers that triggers scan on output queue
  * @int_parm: interruption parameter
- * @input_sbal_addr_array:  address of no_input_qs * 128 pointers
- * @output_sbal_addr_array: address of no_output_qs * 128 pointers
+ * @input_sbal_addr_array:  per-queue array, each element points to 128 SBALs
+ * @output_sbal_addr_array: per-queue array, each element points to 128 SBALs
  * @output_sbal_state_array: no_output_qs * 128 state info (for CQ or NULL)
  */
 struct qdio_initialize {
-       struct ccw_device *cdev;
        unsigned char q_format;
        unsigned char qdr_ac;
        unsigned char adapter_name[8];
@@ -362,8 +360,8 @@ struct qdio_initialize {
        void (*irq_poll)(struct ccw_device *cdev, unsigned long data);
        unsigned int scan_threshold;
        unsigned long int_parm;
-       struct qdio_buffer **input_sbal_addr_array;
-       struct qdio_buffer **output_sbal_addr_array;
+       struct qdio_buffer ***input_sbal_addr_array;
+       struct qdio_buffer ***output_sbal_addr_array;
        struct qdio_outbuf_state *output_sbal_state_array;
 };
 
@@ -408,8 +406,10 @@ int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count);
 void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count);
 void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count);
 
-extern int qdio_allocate(struct qdio_initialize *);
-extern int qdio_establish(struct qdio_initialize *);
+extern int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
+                        unsigned int no_output_qs);
+extern int qdio_establish(struct ccw_device *cdev,
+                         struct qdio_initialize *init_data);
 extern int qdio_activate(struct ccw_device *);
 extern void qdio_release_aob(struct qaob *);
 extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
index 9822a1f..dedc28b 100644 (file)
@@ -852,9 +852,7 @@ void do_secure_storage_access(struct pt_regs *regs)
                        BUG();
                break;
        case VDSO_FAULT:
-               /* fallthrough */
        case GMAP_FAULT:
-               /* fallthrough */
        default:
                do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP);
                WARN_ON_ONCE(1);
index 1ae5439..683ed9e 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(acpi_disabled);
 #define PREFIX                 "ACPI: "
 
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
-int acpi_nobgrt;                       /* skip ACPI BGRT */
+static int acpi_nobgrt;                        /* skip ACPI BGRT */
 int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
index 33b0e20..1a2d8a5 100644 (file)
@@ -985,7 +985,7 @@ void xen_enable_syscall(void)
 #endif /* CONFIG_X86_64 */
 }
 
-void __init xen_pvmmu_arch_setup(void)
+static void __init xen_pvmmu_arch_setup(void)
 {
        HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
        HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
index 7d1c4fc..1ba601d 100644 (file)
@@ -38,7 +38,7 @@ SYM_CODE_START(startup_xen)
 #ifdef CONFIG_X86_64
        mov initial_stack(%rip), %rsp
 #else
-       mov pa(initial_stack), %esp
+       mov initial_stack, %esp
 #endif
 
 #ifdef CONFIG_X86_64
index de22942..3a9f1e8 100644 (file)
@@ -122,7 +122,7 @@ config XTENSA_VARIANT_CUSTOM_NAME
        help
          Provide the name of a custom Xtensa processor variant.
          This CORENAME selects arch/xtensa/variant/CORENAME.
-         Dont forget you have to select MMU if you have one.
+         Don't forget you have to select MMU if you have one.
 
 config XTENSA_VARIANT_NAME
        string
index efb91bf..1a14d38 100644 (file)
@@ -14,7 +14,6 @@ HOSTFLAGS     += -Iarch/$(ARCH)/boot/include
 
 BIG_ENDIAN     := $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
 
-export ccflags-y
 export BIG_ENDIAN
 
 subdir-y       := lib
index 83b244c..cd85a7a 100644 (file)
@@ -53,16 +53,12 @@ static void system_flush_invalidate_dcache_range(unsigned long start,
 #define IPI_IRQ        0
 
 static irqreturn_t ipi_interrupt(int irq, void *dev_id);
-static struct irqaction ipi_irqaction = {
-       .handler =      ipi_interrupt,
-       .flags =        IRQF_PERCPU,
-       .name =         "ipi",
-};
 
 void ipi_init(void)
 {
        unsigned irq = irq_create_mapping(NULL, IPI_IRQ);
-       setup_irq(irq, &ipi_irqaction);
+       if (request_irq(irq, ipi_interrupt, IRQF_PERCPU, "ipi", NULL))
+               pr_err("Failed to request irq %u (ipi)\n", irq);
 }
 
 static inline unsigned int get_core_count(void)
index 69db8c9..77971fe 100644 (file)
@@ -128,12 +128,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction timer_irqaction = {
-       .handler =      timer_interrupt,
-       .flags =        IRQF_TIMER,
-       .name =         "timer",
-};
-
 void local_timer_setup(unsigned cpu)
 {
        struct ccount_timer *timer = &per_cpu(ccount_timer, cpu);
@@ -184,6 +178,8 @@ static inline void calibrate_ccount(void)
 
 void __init time_init(void)
 {
+       int irq;
+
        of_clk_init(NULL);
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        pr_info("Calibrating CPU frequency ");
@@ -199,7 +195,9 @@ void __init time_init(void)
             __func__);
        clocksource_register_hz(&ccount_clocksource, ccount_freq);
        local_timer_setup(0);
-       setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
+       irq = this_cpu_ptr(&ccount_timer)->evt.irq;
+       if (request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL))
+               pr_err("Failed to request irq %d (timer)\n", irq);
        sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
        timer_probe();
 }
index c15a260..c5dc833 100644 (file)
@@ -883,8 +883,8 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
        /* this prevents anyone from attaching or migrating to this blkcg */
        wb_blkcg_offline(blkcg);
 
-       /* put the base cgwb reference allowing step 2 to be triggered */
-       blkcg_cgwb_put(blkcg);
+       /* put the base online pin allowing step 2 to be triggered */
+       blkcg_unpin_online(blkcg);
 }
 
 /**
@@ -983,11 +983,11 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
        }
 
        spin_lock_init(&blkcg->lock);
+       refcount_set(&blkcg->online_pin, 1);
        INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN);
        INIT_HLIST_HEAD(&blkcg->blkg_list);
 #ifdef CONFIG_CGROUP_WRITEBACK
        INIT_LIST_HEAD(&blkcg->cgwb_list);
-       refcount_set(&blkcg->cgwb_refcnt, 1);
 #endif
        list_add_tail(&blkcg->all_blkcgs_node, &all_blkcgs);
 
@@ -1006,6 +1006,21 @@ unlock:
        return ret;
 }
 
+static int blkcg_css_online(struct cgroup_subsys_state *css)
+{
+       struct blkcg *blkcg = css_to_blkcg(css);
+       struct blkcg *parent = blkcg_parent(blkcg);
+
+       /*
+        * blkcg_pin_online() is used to delay blkcg offline so that blkgs
+        * don't go offline while cgwbs are still active on them.  Pin the
+        * parent so that offline always happens towards the root.
+        */
+       if (parent)
+               blkcg_pin_online(parent);
+       return 0;
+}
+
 /**
  * blkcg_init_queue - initialize blkcg part of request queue
  * @q: request_queue to initialize
@@ -1199,6 +1214,7 @@ static void blkcg_exit(struct task_struct *tsk)
 
 struct cgroup_subsys io_cgrp_subsys = {
        .css_alloc = blkcg_css_alloc,
+       .css_online = blkcg_css_online,
        .css_offline = blkcg_css_offline,
        .css_free = blkcg_css_free,
        .can_attach = blkcg_can_attach,
index f6291ce..8e56884 100644 (file)
@@ -1289,7 +1289,7 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
                 * the driver there was more coming, but that turned out to
                 * be a lie.
                 */
-               if (q->mq_ops->commit_rqs)
+               if (q->mq_ops->commit_rqs && queued)
                        q->mq_ops->commit_rqs(hctx);
 
                spin_lock(&hctx->lock);
@@ -1911,6 +1911,8 @@ blk_status_t blk_mq_request_issue_directly(struct request *rq, bool last)
 void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                struct list_head *list)
 {
+       int queued = 0;
+
        while (!list_empty(list)) {
                blk_status_t ret;
                struct request *rq = list_first_entry(list, struct request,
@@ -1926,7 +1928,8 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                                break;
                        }
                        blk_mq_end_request(rq, ret);
-               }
+               } else
+                       queued++;
        }
 
        /*
@@ -1934,7 +1937,7 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
         * the driver there was more coming, but that turned out to
         * be a lie.
         */
-       if (!list_empty(list) && hctx->queue->mq_ops->commit_rqs)
+       if (!list_empty(list) && hctx->queue->mq_ops->commit_rqs && queued)
                hctx->queue->mq_ops->commit_rqs(hctx);
 }
 
index b79c451..bc1ded1 100644 (file)
@@ -496,7 +496,7 @@ int blk_drop_partitions(struct gendisk *disk, struct block_device *bdev)
 
        if (!disk_part_scan_enabled(disk))
                return 0;
-       if (bdev->bd_part_count || bdev->bd_super)
+       if (bdev->bd_part_count || bdev->bd_openers > 1)
                return -EBUSY;
        res = invalidate_partition(disk, 0);
        if (res)
index 4816df5..b4c0152 100644 (file)
@@ -1589,8 +1589,8 @@ static int acpi_ec_add(struct acpi_device *device)
        strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 
-       if ((boot_ec && boot_ec->handle == device->handle) ||
-           !strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
+       if (boot_ec && (boot_ec->handle == device->handle ||
+           !strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) {
                /* Fast path: this device corresponds to the boot EC. */
                ec = boot_ec;
        } else {
index ad0185c..0101b65 100644 (file)
@@ -410,6 +410,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */
        { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_mobile }, /* ApolloLake AHCI */
        { PCI_VDEVICE(INTEL, 0x34d3), board_ahci_mobile }, /* Ice Lake LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x02d7), board_ahci_mobile }, /* Comet Lake PCH RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1495,7 +1496,7 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
 static void ahci_remap_check(struct pci_dev *pdev, int bar,
                struct ahci_host_priv *hpriv)
 {
-       int i, count = 0;
+       int i;
        u32 cap;
 
        /*
@@ -1516,13 +1517,14 @@ static void ahci_remap_check(struct pci_dev *pdev, int bar,
                        continue;
 
                /* We've found a remapped device */
-               count++;
+               hpriv->remapped_nvme++;
        }
 
-       if (!count)
+       if (!hpriv->remapped_nvme)
                return;
 
-       dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count);
+       dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
+                hpriv->remapped_nvme);
        dev_warn(&pdev->dev,
                 "Switch your BIOS from RAID to AHCI mode to use them.\n");
 
@@ -1642,6 +1644,18 @@ static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hp
        }
 }
 
+static ssize_t remapped_nvme_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       return sprintf(buf, "%u\n", hpriv->remapped_nvme);
+}
+
+static DEVICE_ATTR_RO(remapped_nvme);
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int board_id = ent->driver_data;
@@ -1745,6 +1759,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* detect remapped nvme devices */
        ahci_remap_check(pdev, ahci_pci_bar, hpriv);
 
+       sysfs_add_file_to_group(&pdev->dev.kobj,
+                               &dev_attr_remapped_nvme.attr,
+                               NULL);
+
        /* must set flag prior to save config in order to take effect */
        if (ahci_broken_devslp(pdev))
                hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
@@ -1896,6 +1914,9 @@ static void ahci_shutdown_one(struct pci_dev *pdev)
 
 static void ahci_remove_one(struct pci_dev *pdev)
 {
+       sysfs_remove_file_from_group(&pdev->dev.kobj,
+                                    &dev_attr_remapped_nvme.attr,
+                                    NULL);
        pm_runtime_get_noresume(&pdev->dev);
        ata_pci_remove_one(pdev);
 }
index 3dbf398..d991dd4 100644 (file)
@@ -336,6 +336,7 @@ struct ahci_host_priv {
        u32                     em_loc; /* enclosure management location */
        u32                     em_buf_sz;      /* EM buffer size in byte */
        u32                     em_msg_type;    /* EM message type */
+       u32                     remapped_nvme;  /* NVMe remapped device count */
        bool                    got_runtime_pm; /* Did we do pm_runtime_get? */
        struct clk              *clks[AHCI_MAX_CLKS]; /* Optional */
        struct reset_control    *rsts;          /* Optional */
index 948d2c6..388baf5 100644 (file)
@@ -782,7 +782,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
        struct ata_host *host = dev_get_drvdata(ap->dev);
        struct ahci_host_priv *hpriv = host->private_data;
        struct imx_ahci_priv *imxpriv = hpriv->plat_data;
-       int ret = -EIO;
+       int ret;
 
        if (imxpriv->type == AHCI_IMX53)
                ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
index 3ff1407..79f2aee 100644 (file)
@@ -763,6 +763,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
 
        if (dev->flags & ATA_DFLAG_DETACH) {
                detach = 1;
+               rc = -ENODEV;
                goto fail;
        }
 
index a42c49e..da693e6 100644 (file)
@@ -429,11 +429,12 @@ static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos,
         * information.
         */
        struct file *file = lo->lo_backing_file;
+       struct request_queue *q = lo->lo_queue;
        int ret;
 
        mode |= FALLOC_FL_KEEP_SIZE;
 
-       if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
+       if (!blk_queue_discard(q)) {
                ret = -EOPNOTSUPP;
                goto out;
        }
@@ -463,7 +464,7 @@ static void lo_complete_rq(struct request *rq)
        if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
            req_op(rq) != REQ_OP_READ) {
                if (cmd->ret < 0)
-                       ret = BLK_STS_IOERR;
+                       ret = errno_to_blk_status(cmd->ret);
                goto end_io;
        }
 
@@ -868,27 +869,46 @@ static void loop_config_discard(struct loop_device *lo)
        struct request_queue *q = lo->lo_queue;
 
        /*
+        * If the backing device is a block device, mirror its zeroing
+        * capability. Set the discard sectors to the block device's zeroing
+        * capabilities because loop discards result in blkdev_issue_zeroout(),
+        * not blkdev_issue_discard(). This maintains consistent behavior with
+        * file-backed loop devices: discarded regions read back as zero.
+        */
+       if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) {
+               struct request_queue *backingq;
+
+               backingq = bdev_get_queue(inode->i_bdev);
+               blk_queue_max_discard_sectors(q,
+                       backingq->limits.max_write_zeroes_sectors);
+
+               blk_queue_max_write_zeroes_sectors(q,
+                       backingq->limits.max_write_zeroes_sectors);
+
+       /*
         * We use punch hole to reclaim the free space used by the
         * image a.k.a. discard. However we do not support discard if
         * encryption is enabled, because it may give an attacker
         * useful information.
         */
-       if ((!file->f_op->fallocate) ||
-           lo->lo_encrypt_key_size) {
+       } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) {
                q->limits.discard_granularity = 0;
                q->limits.discard_alignment = 0;
                blk_queue_max_discard_sectors(q, 0);
                blk_queue_max_write_zeroes_sectors(q, 0);
-               blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
-               return;
-       }
 
-       q->limits.discard_granularity = inode->i_sb->s_blocksize;
-       q->limits.discard_alignment = 0;
+       } else {
+               q->limits.discard_granularity = inode->i_sb->s_blocksize;
+               q->limits.discard_alignment = 0;
+
+               blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
+               blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
+       }
 
-       blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
-       blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
-       blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+       if (q->limits.max_write_zeroes_sectors)
+               blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+       else
+               blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
 }
 
 static void loop_unprepare_queue(struct loop_device *lo)
@@ -1955,7 +1975,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
  failed:
        /* complete non-aio request */
        if (!cmd->use_aio || ret) {
-               cmd->ret = ret ? -EIO : 0;
+               if (ret == -EOPNOTSUPP)
+                       cmd->ret = ret;
+               else
+                       cmd->ret = ret ? -EIO : 0;
                blk_mq_complete_request(rq);
        }
 }
index 915cf5b..3b889ea 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/bitmap.h>
 #include <linux/list.h>
 #include <linux/workqueue.h>
+#include <linux/sched/mm.h>
 
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -2189,10 +2190,12 @@ static void blkfront_setup_discard(struct blkfront_info *info)
 
 static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
 {
-       unsigned int psegs, grants;
+       unsigned int psegs, grants, memflags;
        int err, i;
        struct blkfront_info *info = rinfo->dev_info;
 
+       memflags = memalloc_noio_save();
+
        if (info->max_indirect_segments == 0) {
                if (!HAS_EXTRA_REQ)
                        grants = BLKIF_MAX_SEGMENTS_PER_REQUEST;
@@ -2224,7 +2227,7 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
 
                BUG_ON(!list_empty(&rinfo->indirect_pages));
                for (i = 0; i < num; i++) {
-                       struct page *indirect_page = alloc_page(GFP_NOIO);
+                       struct page *indirect_page = alloc_page(GFP_KERNEL);
                        if (!indirect_page)
                                goto out_of_memory;
                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2235,15 +2238,15 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
                rinfo->shadow[i].grants_used =
                        kvcalloc(grants,
                                 sizeof(rinfo->shadow[i].grants_used[0]),
-                                GFP_NOIO);
+                                GFP_KERNEL);
                rinfo->shadow[i].sg = kvcalloc(psegs,
                                               sizeof(rinfo->shadow[i].sg[0]),
-                                              GFP_NOIO);
+                                              GFP_KERNEL);
                if (info->max_indirect_segments)
                        rinfo->shadow[i].indirect_grants =
                                kvcalloc(INDIRECT_GREFS(grants),
                                         sizeof(rinfo->shadow[i].indirect_grants[0]),
-                                        GFP_NOIO);
+                                        GFP_KERNEL);
                if ((rinfo->shadow[i].grants_used == NULL) ||
                        (rinfo->shadow[i].sg == NULL) ||
                     (info->max_indirect_segments &&
@@ -2252,6 +2255,7 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
                sg_init_table(rinfo->shadow[i].sg, psegs);
        }
 
+       memalloc_noio_restore(memflags);
 
        return 0;
 
@@ -2271,6 +2275,9 @@ out_of_memory:
                        __free_page(indirect_page);
                }
        }
+
+       memalloc_noio_restore(memflags);
+
        return -ENOMEM;
 }
 
index cad9563..c48d8f0 100644 (file)
@@ -618,6 +618,8 @@ static DEFINE_MUTEX(ipmidriver_mutex);
 
 static LIST_HEAD(ipmi_interfaces);
 static DEFINE_MUTEX(ipmi_interfaces_mutex);
+#define ipmi_interfaces_mutex_held() \
+       lockdep_is_held(&ipmi_interfaces_mutex)
 static struct srcu_struct ipmi_interfaces_srcu;
 
 /*
@@ -1321,7 +1323,8 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
         * synchronize_srcu()) then free everything in that list.
         */
        mutex_lock(&intf->cmd_rcvrs_mutex);
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if (rcvr->user == user) {
                        list_del_rcu(&rcvr->link);
                        rcvr->next = rcvrs;
@@ -1599,7 +1602,8 @@ static struct cmd_rcvr *find_cmd_rcvr(struct ipmi_smi *intf,
 {
        struct cmd_rcvr *rcvr;
 
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
                                        && (rcvr->chans & (1 << chan)))
                        return rcvr;
@@ -1614,7 +1618,8 @@ static int is_cmd_rcvr_exclusive(struct ipmi_smi *intf,
 {
        struct cmd_rcvr *rcvr;
 
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
                                        && (rcvr->chans & chans))
                        return 0;
@@ -3188,8 +3193,8 @@ static void __get_guid(struct ipmi_smi *intf)
        if (rv)
                /* Send failed, no GUID available. */
                bmc->dyn_guid_set = 0;
-
-       wait_event(intf->waitq, bmc->dyn_guid_set != 2);
+       else
+               wait_event(intf->waitq, bmc->dyn_guid_set != 2);
 
        /* dyn_guid_set makes the guid data available. */
        smp_rmb();
@@ -3450,7 +3455,8 @@ int ipmi_add_smi(struct module         *owner,
        /* Look for a hole in the numbers. */
        i = 0;
        link = &ipmi_interfaces;
-       list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
+       list_for_each_entry_rcu(tintf, &ipmi_interfaces, link,
+                               ipmi_interfaces_mutex_held()) {
                if (tintf->intf_num != i) {
                        link = &tintf->link;
                        break;
index 8ac390c..b7145f3 100644 (file)
@@ -313,6 +313,7 @@ static int start_send(struct ssif_info *ssif_info,
 
 static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info,
                                          unsigned long *flags)
+       __acquires(&ssif_info->lock)
 {
        spin_lock_irqsave(&ssif_info->lock, *flags);
        return flags;
@@ -320,6 +321,7 @@ static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info,
 
 static void ipmi_ssif_unlock_cond(struct ssif_info *ssif_info,
                                  unsigned long *flags)
+       __releases(&ssif_info->lock)
 {
        spin_unlock_irqrestore(&ssif_info->lock, *flags);
 }
index 3c95594..a140203 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/regmap.h>
@@ -233,58 +234,154 @@ static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
        { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
 };
 
-static int aspeed_kcs_probe(struct platform_device *pdev)
+static struct kcs_bmc *aspeed_kcs_probe_of_v1(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
        struct aspeed_kcs_bmc *priv;
-       struct kcs_bmc *kcs_bmc;
-       u32 chan, addr;
+       struct device_node *np;
+       struct kcs_bmc *kcs;
+       u32 channel;
+       u32 slave;
        int rc;
 
-       rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
-       if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
-               dev_err(dev, "no valid 'kcs_chan' configured\n");
-               return -ENODEV;
+       np = pdev->dev.of_node;
+
+       rc = of_property_read_u32(np, "kcs_chan", &channel);
+       if ((rc != 0) || (channel == 0 || channel > KCS_CHANNEL_MAX)) {
+               dev_err(&pdev->dev, "no valid 'kcs_chan' configured\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
+       if (!kcs)
+               return ERR_PTR(-ENOMEM);
+
+       priv = kcs_bmc_priv(kcs);
+       priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+       if (IS_ERR(priv->map)) {
+               dev_err(&pdev->dev, "Couldn't get regmap\n");
+               return ERR_PTR(-ENODEV);
        }
 
-       rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
+       rc = of_property_read_u32(np, "kcs_addr", &slave);
        if (rc) {
-               dev_err(dev, "no valid 'kcs_addr' configured\n");
-               return -ENODEV;
+               dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       kcs->ioreg = ast_kcs_bmc_ioregs[channel - 1];
+       aspeed_kcs_set_address(kcs, slave);
+
+       return kcs;
+}
+
+static int aspeed_kcs_calculate_channel(const struct kcs_ioreg *regs)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) {
+               if (!memcmp(&ast_kcs_bmc_ioregs[i], regs, sizeof(*regs)))
+                       return i + 1;
        }
 
-       kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
-       if (!kcs_bmc)
-               return -ENOMEM;
+       return -EINVAL;
+}
+
+static struct kcs_bmc *aspeed_kcs_probe_of_v2(struct platform_device *pdev)
+{
+       struct aspeed_kcs_bmc *priv;
+       struct device_node *np;
+       struct kcs_ioreg ioreg;
+       struct kcs_bmc *kcs;
+       const __be32 *reg;
+       int channel;
+       u32 slave;
+       int rc;
+
+       np = pdev->dev.of_node;
+
+       /* Don't translate addresses, we want offsets for the regmaps */
+       reg = of_get_address(np, 0, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.idr = be32_to_cpup(reg);
+
+       reg = of_get_address(np, 1, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.odr = be32_to_cpup(reg);
+
+       reg = of_get_address(np, 2, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.str = be32_to_cpup(reg);
 
-       priv = kcs_bmc_priv(kcs_bmc);
-       priv->map = syscon_node_to_regmap(dev->parent->of_node);
+       channel = aspeed_kcs_calculate_channel(&ioreg);
+       if (channel < 0)
+               return ERR_PTR(channel);
+
+       kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
+       if (!kcs)
+               return ERR_PTR(-ENOMEM);
+
+       kcs->ioreg = ioreg;
+
+       priv = kcs_bmc_priv(kcs);
+       priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
        if (IS_ERR(priv->map)) {
-               dev_err(dev, "Couldn't get regmap\n");
-               return -ENODEV;
+               dev_err(&pdev->dev, "Couldn't get regmap\n");
+               return ERR_PTR(-ENODEV);
        }
 
-       kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
+       rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &slave);
+       if (rc)
+               return ERR_PTR(rc);
+
+       aspeed_kcs_set_address(kcs, slave);
+
+       return kcs;
+}
+
+static int aspeed_kcs_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct kcs_bmc *kcs_bmc;
+       struct device_node *np;
+       int rc;
+
+       np = pdev->dev.of_node;
+       if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc") ||
+                       of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc"))
+               kcs_bmc = aspeed_kcs_probe_of_v1(pdev);
+       else if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc-v2") ||
+                       of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2"))
+               kcs_bmc = aspeed_kcs_probe_of_v2(pdev);
+       else
+               return -EINVAL;
+
+       if (IS_ERR(kcs_bmc))
+               return PTR_ERR(kcs_bmc);
+
        kcs_bmc->io_inputb = aspeed_kcs_inb;
        kcs_bmc->io_outputb = aspeed_kcs_outb;
 
-       dev_set_drvdata(dev, kcs_bmc);
-
-       aspeed_kcs_set_address(kcs_bmc, addr);
-       aspeed_kcs_enable_channel(kcs_bmc, true);
        rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
        if (rc)
                return rc;
 
+       dev_set_drvdata(dev, kcs_bmc);
+
+       aspeed_kcs_enable_channel(kcs_bmc, true);
+
        rc = misc_register(&kcs_bmc->miscdev);
        if (rc) {
                dev_err(dev, "Unable to register device\n");
                return rc;
        }
 
-       pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
-               chan, addr,
-               kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
+       dev_dbg(&pdev->dev,
+               "Probed KCS device %d (IDR=0x%x, ODR=0x%x, STR=0x%x)\n",
+               kcs_bmc->channel, kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr,
+               kcs_bmc->ioreg.str);
 
        return 0;
 }
@@ -301,6 +398,8 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
 static const struct of_device_id ast_kcs_bmc_match[] = {
        { .compatible = "aspeed,ast2400-kcs-bmc" },
        { .compatible = "aspeed,ast2500-kcs-bmc" },
+       { .compatible = "aspeed,ast2400-kcs-bmc-v2" },
+       { .compatible = "aspeed,ast2500-kcs-bmc-v2" },
        { }
 };
 MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
index db124bc..fcc5321 100644 (file)
@@ -94,7 +94,7 @@ static void haltpoll_uninit(void)
        haltpoll_cpuidle_devices = NULL;
 }
 
-static bool haltpool_want(void)
+static bool haltpoll_want(void)
 {
        return kvm_para_has_hint(KVM_HINTS_REALTIME) || force;
 }
@@ -110,7 +110,7 @@ static int __init haltpoll_init(void)
 
        cpuidle_poll_state_init(drv);
 
-       if (!kvm_para_available() || !haltpool_want())
+       if (!kvm_para_available() || !haltpoll_want())
                return -ENODEV;
 
        ret = cpuidle_register_driver(drv);
index 29906e3..14d0970 100644 (file)
@@ -341,7 +341,7 @@ edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
+       p += scnprintf(p, left, "%u\n", info->legacy_max_cylinder);
        return (p - buf);
 }
 
@@ -356,7 +356,7 @@ edd_show_legacy_max_head(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_max_head);
+       p += scnprintf(p, left, "%u\n", info->legacy_max_head);
        return (p - buf);
 }
 
@@ -371,7 +371,7 @@ edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
+       p += scnprintf(p, left, "%u\n", info->legacy_sectors_per_track);
        return (p - buf);
 }
 
index faa3e71..559dc24 100644 (file)
@@ -2340,8 +2340,6 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
 {
        int i, r;
 
-       amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
-       amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
                if (!adev->ip_blocks[i].status.valid)
@@ -3356,6 +3354,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
                }
        }
 
+       amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
+       amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
+
        amdgpu_amdkfd_suspend(adev, !fbcon);
 
        amdgpu_ras_suspend(adev);
index f197f1b..abe94a5 100644 (file)
@@ -89,7 +89,8 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
                        adev->pm.ac_power = true;
                else
                        adev->pm.ac_power = false;
-               if (adev->powerplay.pp_funcs->enable_bapm)
+               if (adev->powerplay.pp_funcs &&
+                   adev->powerplay.pp_funcs->enable_bapm)
                        amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
                mutex_unlock(&adev->pm.mutex);
 
index be50867..deaa268 100644 (file)
@@ -818,7 +818,7 @@ static int psp_ras_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_ras_ucode_size ||
            !psp->adev->psp.ta_ras_start_addr) {
-               dev_warn(psp->adev->dev, "RAS: ras ta ucode is not available\n");
+               dev_info(psp->adev->dev, "RAS: optional ras ta ucode is not available\n");
                return 0;
        }
 
@@ -902,7 +902,7 @@ static int psp_hdcp_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_hdcp_ucode_size ||
            !psp->adev->psp.ta_hdcp_start_addr) {
-               dev_warn(psp->adev->dev, "HDCP: hdcp ta ucode is not available\n");
+               dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n");
                return 0;
        }
 
@@ -1048,7 +1048,7 @@ static int psp_dtm_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_dtm_ucode_size ||
            !psp->adev->psp.ta_dtm_start_addr) {
-               dev_warn(psp->adev->dev, "DTM: dtm ta ucode is not available\n");
+               dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n");
                return 0;
        }
 
index 3c32a94..ab379b4 100644 (file)
@@ -1424,12 +1424,22 @@ static void amdgpu_ras_do_recovery(struct work_struct *work)
 {
        struct amdgpu_ras *ras =
                container_of(work, struct amdgpu_ras, recovery_work);
+       struct amdgpu_device *remote_adev = NULL;
+       struct amdgpu_device *adev = ras->adev;
+       struct list_head device_list, *device_list_handle =  NULL;
+       struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, false);
+
+       /* Build list of devices to query RAS related errors */
+       if  (hive && adev->gmc.xgmi.num_physical_nodes > 1) {
+               device_list_handle = &hive->device_list;
+       } else {
+               list_add_tail(&adev->gmc.xgmi.head, &device_list);
+               device_list_handle = &device_list;
+       }
 
-       /*
-        * Query and print non zero error counter per IP block for
-        * awareness before recovering GPU.
-        */
-       amdgpu_ras_log_on_err_counter(ras->adev);
+       list_for_each_entry(remote_adev, device_list_handle, gmc.xgmi.head) {
+               amdgpu_ras_log_on_err_counter(remote_adev);
+       }
 
        if (amdgpu_device_should_recover_gpu(ras->adev))
                amdgpu_device_gpu_recover(ras->adev, 0);
index f6e3f59..d78059f 100644 (file)
@@ -279,7 +279,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_1_2_nv12[] =
 
 #define DEFAULT_SH_MEM_CONFIG \
        ((SH_MEM_ADDRESS_MODE_64 << SH_MEM_CONFIG__ADDRESS_MODE__SHIFT) | \
-        (SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
+        (SH_MEM_ALIGNMENT_MODE_DWORD << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
         (SH_MEM_RETRY_MODE_ALL << SH_MEM_CONFIG__RETRY_MODE__SHIFT) | \
         (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT))
 
@@ -4104,6 +4104,12 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
 
        /* It is disabled by HW by default */
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
+               /* 0 - Disable some blocks' MGCG */
+               WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, 0xe0000000);
+               WREG32_SOC15(GC, 0, mmCGTT_WD_CLK_CTRL, 0xff000000);
+               WREG32_SOC15(GC, 0, mmCGTT_VGT_CLK_CTRL, 0xff000000);
+               WREG32_SOC15(GC, 0, mmCGTT_IA_CLK_CTRL, 0xff000000);
+
                /* 1 - RLC_CGTT_MGCG_OVERRIDE */
                def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
                data &= ~(RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK |
@@ -4143,19 +4149,20 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
                if (def != data)
                        WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
 
-               /* 2 - disable MGLS in RLC */
+               /* 2 - disable MGLS in CP */
+               data = RREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL);
+               if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
+                       data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+                       WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
+               }
+
+               /* 3 - disable MGLS in RLC */
                data = RREG32_SOC15(GC, 0, mmRLC_MEM_SLP_CNTL);
                if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK) {
                        data &= ~RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
                        WREG32_SOC15(GC, 0, mmRLC_MEM_SLP_CNTL, data);
                }
 
-               /* 3 - disable MGLS in CP */
-               data = RREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL);
-               if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
-                       data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
-                       WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
-               }
        }
 }
 
@@ -4266,7 +4273,7 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev,
                /* ===  CGCG /CGLS for GFX 3D Only === */
                gfx_v10_0_update_3d_clock_gating(adev, enable);
                /* ===  MGCG + MGLS === */
-               gfx_v10_0_update_medium_grain_clock_gating(adev, enable);
+               /* gfx_v10_0_update_medium_grain_clock_gating(adev, enable); */
        }
 
        if (adev->cg_flags &
index 608ffe3..e6b113e 100644 (file)
@@ -1217,6 +1217,8 @@ static void gfx_v9_0_check_fw_write_wait(struct amdgpu_device *adev)
                        adev->gfx.mec_fw_write_wait = true;
                break;
        default:
+               adev->gfx.me_fw_write_wait = true;
+               adev->gfx.mec_fw_write_wait = true;
                break;
        }
 }
index cceb46f..dce945e 100644 (file)
@@ -710,14 +710,16 @@ static int gfx_v9_4_query_utc_edc_status(struct amdgpu_device *adev,
 
                sec_count = REG_GET_FIELD(data, VML2_MEM_ECC_CNTL, SEC_COUNT);
                if (sec_count) {
-                       DRM_INFO("Instance[%d]: SubBlock %s, SEC %d\n", i,
+                       dev_info(adev->dev,
+                                "Instance[%d]: SubBlock %s, SEC %d\n", i,
                                 vml2_mems[i], sec_count);
                        err_data->ce_count += sec_count;
                }
 
                ded_count = REG_GET_FIELD(data, VML2_MEM_ECC_CNTL, DED_COUNT);
                if (ded_count) {
-                       DRM_INFO("Instance[%d]: SubBlock %s, DED %d\n", i,
+                       dev_info(adev->dev,
+                                "Instance[%d]: SubBlock %s, DED %d\n", i,
                                 vml2_mems[i], ded_count);
                        err_data->ue_count += ded_count;
                }
index 0d413fa..c0e3efc 100644 (file)
@@ -1539,8 +1539,11 @@ static const struct soc15_reg_entry mmhub_v9_4_edc_cnt_regs[] = {
        { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA7_EDC_CNT3), 0, 0, 0 },
 };
 
-static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
-       uint32_t value, uint32_t *sec_count, uint32_t *ded_count)
+static int mmhub_v9_4_get_ras_error_count(struct amdgpu_device *adev,
+                                         const struct soc15_reg_entry *reg,
+                                         uint32_t value,
+                                         uint32_t *sec_count,
+                                         uint32_t *ded_count)
 {
        uint32_t i;
        uint32_t sec_cnt, ded_cnt;
@@ -1553,7 +1556,7 @@ static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
                                mmhub_v9_4_ras_fields[i].sec_count_mask) >>
                                mmhub_v9_4_ras_fields[i].sec_count_shift;
                if (sec_cnt) {
-                       DRM_INFO("MMHUB SubBlock %s, SEC %d\n",
+                       dev_info(adev->dev, "MMHUB SubBlock %s, SEC %d\n",
                                mmhub_v9_4_ras_fields[i].name,
                                sec_cnt);
                        *sec_count += sec_cnt;
@@ -1563,7 +1566,7 @@ static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
                                mmhub_v9_4_ras_fields[i].ded_count_mask) >>
                                mmhub_v9_4_ras_fields[i].ded_count_shift;
                if (ded_cnt) {
-                       DRM_INFO("MMHUB SubBlock %s, DED %d\n",
+                       dev_info(adev->dev, "MMHUB SubBlock %s, DED %d\n",
                                mmhub_v9_4_ras_fields[i].name,
                                ded_cnt);
                        *ded_count += ded_cnt;
@@ -1588,7 +1591,7 @@ static void mmhub_v9_4_query_ras_error_count(struct amdgpu_device *adev,
                reg_value =
                        RREG32(SOC15_REG_ENTRY_OFFSET(mmhub_v9_4_edc_cnt_regs[i]));
                if (reg_value)
-                       mmhub_v9_4_get_ras_error_count(&mmhub_v9_4_edc_cnt_regs[i],
+                       mmhub_v9_4_get_ras_error_count(adev, &mmhub_v9_4_edc_cnt_regs[i],
                                reg_value, &sec_count, &ded_count);
        }
 
index bab587a..f7c5cdc 100644 (file)
@@ -4723,10 +4723,10 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 static int
 amdgpu_dm_connector_late_register(struct drm_connector *connector)
 {
+#if defined(CONFIG_DEBUG_FS)
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                to_amdgpu_dm_connector(connector);
 
-#if defined(CONFIG_DEBUG_FS)
        connector_debugfs_init(amdgpu_dm_connector);
 #endif
 
@@ -5929,7 +5929,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.underscan_vborder_property,
                                0);
 
-       drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
+       if (!aconnector->mst_port)
+               drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
 
        /* This defaults to the max in the range, but we want 8bpc for non-edp. */
        aconnector->base.state->max_bpc = (connector_type == DRM_MODE_CONNECTOR_eDP) ? 16 : 8;
@@ -5948,8 +5949,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                        &aconnector->base.base,
                        dm->ddev->mode_config.hdr_output_metadata_property, 0);
 
-               drm_connector_attach_vrr_capable_property(
-                       &aconnector->base);
+               if (!aconnector->mst_port)
+                       drm_connector_attach_vrr_capable_property(&aconnector->base);
+
 #ifdef CONFIG_DRM_AMD_DC_HDCP
                if (adev->dm.hdcp_workqueue)
                        drm_connector_attach_content_protection_property(&aconnector->base, true);
@@ -6272,12 +6274,6 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
            y <= -amdgpu_crtc->max_cursor_height)
                return 0;
 
-       if (crtc->primary->state) {
-               /* avivo cursor are offset into the total surface */
-               x += crtc->primary->state->src_x >> 16;
-               y += crtc->primary->state->src_y >> 16;
-       }
-
        if (x < 0) {
                xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
                x = 0;
@@ -6287,6 +6283,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
                y = 0;
        }
        position->enable = true;
+       position->translate_by_source = true;
        position->x = x;
        position->y = y;
        position->x_hotspot = xorigin;
index e8208df..fabbe78 100644 (file)
@@ -410,6 +410,14 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
        drm_connector_attach_encoder(&aconnector->base,
                                     &aconnector->mst_encoder->base);
 
+       connector->max_bpc_property = master->base.max_bpc_property;
+       if (connector->max_bpc_property)
+               drm_connector_attach_max_bpc_property(connector, 8, 16);
+
+       connector->vrr_capable_property = master->base.vrr_capable_property;
+       if (connector->vrr_capable_property)
+               drm_connector_attach_vrr_capable_property(connector);
+
        drm_object_attach_property(
                &connector->base,
                dev->mode_config.path_property,
index ab267dd..24c5765 100644 (file)
@@ -643,7 +643,7 @@ static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params
        /* Find lowest DPM, FCLK is filled in reverse order*/
 
        for (i = PP_SMU_NUM_FCLK_DPM_LEVELS - 1; i >= 0; i--) {
-               if (clock_table->FClocks[i].Freq != 0) {
+               if (clock_table->FClocks[i].Freq != 0 && clock_table->FClocks[i].Vol != 0) {
                        j = i;
                        break;
                }
index f21bbb2..8489f1e 100644 (file)
@@ -283,6 +283,8 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
        int i = 0;
        bool ret = false;
 
+       stream->adjust = *adjust;
+
        for (i = 0; i < MAX_PIPES; i++) {
                struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 
@@ -1859,8 +1861,9 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
                // Else we fallback to mem compare.
                } else if (memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0) {
                        dc->optimized_required = true;
-               } else if (dc->wm_optimized_required)
-                       dc->optimized_required = true;
+               }
+
+               dc->optimized_required |= dc->wm_optimized_required;
        }
 
        return type;
@@ -2462,7 +2465,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
        enum surface_update_type update_type;
        struct dc_state *context;
        struct dc_context *dc_ctx = dc->ctx;
-       int i;
+       int i, j;
 
        stream_status = dc_stream_get_status(stream);
        context = dc->current_state;
@@ -2500,6 +2503,17 @@ void dc_commit_updates_for_stream(struct dc *dc,
 
                copy_surface_update_to_plane(surface, &srf_updates[i]);
 
+               if (update_type >= UPDATE_TYPE_MED) {
+                       for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                               struct pipe_ctx *pipe_ctx =
+                                       &context->res_ctx.pipe_ctx[j];
+
+                               if (pipe_ctx->plane_state != surface)
+                                       continue;
+
+                               resource_build_scaling_params(pipe_ctx);
+                       }
+               }
        }
 
        copy_stream_update_to_stream(dc, context, stream, stream_update);
index 25c50bc..a8dc308 100644 (file)
@@ -385,6 +385,8 @@ struct dc_cursor_position {
         */
        bool enable;
 
+       /* Translate cursor x/y by the source rectangle for each plane. */
+       bool translate_by_source;
 };
 
 struct dc_cursor_mi_param {
index 0976e37..c279982 100644 (file)
@@ -2685,6 +2685,23 @@ void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
                .mirror = pipe_ctx->plane_state->horizontal_mirror
        };
 
+       /**
+        * If the cursor's source viewport is clipped then we need to
+        * translate the cursor to appear in the correct position on
+        * the screen.
+        *
+        * This translation isn't affected by scaling so it needs to be
+        * done *after* we adjust the position for the scale factor.
+        *
+        * This is only done by opt-in for now since there are still
+        * some usecases like tiled display that might enable the
+        * cursor on both streams while expecting dc to clip it.
+        */
+       if (pos_cpy.translate_by_source) {
+               pos_cpy.x += pipe_ctx->plane_state->src_rect.x;
+               pos_cpy.y += pipe_ctx->plane_state->src_rect.y;
+       }
+
        if (pipe_ctx->plane_state->address.type
                        == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
                pos_cpy.enable = false;
index 0be0100..b035754 100644 (file)
@@ -3021,12 +3021,50 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
        int x_pos = pos_cpy.x;
        int y_pos = pos_cpy.y;
 
-       // translate cursor from stream space to plane space
+       /**
+        * DC cursor is stream space, HW cursor is plane space and drawn
+        * as part of the framebuffer.
+        *
+        * Cursor position can't be negative, but hotspot can be used to
+        * shift cursor out of the plane bounds. Hotspot must be smaller
+        * than the cursor size.
+        */
+
+       /**
+        * Translate cursor from stream space to plane space.
+        *
+        * If the cursor is scaled then we need to scale the position
+        * to be in the approximately correct place. We can't do anything
+        * about the actual size being incorrect, that's a limitation of
+        * the hardware.
+        */
        x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width /
                        pipe_ctx->plane_state->dst_rect.width;
        y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height /
                        pipe_ctx->plane_state->dst_rect.height;
 
+       /**
+        * If the cursor's source viewport is clipped then we need to
+        * translate the cursor to appear in the correct position on
+        * the screen.
+        *
+        * This translation isn't affected by scaling so it needs to be
+        * done *after* we adjust the position for the scale factor.
+        *
+        * This is only done by opt-in for now since there are still
+        * some usecases like tiled display that might enable the
+        * cursor on both streams while expecting dc to clip it.
+        */
+       if (pos_cpy.translate_by_source) {
+               x_pos += pipe_ctx->plane_state->src_rect.x;
+               y_pos += pipe_ctx->plane_state->src_rect.y;
+       }
+
+       /**
+        * If the position is negative then we need to add to the hotspot
+        * to shift the cursor outside the plane.
+        */
+
        if (x_pos < 0) {
                pos_cpy.x_hotspot -= x_pos;
                x_pos = 0;
index 8b71222..07265ca 100644 (file)
@@ -585,7 +585,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .disable_pplib_clock_request = false,
                .disable_pplib_wm_range = false,
                .pplib_wm_report_mode = WM_REPORT_DEFAULT,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = true,
                .disable_dcc = DCC_ENABLE,
                .voltage_align_fclk = true,
index 2333182..22f421e 100644 (file)
@@ -1373,6 +1373,7 @@ static void dcn20_update_dchubp_dpp(
        }
 
        if (pipe_ctx->update_flags.bits.viewport ||
+                       (context == dc->current_state && plane_state->update_flags.bits.position_change) ||
                        (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
                        (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
 
index 8a87d0e..2359e88 100644 (file)
 #define RAVEN2_A0 0x81
 #define RAVEN1_F0 0xF0
 #define RAVEN_UNKNOWN 0xFF
+#define RENOIR_A0 0x91
 #ifndef ASICREV_IS_RAVEN
 #define ASICREV_IS_RAVEN(eChipRev) ((eChipRev >= RAVEN_A0) && eChipRev < RAVEN_UNKNOWN)
 #endif
@@ -171,8 +172,6 @@ enum {
 #define ASICREV_IS_NAVI10_P(eChipRev)        (eChipRev < NV_NAVI12_P_A0)
 #define ASICREV_IS_NAVI12_P(eChipRev)        ((eChipRev >= NV_NAVI12_P_A0) && (eChipRev < NV_NAVI14_M_A0))
 #define ASICREV_IS_NAVI14_M(eChipRev)        ((eChipRev >= NV_NAVI14_M_A0) && (eChipRev < NV_UNKNOWN))
-#define RENOIR_A0 0x91
-#define DEVICE_ID_RENOIR_1636 0x1636   // Renoir
 #define ASICREV_IS_RENOIR(eChipRev) ((eChipRev >= RENOIR_A0) && (eChipRev < RAVEN1_F0))
 
 /*
@@ -183,6 +182,9 @@ enum {
 #define DEVICE_ID_TEMASH_9839 0x9839
 #define DEVICE_ID_TEMASH_983D 0x983D
 
+/* RENOIR */
+#define DEVICE_ID_RENOIR_1636 0x1636
+
 /* Asic Family IDs for different asic family. */
 #define FAMILY_CI 120 /* Sea Islands: Hawaii (P), Bonaire (M) */
 #define FAMILY_KV 125 /* Fusion => Kaveri: Spectre, Spooky; Kabini: Kalindi */
index c195575..2a12614 100644 (file)
@@ -1452,7 +1452,8 @@ static int pp_get_asic_baco_state(void *handle, int *state)
        if (!hwmgr)
                return -EINVAL;
 
-       if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_state)
+       if (!(hwmgr->not_vf && amdgpu_dpm) ||
+               !hwmgr->hwmgr_func->get_asic_baco_state)
                return 0;
 
        mutex_lock(&hwmgr->smu_lock);
index 5db8c56..1ef0923 100644 (file)
@@ -794,8 +794,21 @@ static int arcturus_force_clk_levels(struct smu_context *smu,
        struct arcturus_dpm_table *dpm_table;
        struct arcturus_single_dpm_table *single_dpm_table;
        uint32_t soft_min_level, soft_max_level;
+       uint32_t smu_version;
        int ret = 0;
 
+       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               pr_err("Failed to get smu version!\n");
+               return ret;
+       }
+
+       if (smu_version >= 0x361200) {
+               pr_err("Forcing clock level is not supported with "
+                      "54.18 and onwards SMU firmwares\n");
+               return -EOPNOTSUPP;
+       }
+
        soft_min_level = mask ? (ffs(mask) - 1) : 0;
        soft_max_level = mask ? (fls(mask) - 1) : 0;
 
@@ -1512,6 +1525,38 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
        return 0;
 }
 
+static int arcturus_set_performance_level(struct smu_context *smu,
+                                         enum amd_dpm_forced_level level)
+{
+       uint32_t smu_version;
+       int ret;
+
+       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               pr_err("Failed to get smu version!\n");
+               return ret;
+       }
+
+       switch (level) {
+       case AMD_DPM_FORCED_LEVEL_HIGH:
+       case AMD_DPM_FORCED_LEVEL_LOW:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
+               if (smu_version >= 0x361200) {
+                       pr_err("Forcing clock level is not supported with "
+                              "54.18 and onwards SMU firmwares\n");
+                       return -EOPNOTSUPP;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return smu_v11_0_set_performance_level(smu, level);
+}
+
 static void arcturus_dump_pptable(struct smu_context *smu)
 {
        struct smu_table_context *table_context = &smu->smu_table;
@@ -2285,7 +2330,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .get_profiling_clk_mask = arcturus_get_profiling_clk_mask,
        .get_power_profile_mode = arcturus_get_power_profile_mode,
        .set_power_profile_mode = arcturus_set_power_profile_mode,
-       .set_performance_level = smu_v11_0_set_performance_level,
+       .set_performance_level = arcturus_set_performance_level,
        /* debug (internal used) */
        .dump_pptable = arcturus_dump_pptable,
        .get_power_limit = arcturus_get_power_limit,
index 7bf52ec..ff73a73 100644 (file)
@@ -239,6 +239,7 @@ static int renoir_print_clk_levels(struct smu_context *smu,
        uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
        SmuMetrics_t metrics;
+       bool cur_value_match_level = false;
 
        if (!clk_table || clk_type >= SMU_CLK_COUNT)
                return -EINVAL;
@@ -297,8 +298,13 @@ static int renoir_print_clk_levels(struct smu_context *smu,
                GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
                size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
                                cur_value == value ? "*" : "");
+               if (cur_value == value)
+                       cur_value_match_level = true;
        }
 
+       if (!cur_value_match_level)
+               size += sprintf(buf + size, "   %uMhz *\n", cur_value);
+
        return size;
 }
 
@@ -887,6 +893,17 @@ static int renoir_read_sensor(struct smu_context *smu,
        return ret;
 }
 
+static bool renoir_is_dpm_running(struct smu_context *smu)
+{
+       /*
+        * Util now, the pmfw hasn't exported the interface of SMU
+        * feature mask to APU SKU so just force on all the feature
+        * at early initial stage.
+        */
+       return true;
+
+}
+
 static const struct pptable_funcs renoir_ppt_funcs = {
        .get_smu_msg_index = renoir_get_smu_msg_index,
        .get_smu_clk_index = renoir_get_smu_clk_index,
@@ -927,6 +944,7 @@ static const struct pptable_funcs renoir_ppt_funcs = {
        .mode2_reset = smu_v12_0_mode2_reset,
        .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range,
        .set_driver_table_location = smu_v12_0_set_driver_table_location,
+       .is_dpm_running = renoir_is_dpm_running,
 };
 
 void renoir_set_ppt_funcs(struct smu_context *smu)
index 2a390dd..89cd6da 100644 (file)
@@ -37,7 +37,7 @@ extern void renoir_set_ppt_funcs(struct smu_context *smu);
                        freq = table->SocClocks[dpm_level].Freq;        \
                        break;                                          \
                case SMU_MCLK:                                          \
-                       freq = table->MemClocks[dpm_level].Freq;        \
+                       freq = table->FClocks[dpm_level].Freq;  \
                        break;                                          \
                case SMU_DCEFCLK:                                       \
                        freq = table->DcfClocks[dpm_level].Freq;        \
index 9ded2ce..76736fb 100644 (file)
@@ -1652,8 +1652,7 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 }
 
 struct analogix_dp_device *
-analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-                struct analogix_dp_plat_data *plat_data)
+analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct analogix_dp_device *dp;
@@ -1756,22 +1755,30 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
                                        irq_flags, "analogix-dp", dp);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto err_disable_pm_runtime;
+               return ERR_PTR(ret);
        }
        disable_irq(dp->irq);
 
+       return dp;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_probe);
+
+int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
+{
+       int ret;
+
        dp->drm_dev = drm_dev;
        dp->encoder = dp->plat_data->encoder;
 
        dp->aux.name = "DP-AUX";
        dp->aux.transfer = analogix_dpaux_transfer;
-       dp->aux.dev = &pdev->dev;
+       dp->aux.dev = dp->dev;
 
        ret = drm_dp_aux_register(&dp->aux);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
 
-       pm_runtime_enable(dev);
+       pm_runtime_enable(dp->dev);
 
        ret = analogix_dp_create_bridge(drm_dev, dp);
        if (ret) {
@@ -1779,13 +1786,12 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
                goto err_disable_pm_runtime;
        }
 
-       return dp;
+       return 0;
 
 err_disable_pm_runtime:
+       pm_runtime_disable(dp->dev);
 
-       pm_runtime_disable(dev);
-
-       return ERR_PTR(ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
@@ -1802,10 +1808,15 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
 
        drm_dp_aux_unregister(&dp->aux);
        pm_runtime_disable(dp->dev);
-       clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
+void analogix_dp_remove(struct analogix_dp_device *dp)
+{
+       clk_disable_unprepare(dp->clock);
+}
+EXPORT_SYMBOL_GPL(analogix_dp_remove);
+
 #ifdef CONFIG_PM
 int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
index 1de2cde..282774e 100644 (file)
@@ -962,27 +962,40 @@ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
        unsigned count;
        struct scatterlist *sg;
        struct page *page;
-       u32 len, index;
+       u32 page_len, page_index;
        dma_addr_t addr;
+       u32 dma_len, dma_index;
 
-       index = 0;
+       /*
+        * Scatterlist elements contains both pages and DMA addresses, but
+        * one shoud not assume 1:1 relation between them. The sg->length is
+        * the size of the physical memory chunk described by the sg->page,
+        * while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
+        * described by the sg_dma_address(sg).
+        */
+       page_index = 0;
+       dma_index = 0;
        for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-               len = sg_dma_len(sg);
+               page_len = sg->length;
                page = sg_page(sg);
+               dma_len = sg_dma_len(sg);
                addr = sg_dma_address(sg);
 
-               while (len > 0) {
-                       if (WARN_ON(index >= max_entries))
+               while (pages && page_len > 0) {
+                       if (WARN_ON(page_index >= max_entries))
                                return -1;
-                       if (pages)
-                               pages[index] = page;
-                       if (addrs)
-                               addrs[index] = addr;
-
+                       pages[page_index] = page;
                        page++;
+                       page_len -= PAGE_SIZE;
+                       page_index++;
+               }
+               while (addrs && dma_len > 0) {
+                       if (WARN_ON(dma_index >= max_entries))
+                               return -1;
+                       addrs[dma_index] = addr;
                        addr += PAGE_SIZE;
-                       len -= PAGE_SIZE;
-                       index++;
+                       dma_len -= PAGE_SIZE;
+                       dma_index++;
                }
        }
        return 0;
index d23d350..5ee0906 100644 (file)
@@ -159,15 +159,8 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
        struct drm_device *drm_dev = data;
        int ret;
 
-       dp->dev = dev;
        dp->drm_dev = drm_dev;
 
-       dp->plat_data.dev_type = EXYNOS_DP;
-       dp->plat_data.power_on_start = exynos_dp_poweron;
-       dp->plat_data.power_off = exynos_dp_poweroff;
-       dp->plat_data.attach = exynos_dp_bridge_attach;
-       dp->plat_data.get_modes = exynos_dp_get_modes;
-
        if (!dp->plat_data.panel && !dp->ptn_bridge) {
                ret = exynos_dp_dt_parse_panel(dp);
                if (ret)
@@ -185,13 +178,11 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
        dp->plat_data.encoder = encoder;
 
-       dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-       if (IS_ERR(dp->adp)) {
+       ret = analogix_dp_bind(dp->adp, dp->drm_dev);
+       if (ret)
                dp->encoder.funcs->destroy(&dp->encoder);
-               return PTR_ERR(dp->adp);
-       }
 
-       return 0;
+       return ret;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -222,6 +213,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
        if (!dp)
                return -ENOMEM;
 
+       dp->dev = dev;
        /*
         * We just use the drvdata until driver run into component
         * add function, and then we would set drvdata to null, so
@@ -247,16 +239,29 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
        /* The remote port can be either a panel or a bridge */
        dp->plat_data.panel = panel;
+       dp->plat_data.dev_type = EXYNOS_DP;
+       dp->plat_data.power_on_start = exynos_dp_poweron;
+       dp->plat_data.power_off = exynos_dp_poweroff;
+       dp->plat_data.attach = exynos_dp_bridge_attach;
+       dp->plat_data.get_modes = exynos_dp_get_modes;
        dp->plat_data.skip_connector = !!bridge;
+
        dp->ptn_bridge = bridge;
 
 out:
+       dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+       if (IS_ERR(dp->adp))
+               return PTR_ERR(dp->adp);
+
        return component_add(&pdev->dev, &exynos_dp_ops);
 }
 
 static int exynos_dp_remove(struct platform_device *pdev)
 {
+       struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
        component_del(&pdev->dev, &exynos_dp_ops);
+       analogix_dp_remove(dp->adp);
 
        return 0;
 }
index 73d0f46..2c617c9 100644 (file)
@@ -947,7 +947,8 @@ static const struct cnl_ddi_buf_trans *
 ehl_get_combo_buf_trans(struct drm_i915_private *dev_priv, int type, int rate,
                        int *n_entries)
 {
-       if (type == INTEL_OUTPUT_DP && rate > 270000) {
+       if (type != INTEL_OUTPUT_HDMI && type != INTEL_OUTPUT_EDP &&
+           rate > 270000) {
                *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_hbr2_hbr3);
                return ehl_combo_phy_ddi_translations_hbr2_hbr3;
        }
@@ -959,7 +960,7 @@ static const struct cnl_ddi_buf_trans *
 tgl_get_combo_buf_trans(struct drm_i915_private *dev_priv, int type, int rate,
                        int *n_entries)
 {
-       if (type != INTEL_OUTPUT_DP) {
+       if (type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_EDP) {
                return icl_get_combo_buf_trans(dev_priv, type, rate, n_entries);
        } else if (rate > 270000) {
                *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
@@ -1869,7 +1870,11 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
                return;
 
        dig_port = enc_to_dig_port(encoder);
-       intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
+
+       if (!intel_phy_is_tc(dev_priv, phy) ||
+           dig_port->tc_mode != TC_PORT_TBT_ALT)
+               intel_display_power_get(dev_priv,
+                                       dig_port->ddi_io_power_domain);
 
        /*
         * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
index 36d0695..b7440f0 100644 (file)
@@ -896,11 +896,13 @@ static inline struct i915_ggtt *cache_to_ggtt(struct reloc_cache *cache)
 
 static void reloc_gpu_flush(struct reloc_cache *cache)
 {
-       GEM_BUG_ON(cache->rq_size >= cache->rq->batch->obj->base.size / sizeof(u32));
+       struct drm_i915_gem_object *obj = cache->rq->batch->obj;
+
+       GEM_BUG_ON(cache->rq_size >= obj->base.size / sizeof(u32));
        cache->rq_cmd[cache->rq_size] = MI_BATCH_BUFFER_END;
 
-       __i915_gem_object_flush_map(cache->rq->batch->obj, 0, cache->rq_size);
-       i915_gem_object_unpin_map(cache->rq->batch->obj);
+       __i915_gem_object_flush_map(obj, 0, sizeof(u32) * (cache->rq_size + 1));
+       i915_gem_object_unpin_map(obj);
 
        intel_gt_chipset_flush(cache->rq->engine->gt);
 
@@ -1477,10 +1479,8 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
                                 * can read from this userspace address.
                                 */
                                offset = gen8_canonical_addr(offset & ~UPDATE);
-                               if (unlikely(__put_user(offset, &urelocs[r-stack].presumed_offset))) {
-                                       remain = -EFAULT;
-                                       goto out;
-                               }
+                               __put_user(offset,
+                                          &urelocs[r - stack].presumed_offset);
                        }
                } while (r++, --count);
                urelocs += ARRAY_SIZE(stack);
index aed498a..4c5a209 100644 (file)
@@ -191,10 +191,11 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                                     enum i915_cache_level level,
                                     u32 flags)
 {
-       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       struct sgt_iter sgt_iter;
-       gen8_pte_t __iomem *gtt_entries;
        const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, 0);
+       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+       gen8_pte_t __iomem *gte;
+       gen8_pte_t __iomem *end;
+       struct sgt_iter iter;
        dma_addr_t addr;
 
        /*
@@ -202,10 +203,17 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
         * not to allow the user to override access to a read only page.
         */
 
-       gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm;
-       gtt_entries += vma->node.start / I915_GTT_PAGE_SIZE;
-       for_each_sgt_daddr(addr, sgt_iter, vma->pages)
-               gen8_set_pte(gtt_entries++, pte_encode | addr);
+       gte = (gen8_pte_t __iomem *)ggtt->gsm;
+       gte += vma->node.start / I915_GTT_PAGE_SIZE;
+       end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
+
+       for_each_sgt_daddr(addr, iter, vma->pages)
+               gen8_set_pte(gte++, pte_encode | addr);
+       GEM_BUG_ON(gte > end);
+
+       /* Fill the allocated but "unused" space beyond the end of the buffer */
+       while (gte < end)
+               gen8_set_pte(gte++, vm->scratch[0].encode);
 
        /*
         * We want to flush the TLBs only after we're certain all the PTE
@@ -241,13 +249,22 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     u32 flags)
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       gen6_pte_t __iomem *entries = (gen6_pte_t __iomem *)ggtt->gsm;
-       unsigned int i = vma->node.start / I915_GTT_PAGE_SIZE;
+       gen6_pte_t __iomem *gte;
+       gen6_pte_t __iomem *end;
        struct sgt_iter iter;
        dma_addr_t addr;
 
+       gte = (gen6_pte_t __iomem *)ggtt->gsm;
+       gte += vma->node.start / I915_GTT_PAGE_SIZE;
+       end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
+
        for_each_sgt_daddr(addr, iter, vma->pages)
-               iowrite32(vm->pte_encode(addr, level, flags), &entries[i++]);
+               iowrite32(vm->pte_encode(addr, level, flags), gte++);
+       GEM_BUG_ON(gte > end);
+
+       /* Fill the allocated but "unused" space beyond the end of the buffer */
+       while (gte < end)
+               iowrite32(vm->scratch[0].encode, gte++);
 
        /*
         * We want to flush the TLBs only after we're certain all the PTE
index f38f5e1..ce98c08 100644 (file)
@@ -325,15 +325,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
                            void *data)
 {
        struct rockchip_dp_device *dp = dev_get_drvdata(dev);
-       const struct rockchip_dp_chip_data *dp_data;
        struct drm_device *drm_dev = data;
        int ret;
 
-       dp_data = of_device_get_match_data(dev);
-       if (!dp_data)
-               return -ENODEV;
-
-       dp->data = dp_data;
        dp->drm_dev = drm_dev;
 
        ret = rockchip_dp_drm_create_encoder(dp);
@@ -344,16 +338,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
        dp->plat_data.encoder = &dp->encoder;
 
-       dp->plat_data.dev_type = dp->data->chip_type;
-       dp->plat_data.power_on_start = rockchip_dp_poweron_start;
-       dp->plat_data.power_off = rockchip_dp_powerdown;
-       dp->plat_data.get_modes = rockchip_dp_get_modes;
-
-       dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-       if (IS_ERR(dp->adp)) {
-               ret = PTR_ERR(dp->adp);
+       ret = analogix_dp_bind(dp->adp, drm_dev);
+       if (ret)
                goto err_cleanup_encoder;
-       }
 
        return 0;
 err_cleanup_encoder:
@@ -368,8 +355,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
        analogix_dp_unbind(dp->adp);
        dp->encoder.funcs->destroy(&dp->encoder);
-
-       dp->adp = ERR_PTR(-ENODEV);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -380,10 +365,15 @@ static const struct component_ops rockchip_dp_component_ops = {
 static int rockchip_dp_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct rockchip_dp_chip_data *dp_data;
        struct drm_panel *panel = NULL;
        struct rockchip_dp_device *dp;
        int ret;
 
+       dp_data = of_device_get_match_data(dev);
+       if (!dp_data)
+               return -ENODEV;
+
        ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
        if (ret < 0)
                return ret;
@@ -394,7 +384,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
        dp->dev = dev;
        dp->adp = ERR_PTR(-ENODEV);
+       dp->data = dp_data;
        dp->plat_data.panel = panel;
+       dp->plat_data.dev_type = dp->data->chip_type;
+       dp->plat_data.power_on_start = rockchip_dp_poweron_start;
+       dp->plat_data.power_off = rockchip_dp_powerdown;
+       dp->plat_data.get_modes = rockchip_dp_get_modes;
 
        ret = rockchip_dp_of_probe(dp);
        if (ret < 0)
@@ -402,12 +397,19 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dp);
 
+       dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+       if (IS_ERR(dp->adp))
+               return PTR_ERR(dp->adp);
+
        return component_add(dev, &rockchip_dp_component_ops);
 }
 
 static int rockchip_dp_remove(struct platform_device *pdev)
 {
+       struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
+
        component_del(&pdev->dev, &rockchip_dp_component_ops);
+       analogix_dp_remove(dp->adp);
 
        return 0;
 }
index 6ee3b96..0ad30b1 100644 (file)
@@ -442,66 +442,6 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
 }
 EXPORT_SYMBOL(ttm_bo_vm_fault);
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-/**
- * ttm_pgprot_is_wrprotecting - Is a page protection value write-protecting?
- * @prot: The page protection value
- *
- * Return: true if @prot is write-protecting. false otherwise.
- */
-static bool ttm_pgprot_is_wrprotecting(pgprot_t prot)
-{
-       /*
-        * This is meant to say "pgprot_wrprotect(prot) == prot" in a generic
-        * way. Unfortunately there is no generic pgprot_wrprotect.
-        */
-       return pte_val(pte_wrprotect(__pte(pgprot_val(prot)))) ==
-               pgprot_val(prot);
-}
-
-static vm_fault_t ttm_bo_vm_huge_fault(struct vm_fault *vmf,
-                                      enum page_entry_size pe_size)
-{
-       struct vm_area_struct *vma = vmf->vma;
-       pgprot_t prot;
-       struct ttm_buffer_object *bo = vma->vm_private_data;
-       vm_fault_t ret;
-       pgoff_t fault_page_size = 0;
-       bool write = vmf->flags & FAULT_FLAG_WRITE;
-
-       switch (pe_size) {
-       case PE_SIZE_PMD:
-               fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT;
-               break;
-#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-       case PE_SIZE_PUD:
-               fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT;
-               break;
-#endif
-       default:
-               WARN_ON_ONCE(1);
-               return VM_FAULT_FALLBACK;
-       }
-
-       /* Fallback on write dirty-tracking or COW */
-       if (write && ttm_pgprot_is_wrprotecting(vma->vm_page_prot))
-               return VM_FAULT_FALLBACK;
-
-       ret = ttm_bo_vm_reserve(bo, vmf);
-       if (ret)
-               return ret;
-
-       prot = vm_get_page_prot(vma->vm_flags);
-       ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size);
-       if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
-               return ret;
-
-       dma_resv_unlock(bo->base.resv);
-
-       return ret;
-}
-#endif
-
 void ttm_bo_vm_open(struct vm_area_struct *vma)
 {
        struct ttm_buffer_object *bo = vma->vm_private_data;
@@ -604,9 +544,6 @@ static const struct vm_operations_struct ttm_bo_vm_ops = {
        .open = ttm_bo_vm_open,
        .close = ttm_bo_vm_close,
        .access = ttm_bo_vm_access,
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       .huge_fault = ttm_bo_vm_huge_fault,
-#endif
 };
 
 static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev,
index 2bfb13d..d9039bb 100644 (file)
@@ -123,15 +123,17 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo)
 struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
                                                size_t size)
 {
-       struct virtio_gpu_object *bo;
+       struct virtio_gpu_object_shmem *shmem;
+       struct drm_gem_shmem_object *dshmem;
 
-       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
-       if (!bo)
+       shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);
+       if (!shmem)
                return NULL;
 
-       bo->base.base.funcs = &virtio_gpu_shmem_funcs;
-       bo->base.map_cached = true;
-       return &bo->base.base;
+       dshmem = &shmem->base.base;
+       dshmem->base.funcs = &virtio_gpu_shmem_funcs;
+       dshmem->map_cached = true;
+       return &dshmem->base;
 }
 
 static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
index 4f907e3..91c1bd6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/blkdev.h>
 #include <linux/blk-mq.h>
+#include <linux/compat.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/hdreg.h>
@@ -1252,6 +1253,18 @@ static void nvme_enable_aen(struct nvme_ctrl *ctrl)
        queue_work(nvme_wq, &ctrl->async_event_work);
 }
 
+/*
+ * Convert integer values from ioctl structures to user pointers, silently
+ * ignoring the upper bits in the compat case to match behaviour of 32-bit
+ * kernels.
+ */
+static void __user *nvme_to_user_ptr(uintptr_t ptrval)
+{
+       if (in_compat_syscall())
+               ptrval = (compat_uptr_t)ptrval;
+       return (void __user *)ptrval;
+}
+
 static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 {
        struct nvme_user_io io;
@@ -1275,7 +1288,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 
        length = (io.nblocks + 1) << ns->lba_shift;
        meta_len = (io.nblocks + 1) * ns->ms;
-       metadata = (void __user *)(uintptr_t)io.metadata;
+       metadata = nvme_to_user_ptr(io.metadata);
 
        if (ns->ext) {
                length += meta_len;
@@ -1298,7 +1311,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        c.rw.appmask = cpu_to_le16(io.appmask);
 
        return nvme_submit_user_cmd(ns->queue, &c,
-                       (void __user *)(uintptr_t)io.addr, length,
+                       nvme_to_user_ptr(io.addr), length,
                        metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
 }
 
@@ -1418,9 +1431,9 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 
        effects = nvme_passthru_start(ctrl, ns, cmd.opcode);
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       (void __user *)(uintptr_t)cmd.addr, cmd.data_len,
-                       (void __user *)(uintptr_t)cmd.metadata,
-                       cmd.metadata_len, 0, &result, timeout);
+                       nvme_to_user_ptr(cmd.addr), cmd.data_len,
+                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
+                       0, &result, timeout);
        nvme_passthru_end(ctrl, effects);
 
        if (status >= 0) {
@@ -1465,8 +1478,8 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 
        effects = nvme_passthru_start(ctrl, ns, cmd.opcode);
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       (void __user *)(uintptr_t)cmd.addr, cmd.data_len,
-                       (void __user *)(uintptr_t)cmd.metadata, cmd.metadata_len,
+                       nvme_to_user_ptr(cmd.addr), cmd.data_len,
+                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
                        0, &cmd.result, timeout);
        nvme_passthru_end(ctrl, effects);
 
@@ -1884,6 +1897,13 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
        if (ns->head->disk) {
                nvme_update_disk_info(ns->head->disk, ns, id);
                blk_queue_stack_limits(ns->head->disk->queue, ns->queue);
+               if (bdi_cap_stable_pages_required(ns->queue->backing_dev_info)) {
+                       struct backing_dev_info *info =
+                               ns->head->disk->queue->backing_dev_info;
+
+                        info->capabilities |= BDI_CAP_STABLE_WRITES;
+               }
+
                revalidate_disk(ns->head->disk);
        }
 #endif
index a8bf2fb..7dfc4a2 100644 (file)
@@ -342,8 +342,7 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo,
            !template->ls_req || !template->fcp_io ||
            !template->ls_abort || !template->fcp_abort ||
            !template->max_hw_queues || !template->max_sgl_segments ||
-           !template->max_dif_sgl_segments || !template->dma_boundary ||
-           !template->module) {
+           !template->max_dif_sgl_segments || !template->dma_boundary) {
                ret = -EINVAL;
                goto out_reghost_failed;
        }
@@ -2016,7 +2015,6 @@ nvme_fc_ctrl_free(struct kref *ref)
 {
        struct nvme_fc_ctrl *ctrl =
                container_of(ref, struct nvme_fc_ctrl, ref);
-       struct nvme_fc_lport *lport = ctrl->lport;
        unsigned long flags;
 
        if (ctrl->ctrl.tagset) {
@@ -2043,7 +2041,6 @@ nvme_fc_ctrl_free(struct kref *ref)
        if (ctrl->ctrl.opts)
                nvmf_free_options(ctrl->ctrl.opts);
        kfree(ctrl);
-       module_put(lport->ops->module);
 }
 
 static void
@@ -3074,15 +3071,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
                goto out_fail;
        }
 
-       if (!try_module_get(lport->ops->module)) {
-               ret = -EUNATCH;
-               goto out_free_ctrl;
-       }
-
        idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL);
        if (idx < 0) {
                ret = -ENOSPC;
-               goto out_mod_put;
+               goto out_free_ctrl;
        }
 
        ctrl->ctrl.opts = opts;
@@ -3232,8 +3224,6 @@ out_free_queues:
 out_free_ida:
        put_device(ctrl->dev);
        ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum);
-out_mod_put:
-       module_put(lport->ops->module);
 out_free_ctrl:
        kfree(ctrl);
 out_fail:
index 61bf875..54603bd 100644 (file)
@@ -510,7 +510,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
        if (!nr_nsids)
                return 0;
 
-       down_write(&ctrl->namespaces_rwsem);
+       down_read(&ctrl->namespaces_rwsem);
        list_for_each_entry(ns, &ctrl->namespaces, list) {
                unsigned nsid = le32_to_cpu(desc->nsids[n]);
 
@@ -521,7 +521,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
                if (++n == nr_nsids)
                        break;
        }
-       up_write(&ctrl->namespaces_rwsem);
+       up_read(&ctrl->namespaces_rwsem);
        return 0;
 }
 
index 76dbb55..cac8a93 100644 (file)
@@ -1342,7 +1342,7 @@ static int nvme_rdma_post_send(struct nvme_rdma_queue *queue,
        int ret;
 
        sge->addr   = qe->dma;
-       sge->length = sizeof(struct nvme_command),
+       sge->length = sizeof(struct nvme_command);
        sge->lkey   = queue->device->pd->local_dma_lkey;
 
        wr.next       = NULL;
index 0ef14f0..c15a921 100644 (file)
@@ -174,16 +174,14 @@ static inline bool nvme_tcp_async_req(struct nvme_tcp_request *req)
 static inline bool nvme_tcp_has_inline_data(struct nvme_tcp_request *req)
 {
        struct request *rq;
-       unsigned int bytes;
 
        if (unlikely(nvme_tcp_async_req(req)))
                return false; /* async events don't have a request */
 
        rq = blk_mq_rq_from_pdu(req);
-       bytes = blk_rq_payload_bytes(rq);
 
-       return rq_data_dir(rq) == WRITE && bytes &&
-               bytes <= nvme_tcp_inline_data_size(req->queue);
+       return rq_data_dir(rq) == WRITE && req->data_len &&
+               req->data_len <= nvme_tcp_inline_data_size(req->queue);
 }
 
 static inline struct page *nvme_tcp_req_cur_page(struct nvme_tcp_request *req)
@@ -1075,7 +1073,7 @@ static void nvme_tcp_io_work(struct work_struct *w)
                if (result > 0)
                        pending = true;
                else if (unlikely(result < 0))
-                       break;
+                       return;
 
                if (!pending)
                        return;
@@ -2164,7 +2162,9 @@ static blk_status_t nvme_tcp_map_data(struct nvme_tcp_queue *queue,
 
        c->common.flags |= NVME_CMD_SGL_METABUF;
 
-       if (rq_data_dir(rq) == WRITE && req->data_len &&
+       if (!blk_rq_nr_phys_segments(rq))
+               nvme_tcp_set_sg_null(c);
+       else if (rq_data_dir(rq) == WRITE &&
            req->data_len <= nvme_tcp_inline_data_size(queue))
                nvme_tcp_set_sg_inline(queue, c, req->data_len);
        else
@@ -2191,7 +2191,8 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
        req->data_sent = 0;
        req->pdu_len = 0;
        req->pdu_sent = 0;
-       req->data_len = blk_rq_payload_bytes(rq);
+       req->data_len = blk_rq_nr_phys_segments(rq) ?
+                               blk_rq_payload_bytes(rq) : 0;
        req->curr_bio = rq->bio;
 
        if (rq_data_dir(rq) == WRITE &&
@@ -2298,6 +2299,9 @@ static int nvme_tcp_poll(struct blk_mq_hw_ctx *hctx)
        struct nvme_tcp_queue *queue = hctx->driver_data;
        struct sock *sk = queue->sock->sk;
 
+       if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags))
+               return 0;
+
        if (sk_can_busy_loop(sk) && skb_queue_empty_lockless(&sk->sk_receive_queue))
                sk_busy_loop(sk, true);
        nvme_tcp_try_recv(queue);
index 7aa1078..58cabd7 100644 (file)
@@ -1098,12 +1098,19 @@ static struct configfs_attribute *nvmet_referral_attrs[] = {
        NULL,
 };
 
-static void nvmet_referral_release(struct config_item *item)
+static void nvmet_referral_notify(struct config_group *group,
+               struct config_item *item)
 {
        struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
        struct nvmet_port *port = to_nvmet_port(item);
 
        nvmet_referral_disable(parent, port);
+}
+
+static void nvmet_referral_release(struct config_item *item)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+
        kfree(port);
 }
 
@@ -1134,6 +1141,7 @@ static struct config_group *nvmet_referral_make(
 
 static struct configfs_group_operations nvmet_referral_group_ops = {
        .make_group             = nvmet_referral_make,
+       .disconnect_notify      = nvmet_referral_notify,
 };
 
 static const struct config_item_type nvmet_referrals_type = {
index a0db637..a8ceb77 100644 (file)
@@ -684,7 +684,7 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue)
        disconnect = atomic_xchg(&queue->connected, 0);
 
        spin_lock_irqsave(&queue->qlock, flags);
-       /* about outstanding io's */
+       /* abort outstanding io's */
        for (i = 0; i < queue->sqsize; fod++, i++) {
                if (fod->active) {
                        spin_lock(&fod->flock);
index 1c50af6..f69ce66 100644 (file)
@@ -198,10 +198,13 @@ struct fcloop_lport_priv {
 };
 
 struct fcloop_rport {
-       struct nvme_fc_remote_port *remoteport;
-       struct nvmet_fc_target_port *targetport;
-       struct fcloop_nport *nport;
-       struct fcloop_lport *lport;
+       struct nvme_fc_remote_port      *remoteport;
+       struct nvmet_fc_target_port     *targetport;
+       struct fcloop_nport             *nport;
+       struct fcloop_lport             *lport;
+       spinlock_t                      lock;
+       struct list_head                ls_list;
+       struct work_struct              ls_work;
 };
 
 struct fcloop_tport {
@@ -224,11 +227,10 @@ struct fcloop_nport {
 };
 
 struct fcloop_lsreq {
-       struct fcloop_tport             *tport;
        struct nvmefc_ls_req            *lsreq;
-       struct work_struct              work;
        struct nvmefc_tgt_ls_req        tgt_ls_req;
        int                             status;
+       struct list_head                ls_list; /* fcloop_rport->ls_list */
 };
 
 struct fcloop_rscn {
@@ -292,21 +294,32 @@ fcloop_delete_queue(struct nvme_fc_local_port *localport,
 {
 }
 
-
-/*
- * Transmit of LS RSP done (e.g. buffers all set). call back up
- * initiator "done" flows.
- */
 static void
-fcloop_tgt_lsrqst_done_work(struct work_struct *work)
+fcloop_rport_lsrqst_work(struct work_struct *work)
 {
-       struct fcloop_lsreq *tls_req =
-               container_of(work, struct fcloop_lsreq, work);
-       struct fcloop_tport *tport = tls_req->tport;
-       struct nvmefc_ls_req *lsreq = tls_req->lsreq;
+       struct fcloop_rport *rport =
+               container_of(work, struct fcloop_rport, ls_work);
+       struct fcloop_lsreq *tls_req;
 
-       if (!tport || tport->remoteport)
-               lsreq->done(lsreq, tls_req->status);
+       spin_lock(&rport->lock);
+       for (;;) {
+               tls_req = list_first_entry_or_null(&rport->ls_list,
+                               struct fcloop_lsreq, ls_list);
+               if (!tls_req)
+                       break;
+
+               list_del(&tls_req->ls_list);
+               spin_unlock(&rport->lock);
+
+               tls_req->lsreq->done(tls_req->lsreq, tls_req->status);
+               /*
+                * callee may free memory containing tls_req.
+                * do not reference lsreq after this.
+                */
+
+               spin_lock(&rport->lock);
+       }
+       spin_unlock(&rport->lock);
 }
 
 static int
@@ -319,17 +332,18 @@ fcloop_ls_req(struct nvme_fc_local_port *localport,
        int ret = 0;
 
        tls_req->lsreq = lsreq;
-       INIT_WORK(&tls_req->work, fcloop_tgt_lsrqst_done_work);
+       INIT_LIST_HEAD(&tls_req->ls_list);
 
        if (!rport->targetport) {
                tls_req->status = -ECONNREFUSED;
-               tls_req->tport = NULL;
-               schedule_work(&tls_req->work);
+               spin_lock(&rport->lock);
+               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               spin_unlock(&rport->lock);
+               schedule_work(&rport->ls_work);
                return ret;
        }
 
        tls_req->status = 0;
-       tls_req->tport = rport->targetport->private;
        ret = nvmet_fc_rcv_ls_req(rport->targetport, &tls_req->tgt_ls_req,
                                 lsreq->rqstaddr, lsreq->rqstlen);
 
@@ -337,18 +351,28 @@ fcloop_ls_req(struct nvme_fc_local_port *localport,
 }
 
 static int
-fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport,
+fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *targetport,
                        struct nvmefc_tgt_ls_req *tgt_lsreq)
 {
        struct fcloop_lsreq *tls_req = tgt_ls_req_to_lsreq(tgt_lsreq);
        struct nvmefc_ls_req *lsreq = tls_req->lsreq;
+       struct fcloop_tport *tport = targetport->private;
+       struct nvme_fc_remote_port *remoteport = tport->remoteport;
+       struct fcloop_rport *rport;
 
        memcpy(lsreq->rspaddr, tgt_lsreq->rspbuf,
                ((lsreq->rsplen < tgt_lsreq->rsplen) ?
                                lsreq->rsplen : tgt_lsreq->rsplen));
+
        tgt_lsreq->done(tgt_lsreq);
 
-       schedule_work(&tls_req->work);
+       if (remoteport) {
+               rport = remoteport->private;
+               spin_lock(&rport->lock);
+               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               spin_unlock(&rport->lock);
+               schedule_work(&rport->ls_work);
+       }
 
        return 0;
 }
@@ -834,6 +858,7 @@ fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport)
 {
        struct fcloop_rport *rport = remoteport->private;
 
+       flush_work(&rport->ls_work);
        fcloop_nport_put(rport->nport);
 }
 
@@ -850,7 +875,6 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
 #define FCLOOP_DMABOUND_4G             0xFFFFFFFF
 
 static struct nvme_fc_port_template fctemplate = {
-       .module                 = THIS_MODULE,
        .localport_delete       = fcloop_localport_delete,
        .remoteport_delete      = fcloop_remoteport_delete,
        .create_queue           = fcloop_create_queue,
@@ -1136,6 +1160,9 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr,
        rport->nport = nport;
        rport->lport = nport->lport;
        nport->rport = rport;
+       spin_lock_init(&rport->lock);
+       INIT_WORK(&rport->ls_work, fcloop_rport_lsrqst_work);
+       INIT_LIST_HEAD(&rport->ls_list);
 
        return count;
 }
index c90c068..fd47de0 100644 (file)
@@ -78,6 +78,7 @@ enum nvmet_rdma_queue_state {
 
 struct nvmet_rdma_queue {
        struct rdma_cm_id       *cm_id;
+       struct ib_qp            *qp;
        struct nvmet_port       *port;
        struct ib_cq            *cq;
        atomic_t                sq_wr_avail;
@@ -105,6 +106,13 @@ struct nvmet_rdma_queue {
        struct list_head        queue_list;
 };
 
+struct nvmet_rdma_port {
+       struct nvmet_port       *nport;
+       struct sockaddr_storage addr;
+       struct rdma_cm_id       *cm_id;
+       struct delayed_work     repair_work;
+};
+
 struct nvmet_rdma_device {
        struct ib_device        *device;
        struct ib_pd            *pd;
@@ -461,7 +469,7 @@ static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev,
        if (ndev->srq)
                ret = ib_post_srq_recv(ndev->srq, &cmd->wr, NULL);
        else
-               ret = ib_post_recv(cmd->queue->cm_id->qp, &cmd->wr, NULL);
+               ret = ib_post_recv(cmd->queue->qp, &cmd->wr, NULL);
 
        if (unlikely(ret))
                pr_err("post_recv cmd failed\n");
@@ -500,7 +508,7 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
        atomic_add(1 + rsp->n_rdma, &queue->sq_wr_avail);
 
        if (rsp->n_rdma) {
-               rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
+               rdma_rw_ctx_destroy(&rsp->rw, queue->qp,
                                queue->cm_id->port_num, rsp->req.sg,
                                rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
        }
@@ -584,7 +592,7 @@ static void nvmet_rdma_read_data_done(struct ib_cq *cq, struct ib_wc *wc)
 
        WARN_ON(rsp->n_rdma <= 0);
        atomic_add(rsp->n_rdma, &queue->sq_wr_avail);
-       rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
+       rdma_rw_ctx_destroy(&rsp->rw, queue->qp,
                        queue->cm_id->port_num, rsp->req.sg,
                        rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
        rsp->n_rdma = 0;
@@ -739,7 +747,7 @@ static bool nvmet_rdma_execute_command(struct nvmet_rdma_rsp *rsp)
        }
 
        if (nvmet_rdma_need_data_in(rsp)) {
-               if (rdma_rw_ctx_post(&rsp->rw, queue->cm_id->qp,
+               if (rdma_rw_ctx_post(&rsp->rw, queue->qp,
                                queue->cm_id->port_num, &rsp->read_cqe, NULL))
                        nvmet_req_complete(&rsp->req, NVME_SC_DATA_XFER_ERROR);
        } else {
@@ -911,7 +919,8 @@ static void nvmet_rdma_free_dev(struct kref *ref)
 static struct nvmet_rdma_device *
 nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
 {
-       struct nvmet_port *port = cm_id->context;
+       struct nvmet_rdma_port *port = cm_id->context;
+       struct nvmet_port *nport = port->nport;
        struct nvmet_rdma_device *ndev;
        int inline_page_count;
        int inline_sge_count;
@@ -928,17 +937,17 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
        if (!ndev)
                goto out_err;
 
-       inline_page_count = num_pages(port->inline_data_size);
+       inline_page_count = num_pages(nport->inline_data_size);
        inline_sge_count = max(cm_id->device->attrs.max_sge_rd,
                                cm_id->device->attrs.max_recv_sge) - 1;
        if (inline_page_count > inline_sge_count) {
                pr_warn("inline_data_size %d cannot be supported by device %s. Reducing to %lu.\n",
-                       port->inline_data_size, cm_id->device->name,
+                       nport->inline_data_size, cm_id->device->name,
                        inline_sge_count * PAGE_SIZE);
-               port->inline_data_size = inline_sge_count * PAGE_SIZE;
+               nport->inline_data_size = inline_sge_count * PAGE_SIZE;
                inline_page_count = inline_sge_count;
        }
-       ndev->inline_data_size = port->inline_data_size;
+       ndev->inline_data_size = nport->inline_data_size;
        ndev->inline_page_count = inline_page_count;
        ndev->device = cm_id->device;
        kref_init(&ndev->ref);
@@ -1024,6 +1033,7 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
                pr_err("failed to create_qp ret= %d\n", ret);
                goto err_destroy_cq;
        }
+       queue->qp = queue->cm_id->qp;
 
        atomic_set(&queue->sq_wr_avail, qp_attr.cap.max_send_wr);
 
@@ -1052,11 +1062,10 @@ err_destroy_cq:
 
 static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
 {
-       struct ib_qp *qp = queue->cm_id->qp;
-
-       ib_drain_qp(qp);
-       rdma_destroy_id(queue->cm_id);
-       ib_destroy_qp(qp);
+       ib_drain_qp(queue->qp);
+       if (queue->cm_id)
+               rdma_destroy_id(queue->cm_id);
+       ib_destroy_qp(queue->qp);
        ib_free_cq(queue->cq);
 }
 
@@ -1266,6 +1275,7 @@ static int nvmet_rdma_cm_accept(struct rdma_cm_id *cm_id,
 static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
                struct rdma_cm_event *event)
 {
+       struct nvmet_rdma_port *port = cm_id->context;
        struct nvmet_rdma_device *ndev;
        struct nvmet_rdma_queue *queue;
        int ret = -EINVAL;
@@ -1281,7 +1291,7 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
                ret = -ENOMEM;
                goto put_device;
        }
-       queue->port = cm_id->context;
+       queue->port = port->nport;
 
        if (queue->host_qid == 0) {
                /* Let inflight controller teardown complete */
@@ -1290,9 +1300,12 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
 
        ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
        if (ret) {
-               schedule_work(&queue->release_work);
-               /* Destroying rdma_cm id is not needed here */
-               return 0;
+               /*
+                * Don't destroy the cm_id in free path, as we implicitly
+                * destroy the cm_id here with non-zero ret code.
+                */
+               queue->cm_id = NULL;
+               goto free_queue;
        }
 
        mutex_lock(&nvmet_rdma_queue_mutex);
@@ -1301,6 +1314,8 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
 
        return 0;
 
+free_queue:
+       nvmet_rdma_free_queue(queue);
 put_device:
        kref_put(&ndev->ref, nvmet_rdma_free_dev);
 
@@ -1406,7 +1421,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
 static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id,
                struct nvmet_rdma_queue *queue)
 {
-       struct nvmet_port *port;
+       struct nvmet_rdma_port *port;
 
        if (queue) {
                /*
@@ -1425,7 +1440,7 @@ static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id,
         * cm_id destroy. use atomic xchg to make sure
         * we don't compete with remove_port.
         */
-       if (xchg(&port->priv, NULL) != cm_id)
+       if (xchg(&port->cm_id, NULL) != cm_id)
                return 0;
 
        /*
@@ -1456,6 +1471,13 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
                nvmet_rdma_queue_established(queue);
                break;
        case RDMA_CM_EVENT_ADDR_CHANGE:
+               if (!queue) {
+                       struct nvmet_rdma_port *port = cm_id->context;
+
+                       schedule_delayed_work(&port->repair_work, 0);
+                       break;
+               }
+               /* FALLTHROUGH */
        case RDMA_CM_EVENT_DISCONNECTED:
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:
                nvmet_rdma_queue_disconnect(queue);
@@ -1498,42 +1520,19 @@ restart:
        mutex_unlock(&nvmet_rdma_queue_mutex);
 }
 
-static int nvmet_rdma_add_port(struct nvmet_port *port)
+static void nvmet_rdma_disable_port(struct nvmet_rdma_port *port)
 {
-       struct rdma_cm_id *cm_id;
-       struct sockaddr_storage addr = { };
-       __kernel_sa_family_t af;
-       int ret;
+       struct rdma_cm_id *cm_id = xchg(&port->cm_id, NULL);
 
-       switch (port->disc_addr.adrfam) {
-       case NVMF_ADDR_FAMILY_IP4:
-               af = AF_INET;
-               break;
-       case NVMF_ADDR_FAMILY_IP6:
-               af = AF_INET6;
-               break;
-       default:
-               pr_err("address family %d not supported\n",
-                               port->disc_addr.adrfam);
-               return -EINVAL;
-       }
-
-       if (port->inline_data_size < 0) {
-               port->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE;
-       } else if (port->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) {
-               pr_warn("inline_data_size %u is too large, reducing to %u\n",
-                       port->inline_data_size,
-                       NVMET_RDMA_MAX_INLINE_DATA_SIZE);
-               port->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE;
-       }
+       if (cm_id)
+               rdma_destroy_id(cm_id);
+}
 
-       ret = inet_pton_with_scope(&init_net, af, port->disc_addr.traddr,
-                       port->disc_addr.trsvcid, &addr);
-       if (ret) {
-               pr_err("malformed ip/port passed: %s:%s\n",
-                       port->disc_addr.traddr, port->disc_addr.trsvcid);
-               return ret;
-       }
+static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port)
+{
+       struct sockaddr *addr = (struct sockaddr *)&port->addr;
+       struct rdma_cm_id *cm_id;
+       int ret;
 
        cm_id = rdma_create_id(&init_net, nvmet_rdma_cm_handler, port,
                        RDMA_PS_TCP, IB_QPT_RC);
@@ -1552,23 +1551,19 @@ static int nvmet_rdma_add_port(struct nvmet_port *port)
                goto out_destroy_id;
        }
 
-       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&addr);
+       ret = rdma_bind_addr(cm_id, addr);
        if (ret) {
-               pr_err("binding CM ID to %pISpcs failed (%d)\n",
-                       (struct sockaddr *)&addr, ret);
+               pr_err("binding CM ID to %pISpcs failed (%d)\n", addr, ret);
                goto out_destroy_id;
        }
 
        ret = rdma_listen(cm_id, 128);
        if (ret) {
-               pr_err("listening to %pISpcs failed (%d)\n",
-                       (struct sockaddr *)&addr, ret);
+               pr_err("listening to %pISpcs failed (%d)\n", addr, ret);
                goto out_destroy_id;
        }
 
-       pr_info("enabling port %d (%pISpcs)\n",
-               le16_to_cpu(port->disc_addr.portid), (struct sockaddr *)&addr);
-       port->priv = cm_id;
+       port->cm_id = cm_id;
        return 0;
 
 out_destroy_id:
@@ -1576,18 +1571,92 @@ out_destroy_id:
        return ret;
 }
 
-static void nvmet_rdma_remove_port(struct nvmet_port *port)
+static void nvmet_rdma_repair_port_work(struct work_struct *w)
 {
-       struct rdma_cm_id *cm_id = xchg(&port->priv, NULL);
+       struct nvmet_rdma_port *port = container_of(to_delayed_work(w),
+                       struct nvmet_rdma_port, repair_work);
+       int ret;
 
-       if (cm_id)
-               rdma_destroy_id(cm_id);
+       nvmet_rdma_disable_port(port);
+       ret = nvmet_rdma_enable_port(port);
+       if (ret)
+               schedule_delayed_work(&port->repair_work, 5 * HZ);
+}
+
+static int nvmet_rdma_add_port(struct nvmet_port *nport)
+{
+       struct nvmet_rdma_port *port;
+       __kernel_sa_family_t af;
+       int ret;
+
+       port = kzalloc(sizeof(*port), GFP_KERNEL);
+       if (!port)
+               return -ENOMEM;
+
+       nport->priv = port;
+       port->nport = nport;
+       INIT_DELAYED_WORK(&port->repair_work, nvmet_rdma_repair_port_work);
+
+       switch (nport->disc_addr.adrfam) {
+       case NVMF_ADDR_FAMILY_IP4:
+               af = AF_INET;
+               break;
+       case NVMF_ADDR_FAMILY_IP6:
+               af = AF_INET6;
+               break;
+       default:
+               pr_err("address family %d not supported\n",
+                       nport->disc_addr.adrfam);
+               ret = -EINVAL;
+               goto out_free_port;
+       }
+
+       if (nport->inline_data_size < 0) {
+               nport->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE;
+       } else if (nport->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) {
+               pr_warn("inline_data_size %u is too large, reducing to %u\n",
+                       nport->inline_data_size,
+                       NVMET_RDMA_MAX_INLINE_DATA_SIZE);
+               nport->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE;
+       }
+
+       ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr,
+                       nport->disc_addr.trsvcid, &port->addr);
+       if (ret) {
+               pr_err("malformed ip/port passed: %s:%s\n",
+                       nport->disc_addr.traddr, nport->disc_addr.trsvcid);
+               goto out_free_port;
+       }
+
+       ret = nvmet_rdma_enable_port(port);
+       if (ret)
+               goto out_free_port;
+
+       pr_info("enabling port %d (%pISpcs)\n",
+               le16_to_cpu(nport->disc_addr.portid),
+               (struct sockaddr *)&port->addr);
+
+       return 0;
+
+out_free_port:
+       kfree(port);
+       return ret;
+}
+
+static void nvmet_rdma_remove_port(struct nvmet_port *nport)
+{
+       struct nvmet_rdma_port *port = nport->priv;
+
+       cancel_delayed_work_sync(&port->repair_work);
+       nvmet_rdma_disable_port(port);
+       kfree(port);
 }
 
 static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
-               struct nvmet_port *port, char *traddr)
+               struct nvmet_port *nport, char *traddr)
 {
-       struct rdma_cm_id *cm_id = port->priv;
+       struct nvmet_rdma_port *port = nport->priv;
+       struct rdma_cm_id *cm_id = port->cm_id;
 
        if (inet_addr_is_any((struct sockaddr *)&cm_id->route.addr.src_addr)) {
                struct nvmet_rdma_rsp *rsp =
@@ -1597,7 +1666,7 @@ static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
 
                sprintf(traddr, "%pISc", addr);
        } else {
-               memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE);
+               memcpy(traddr, nport->disc_addr.traddr, NVMF_TRADDR_SIZE);
        }
 }
 
index 30190be..eebbc91 100644 (file)
@@ -33,6 +33,15 @@ config PWM_SYSFS
        bool
        default y if SYSFS
 
+config PWM_DEBUG
+       bool "PWM lowlevel drivers additional checks and debug messages"
+       depends on DEBUG_KERNEL
+       help
+         This option enables some additional checks to help lowlevel driver
+         authors to get their callbacks implemented correctly.
+         It is expected to introduce some runtime overhead and diagnostic
+         output to the kernel log, so only enable while working on a driver.
+
 config PWM_AB8500
        tristate "AB8500 PWM support"
        depends on AB8500_CORE && ARCH_U8500
@@ -44,7 +53,8 @@ config PWM_AB8500
 
 config PWM_ATMEL
        tristate "Atmel PWM support"
-       depends on ARCH_AT91 && OF
+       depends on OF
+       depends on ARCH_AT91 || COMPILE_TEST
        help
          Generic PWM framework driver for Atmel SoC.
 
@@ -100,7 +110,7 @@ config PWM_BCM_KONA
 
 config PWM_BCM2835
        tristate "BCM2835 PWM support"
-       depends on ARCH_BCM2835 || ARCH_BRCMSTB
+       depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
        help
          PWM framework driver for BCM2835 controller (Raspberry Pi)
 
@@ -109,7 +119,7 @@ config PWM_BCM2835
 
 config PWM_BERLIN
        tristate "Marvell Berlin PWM support"
-       depends on ARCH_BERLIN
+       depends on ARCH_BERLIN || COMPILE_TEST
        help
          PWM framework driver for Marvell Berlin SoCs.
 
@@ -118,7 +128,7 @@ config PWM_BERLIN
 
 config PWM_BRCMSTB
        tristate "Broadcom STB PWM support"
-       depends on ARCH_BRCMSTB || BMIPS_GENERIC
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
        help
          Generic PWM framework driver for the Broadcom Set-top-Box
          SoCs (BCM7xxx).
@@ -152,7 +162,7 @@ config PWM_CROS_EC
 
 config PWM_EP93XX
        tristate "Cirrus Logic EP93xx PWM support"
-       depends on ARCH_EP93XX
+       depends on ARCH_EP93XX || COMPILE_TEST
        help
          Generic PWM framework driver for Cirrus Logic EP93xx.
 
@@ -195,7 +205,7 @@ config PWM_IMG
 
 config PWM_IMX1
        tristate "i.MX1 PWM support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Generic PWM framework driver for i.MX1 and i.MX21
 
@@ -204,7 +214,7 @@ config PWM_IMX1
 
 config PWM_IMX27
        tristate "i.MX27 PWM support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Generic PWM framework driver for i.MX27 and later i.MX SoCs.
 
@@ -225,6 +235,8 @@ config PWM_IMX_TPM
 config PWM_JZ4740
        tristate "Ingenic JZ47xx PWM support"
        depends on MACH_INGENIC
+       depends on COMMON_CLK
+       select MFD_SYSCON
        help
          Generic PWM framework driver for Ingenic JZ47xx based
          machines.
@@ -244,7 +256,7 @@ config PWM_LP3943
 
 config PWM_LPC18XX_SCT
        tristate "LPC18xx/43xx PWM/SCT support"
-       depends on ARCH_LPC18XX
+       depends on ARCH_LPC18XX || COMPILE_TEST
        help
          Generic PWM framework driver for NXP LPC18xx PWM/SCT which
          supports 16 channels.
@@ -256,7 +268,7 @@ config PWM_LPC18XX_SCT
 
 config PWM_LPC32XX
        tristate "LPC32XX PWM support"
-       depends on ARCH_LPC32XX
+       depends on ARCH_LPC32XX || COMPILE_TEST
        help
          Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two
          PWM controllers.
@@ -289,7 +301,8 @@ config PWM_LPSS_PLATFORM
 
 config PWM_MESON
        tristate "Amlogic Meson PWM driver"
-       depends on ARCH_MESON
+       depends on ARCH_MESON || COMPILE_TEST
+       depends on COMMON_CLK
        help
          The platform driver for Amlogic Meson PWM controller.
 
@@ -318,7 +331,8 @@ config PWM_MEDIATEK
 
 config PWM_MXS
        tristate "Freescale MXS PWM support"
-       depends on ARCH_MXS && OF
+       depends on OF
+       depends on ARCH_MXS || COMPILE_TEST
        select STMP_DEVICE
        help
          Generic PWM framework driver for Freescale MXS.
@@ -357,7 +371,7 @@ config PWM_PUV3
 
 config PWM_PXA
        tristate "PXA PWM support"
-       depends on ARCH_PXA
+       depends on ARCH_PXA || COMPILE_TEST
        help
          Generic PWM framework driver for PXA.
 
@@ -388,14 +402,14 @@ config PWM_RENESAS_TPU
 
 config PWM_ROCKCHIP
        tristate "Rockchip PWM support"
-       depends on ARCH_ROCKCHIP
+       depends on ARCH_ROCKCHIP || COMPILE_TEST
        help
          Generic PWM framework driver for the PWM controller found on
          Rockchip SoCs.
 
 config PWM_SAMSUNG
        tristate "Samsung PWM support"
-       depends on PLAT_SAMSUNG || ARCH_EXYNOS
+       depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
        help
          Generic PWM framework driver for Samsung.
 
@@ -415,7 +429,7 @@ config PWM_SIFIVE
 
 config PWM_SPEAR
        tristate "STMicroelectronics SPEAr PWM support"
-       depends on PLAT_SPEAR
+       depends on PLAT_SPEAR || COMPILE_TEST
        depends on OF
        help
          Generic PWM framework driver for the PWM controller on ST
@@ -437,7 +451,7 @@ config PWM_SPRD
 
 config PWM_STI
        tristate "STiH4xx PWM support"
-       depends on ARCH_STI
+       depends on ARCH_STI || COMPILE_TEST
        depends on OF
        help
          Generic PWM framework driver for STiH4xx SoCs.
@@ -447,7 +461,7 @@ config PWM_STI
 
 config PWM_STM32
        tristate "STMicroelectronics STM32 PWM"
-       depends on MFD_STM32_TIMERS
+       depends on MFD_STM32_TIMERS || COMPILE_TEST
        help
          Generic PWM framework driver for STM32 SoCs.
 
@@ -483,7 +497,7 @@ config PWM_SUN4I
 
 config PWM_TEGRA
        tristate "NVIDIA Tegra PWM support"
-       depends on ARCH_TEGRA
+       depends on ARCH_TEGRA || COMPILE_TEST
        help
          Generic PWM framework driver for the PWFM controller found on NVIDIA
          Tegra SoCs.
@@ -493,7 +507,7 @@ config PWM_TEGRA
 
 config PWM_TIECAP
        tristate "ECAP PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
        help
          PWM driver support for the ECAP APWM controller found on TI SOCs
 
@@ -502,7 +516,7 @@ config PWM_TIECAP
 
 config PWM_TIEHRPWM
        tristate "EHRPWM PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 || COMPILE_TEST
        help
          PWM driver support for the EHRPWM controller found on TI SOCs
 
@@ -529,7 +543,7 @@ config PWM_TWL_LED
 
 config PWM_VT8500
        tristate "vt8500 PWM support"
-       depends on ARCH_VT8500
+       depends on ARCH_VT8500 || COMPILE_TEST
        help
          Generic PWM framework driver for vt8500.
 
@@ -538,7 +552,7 @@ config PWM_VT8500
 
 config PWM_ZX
        tristate "ZTE ZX PWM support"
-       depends on ARCH_ZX
+       depends on ARCH_ZX || COMPILE_TEST
        help
          Generic PWM framework driver for ZTE ZX family SoCs.
 
index 5a7f659..9973c44 100644 (file)
@@ -120,6 +120,9 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        if (pwm->chip->ops->get_state) {
                pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state);
                trace_pwm_get(pwm, &pwm->state);
+
+               if (IS_ENABLED(PWM_DEBUG))
+                       pwm->last = pwm->state;
        }
 
        set_bit(PWMF_REQUESTED, &pwm->flags);
@@ -232,17 +235,28 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_get_chip_data);
 
-static bool pwm_ops_check(const struct pwm_ops *ops)
+static bool pwm_ops_check(const struct pwm_chip *chip)
 {
+
+       const struct pwm_ops *ops = chip->ops;
+
        /* driver supports legacy, non-atomic operation */
-       if (ops->config && ops->enable && ops->disable)
-               return true;
+       if (ops->config && ops->enable && ops->disable) {
+               if (IS_ENABLED(CONFIG_PWM_DEBUG))
+                       dev_warn(chip->dev,
+                                "Driver needs updating to atomic API\n");
 
-       /* driver supports atomic operation */
-       if (ops->apply)
                return true;
+       }
 
-       return false;
+       if (!ops->apply)
+               return false;
+
+       if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
+               dev_warn(chip->dev,
+                        "Please implement the .get_state() callback\n");
+
+       return true;
 }
 
 /**
@@ -266,7 +280,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
        if (!chip || !chip->dev || !chip->ops || !chip->npwm)
                return -EINVAL;
 
-       if (!pwm_ops_check(chip->ops))
+       if (!pwm_ops_check(chip))
                return -EINVAL;
 
        mutex_lock(&pwm_lock);
@@ -450,6 +464,107 @@ void pwm_free(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_free);
 
+static void pwm_apply_state_debug(struct pwm_device *pwm,
+                                 const struct pwm_state *state)
+{
+       struct pwm_state *last = &pwm->last;
+       struct pwm_chip *chip = pwm->chip;
+       struct pwm_state s1, s2;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_PWM_DEBUG))
+               return;
+
+       /* No reasonable diagnosis possible without .get_state() */
+       if (!chip->ops->get_state)
+               return;
+
+       /*
+        * *state was just applied. Read out the hardware state and do some
+        * checks.
+        */
+
+       chip->ops->get_state(chip, pwm, &s1);
+       trace_pwm_get(pwm, &s1);
+
+       /*
+        * The lowlevel driver either ignored .polarity (which is a bug) or as
+        * best effort inverted .polarity and fixed .duty_cycle respectively.
+        * Undo this inversion and fixup for further tests.
+        */
+       if (s1.enabled && s1.polarity != state->polarity) {
+               s2.polarity = state->polarity;
+               s2.duty_cycle = s1.period - s1.duty_cycle;
+               s2.period = s1.period;
+               s2.enabled = s1.enabled;
+       } else {
+               s2 = s1;
+       }
+
+       if (s2.polarity != state->polarity &&
+           state->duty_cycle < state->period)
+               dev_warn(chip->dev, ".apply ignored .polarity\n");
+
+       if (state->enabled &&
+           last->polarity == state->polarity &&
+           last->period > s2.period &&
+           last->period <= state->period)
+               dev_warn(chip->dev,
+                        ".apply didn't pick the best available period (requested: %u, applied: %u, possible: %u)\n",
+                        state->period, s2.period, last->period);
+
+       if (state->enabled && state->period < s2.period)
+               dev_warn(chip->dev,
+                        ".apply is supposed to round down period (requested: %u, applied: %u)\n",
+                        state->period, s2.period);
+
+       if (state->enabled &&
+           last->polarity == state->polarity &&
+           last->period == s2.period &&
+           last->duty_cycle > s2.duty_cycle &&
+           last->duty_cycle <= state->duty_cycle)
+               dev_warn(chip->dev,
+                        ".apply didn't pick the best available duty cycle (requested: %u/%u, applied: %u/%u, possible: %u/%u)\n",
+                        state->duty_cycle, state->period,
+                        s2.duty_cycle, s2.period,
+                        last->duty_cycle, last->period);
+
+       if (state->enabled && state->duty_cycle < s2.duty_cycle)
+               dev_warn(chip->dev,
+                        ".apply is supposed to round down duty_cycle (requested: %u/%u, applied: %u/%u)\n",
+                        state->duty_cycle, state->period,
+                        s2.duty_cycle, s2.period);
+
+       if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
+               dev_warn(chip->dev,
+                        "requested disabled, but yielded enabled with duty > 0");
+
+       /* reapply the state that the driver reported being configured. */
+       err = chip->ops->apply(chip, pwm, &s1);
+       if (err) {
+               *last = s1;
+               dev_err(chip->dev, "failed to reapply current setting\n");
+               return;
+       }
+
+       trace_pwm_apply(pwm, &s1);
+
+       chip->ops->get_state(chip, pwm, last);
+       trace_pwm_get(pwm, last);
+
+       /* reapplication of the current state should give an exact match */
+       if (s1.enabled != last->enabled ||
+           s1.polarity != last->polarity ||
+           (s1.enabled && s1.period != last->period) ||
+           (s1.enabled && s1.duty_cycle != last->duty_cycle)) {
+               dev_err(chip->dev,
+                       ".apply is not idempotent (ena=%d pol=%d %u/%u) -> (ena=%d pol=%d %u/%u)\n",
+                       s1.enabled, s1.polarity, s1.duty_cycle, s1.period,
+                       last->enabled, last->polarity, last->duty_cycle,
+                       last->period);
+       }
+}
+
 /**
  * pwm_apply_state() - atomically apply a new state to a PWM device
  * @pwm: PWM device
@@ -480,6 +595,12 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
                trace_pwm_apply(pwm, state);
 
                pwm->state = *state;
+
+               /*
+                * only do this after pwm->state was applied as some
+                * implementations of .get_state depend on this
+                */
+               pwm_apply_state_debug(pwm, state);
        } else {
                /*
                 * FIXME: restore the initial state in case of error.
index 91e24f0..d78f86f 100644 (file)
@@ -166,6 +166,7 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &bcm2835_pwm_ops;
+       pc->chip.base = -1;
        pc->chip.npwm = 2;
        pc->chip.of_xlate = of_pwm_xlate_with_flags;
        pc->chip.of_pwm_n_cells = 3;
index 9145f61..5f3d7f7 100644 (file)
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
index 35a7ac4..a6e40d4 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
@@ -96,9 +95,8 @@ struct pwm_imx27_chip {
 
 #define to_pwm_imx27_chip(chip)        container_of(chip, struct pwm_imx27_chip, chip)
 
-static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip)
+static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
 {
-       struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
        int ret;
 
        ret = clk_prepare_enable(imx->clk_ipg);
@@ -114,10 +112,8 @@ static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip)
        return 0;
 }
 
-static void pwm_imx27_clk_disable_unprepare(struct pwm_chip *chip)
+static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx)
 {
-       struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
-
        clk_disable_unprepare(imx->clk_per);
        clk_disable_unprepare(imx->clk_ipg);
 }
@@ -130,7 +126,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
        u64 tmp;
        int ret;
 
-       ret = pwm_imx27_clk_prepare_enable(chip);
+       ret = pwm_imx27_clk_prepare_enable(imx);
        if (ret < 0)
                return;
 
@@ -174,8 +170,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
        tmp = NSEC_PER_SEC * (u64)(val);
        state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
 
-       if (!state->enabled)
-               pwm_imx27_clk_disable_unprepare(chip);
+       pwm_imx27_clk_disable_unprepare(imx);
 }
 
 static void pwm_imx27_sw_reset(struct pwm_chip *chip)
@@ -259,7 +254,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        if (cstate.enabled) {
                pwm_imx27_wait_fifo_slot(chip, pwm);
        } else {
-               ret = pwm_imx27_clk_prepare_enable(chip);
+               ret = pwm_imx27_clk_prepare_enable(imx);
                if (ret)
                        return ret;
 
@@ -289,8 +284,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        writel(cr, imx->mmio_base + MX3_PWMCR);
 
-       if (!state->enabled && cstate.enabled)
-               pwm_imx27_clk_disable_unprepare(chip);
+       if (!state->enabled)
+               pwm_imx27_clk_disable_unprepare(imx);
 
        return 0;
 }
@@ -310,6 +305,8 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
 static int pwm_imx27_probe(struct platform_device *pdev)
 {
        struct pwm_imx27_chip *imx;
+       int ret;
+       u32 pwmcr;
 
        imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
        if (imx == NULL)
@@ -352,6 +349,15 @@ static int pwm_imx27_probe(struct platform_device *pdev)
        if (IS_ERR(imx->mmio_base))
                return PTR_ERR(imx->mmio_base);
 
+       ret = pwm_imx27_clk_prepare_enable(imx);
+       if (ret)
+               return ret;
+
+       /* keep clks on if pwm is running */
+       pwmcr = readl(imx->mmio_base + MX3_PWMCR);
+       if (!(pwmcr & MX3_PWMCR_EN))
+               pwm_imx27_clk_disable_unprepare(imx);
+
        return pwmchip_add(&imx->chip);
 }
 
@@ -361,8 +367,6 @@ static int pwm_imx27_remove(struct platform_device *pdev)
 
        imx = platform_get_drvdata(pdev);
 
-       pwm_imx27_clk_disable_unprepare(&imx->chip);
-
        return pwmchip_remove(&imx->chip);
 }
 
index 9d78cc2..3cd5c05 100644 (file)
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
+#include <linux/mfd/ingenic-tcu.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
-
-#include <asm/mach-jz4740/timer.h>
+#include <linux/regmap.h>
 
 #define NUM_PWM 8
 
 struct jz4740_pwm_chip {
        struct pwm_chip chip;
-       struct clk *clk;
+       struct regmap *map;
 };
 
 static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
@@ -32,82 +33,134 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
        return container_of(chip, struct jz4740_pwm_chip, chip);
 }
 
+static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
+                                  unsigned int channel)
+{
+       /* Enable all TCU channels for PWM use by default except channels 0/1 */
+       u32 pwm_channels_mask = GENMASK(NUM_PWM - 1, 2);
+
+       device_property_read_u32(jz->chip.dev->parent,
+                                "ingenic,pwm-channels-mask",
+                                &pwm_channels_mask);
+
+       return !!(pwm_channels_mask & BIT(channel));
+}
+
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       /*
-        * Timers 0 and 1 are used for system tasks, so they are unavailable
-        * for use as PWMs.
-        */
-       if (pwm->hwpwm < 2)
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
+       struct clk *clk;
+       char name[16];
+       int err;
+
+       if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm))
                return -EBUSY;
 
-       jz4740_timer_start(pwm->hwpwm);
+       snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
+
+       clk = clk_get(chip->dev, name);
+       if (IS_ERR(clk)) {
+               if (PTR_ERR(clk) != -EPROBE_DEFER)
+                       dev_err(chip->dev, "Failed to get clock: %pe", clk);
+
+               return PTR_ERR(clk);
+       }
+
+       err = clk_prepare_enable(clk);
+       if (err < 0) {
+               clk_put(clk);
+               return err;
+       }
+
+       pwm_set_chip_data(pwm, clk);
 
        return 0;
 }
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       jz4740_timer_set_ctrl(pwm->hwpwm, 0);
+       struct clk *clk = pwm_get_chip_data(pwm);
 
-       jz4740_timer_stop(pwm->hwpwm);
+       clk_disable_unprepare(clk);
+       clk_put(clk);
 }
 
 static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
+
+       /* Enable PWM output */
+       regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN);
 
-       ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
-       jz4740_timer_enable(pwm->hwpwm);
+       /* Start counter */
+       regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm));
 
        return 0;
 }
 
 static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
 
        /*
         * Set duty > period. This trick allows the TCU channels in TCU2 mode to
         * properly return to their init level.
         */
-       jz4740_timer_set_duty(pwm->hwpwm, 0xffff);
-       jz4740_timer_set_period(pwm->hwpwm, 0x0);
+       regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff);
+       regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0);
 
        /*
         * Disable PWM output.
         * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
         * counter is stopped, while in TCU1 mode the order does not matter.
         */
-       ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+       regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_EN, 0);
 
        /* Stop counter */
-       jz4740_timer_disable(pwm->hwpwm);
+       regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm));
 }
 
 static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                            const struct pwm_state *state)
 {
        struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
-       unsigned long long tmp;
+       unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
+       struct clk *clk = pwm_get_chip_data(pwm);
        unsigned long period, duty;
-       unsigned int prescaler = 0;
-       uint16_t ctrl;
+       long rate;
+       int err;
 
-       tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period;
-       do_div(tmp, 1000000000);
-       period = tmp;
+       /*
+        * Limit the clock to a maximum rate that still gives us a period value
+        * which fits in 16 bits.
+        */
+       do_div(tmp, state->period);
 
-       while (period > 0xffff && prescaler < 6) {
-               period >>= 2;
-               ++prescaler;
+       /*
+        * /!\ IMPORTANT NOTE:
+        * -------------------
+        * This code relies on the fact that clk_round_rate() will always round
+        * down, which is not a valid assumption given by the clk API, but only
+        * happens to be true with the clk drivers used for Ingenic SoCs.
+        *
+        * Right now, there is no alternative as the clk API does not have a
+        * round-down function (and won't have one for a while), but if it ever
+        * comes to light, a round-down function should be used instead.
+        */
+       rate = clk_round_rate(clk, tmp);
+       if (rate < 0) {
+               dev_err(chip->dev, "Unable to round rate: %ld", rate);
+               return rate;
        }
 
-       if (prescaler == 6)
-               return -EINVAL;
+       /* Calculate period value */
+       tmp = (unsigned long long)rate * state->period;
+       do_div(tmp, NSEC_PER_SEC);
+       period = (unsigned long)tmp;
 
+       /* Calculate duty value */
        tmp = (unsigned long long)period * state->duty_cycle;
        do_div(tmp, state->period);
        duty = period - tmp;
@@ -117,26 +170,38 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        jz4740_pwm_disable(chip, pwm);
 
-       jz4740_timer_set_count(pwm->hwpwm, 0);
-       jz4740_timer_set_duty(pwm->hwpwm, duty);
-       jz4740_timer_set_period(pwm->hwpwm, period);
+       err = clk_set_rate(clk, rate);
+       if (err) {
+               dev_err(chip->dev, "Unable to set rate: %d", err);
+               return err;
+       }
+
+       /* Reset counter to 0 */
+       regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
 
-       ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
-               JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
+       /* Set duty */
+       regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
 
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+       /* Set period */
+       regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period);
 
+       /* Set abrupt shutdown */
+       regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD);
+
+       /* Set polarity */
        switch (state->polarity) {
        case PWM_POLARITY_NORMAL:
-               ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
+               regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                                  TCU_TCSR_PWM_INITL_HIGH, 0);
                break;
        case PWM_POLARITY_INVERSED:
-               ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
+               regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                                  TCU_TCSR_PWM_INITL_HIGH,
+                                  TCU_TCSR_PWM_INITL_HIGH);
                break;
        }
 
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
-
        if (state->enabled)
                jz4740_pwm_enable(chip, pwm);
 
@@ -152,17 +217,20 @@ static const struct pwm_ops jz4740_pwm_ops = {
 
 static int jz4740_pwm_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct jz4740_pwm_chip *jz4740;
 
-       jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
+       jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL);
        if (!jz4740)
                return -ENOMEM;
 
-       jz4740->clk = devm_clk_get(&pdev->dev, "ext");
-       if (IS_ERR(jz4740->clk))
-               return PTR_ERR(jz4740->clk);
+       jz4740->map = device_node_to_regmap(dev->parent->of_node);
+       if (IS_ERR(jz4740->map)) {
+               dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map));
+               return PTR_ERR(jz4740->map);
+       }
 
-       jz4740->chip.dev = &pdev->dev;
+       jz4740->chip.dev = dev;
        jz4740->chip.ops = &jz4740_pwm_ops;
        jz4740->chip.npwm = NUM_PWM;
        jz4740->chip.base = -1;
index 6245bbd..bd0d733 100644 (file)
@@ -136,7 +136,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
                        dev_err(dev, "failed to set parent %s for %s: %d\n",
                                __clk_get_name(channel->clk_parent),
                                __clk_get_name(channel->clk), err);
-                               return err;
+                       return err;
                }
        }
 
@@ -163,7 +163,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
 {
        struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
        unsigned int duty, period, pre_div, cnt, duty_cnt;
-       unsigned long fin_freq = -1;
+       unsigned long fin_freq;
 
        duty = state->duty_cycle;
        period = state->period;
index f2e57fc..7ce6169 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
index 9e4378d..0d31833 100644 (file)
  *
  * Description:
  *   This file is the core OMAP support for the generic, Linux
- *   PWM driver / controller, using the OMAP's dual-mode timers.
+ *   PWM driver / controller, using the OMAP's dual-mode timers
+ *   with a timer counter that goes up. When it overflows it gets
+ *   reloaded with the load value and the pwm output goes up.
+ *   When counter matches with match register, the output goes down.
+ *   Reference Manual: http://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
+ *
+ * Limitations:
+ * - When PWM is stopped, timer counter gets stopped immediately. This
+ *   doesn't allow the current PWM period to complete and stops abruptly.
+ * - When PWM is running and changing both duty cycle and period,
+ *   we cannot prevent in software that the output might produce
+ *   a period with mixed settings. Especially when period/duty_cyle
+ *   is updated while the pwm pin is high, current pwm period/duty_cycle
+ *   can get updated as below based on the current timer counter:
+ *     - period for current cycle =  current_period + new period
+ *     - duty_cycle for current period = current period + new duty_cycle.
+ * - PWM OMAP DM timer cannot change the polarity when pwm is active. When
+ *   user requests a change in polarity when in active state:
+ *     - PWM is stopped abruptly(without completing the current cycle)
+ *     - Polarity is changed
+ *     - A fresh cycle is started.
  */
 
 #include <linux/clk.h>
@@ -20,8 +40,8 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <clocksource/timer-ti-dm.h>
 #include <linux/platform_data/dmtimer-omap.h>
-#include <linux/platform_data/pwm_omap_dmtimer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pwm.h>
 #define DM_TIMER_LOAD_MIN 0xfffffffe
 #define DM_TIMER_MAX      0xffffffff
 
+/**
+ * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
+ *                               corresponding to omap dmtimer.
+ * @chip:              PWM chip structure representing PWM controller
+ * @mutex:             Mutex to protect pwm apply state
+ * @dm_timer:          Pointer to omap dm timer.
+ * @pdata:             Pointer to omap dm timer ops.
+ * dm_timer_pdev:      Pointer to omap dm timer platform device
+ */
 struct pwm_omap_dmtimer_chip {
        struct pwm_chip chip;
+       /* Mutex to protect pwm apply state */
        struct mutex mutex;
-       pwm_omap_dmtimer *dm_timer;
+       struct omap_dm_timer *dm_timer;
        const struct omap_dm_timer_ops *pdata;
        struct platform_device *dm_timer_pdev;
 };
@@ -45,11 +75,22 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
        return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
 }
 
+/**
+ * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
+ * @clk_rate:  pwm timer clock rate
+ * @ns:                time frame in nano seconds.
+ *
+ * Return number of clock cycles in a given period(ins ns).
+ */
 static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
 {
        return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
 }
 
+/**
+ * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
+ * @omap:      Pointer to pwm omap dm timer chip
+ */
 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
 {
        /*
@@ -67,28 +108,46 @@ static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
        omap->pdata->start(omap->dm_timer);
 }
 
-static int pwm_omap_dmtimer_enable(struct pwm_chip *chip,
-                                  struct pwm_device *pwm)
+/**
+ * pwm_omap_dmtimer_is_enabled() -  Detect if the pwm is enabled.
+ * @omap:      Pointer to pwm omap dm timer chip
+ *
+ * Return true if pwm is enabled else false.
+ */
+static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap)
 {
-       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       u32 status;
 
-       mutex_lock(&omap->mutex);
-       pwm_omap_dmtimer_start(omap);
-       mutex_unlock(&omap->mutex);
+       status = omap->pdata->get_pwm_status(omap->dm_timer);
 
-       return 0;
+       return !!(status & OMAP_TIMER_CTRL_ST);
 }
 
-static void pwm_omap_dmtimer_disable(struct pwm_chip *chip,
-                                    struct pwm_device *pwm)
+/**
+ * pwm_omap_dmtimer_polarity() -  Detect the polarity of pwm.
+ * @omap:      Pointer to pwm omap dm timer chip
+ *
+ * Return the polarity of pwm.
+ */
+static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap)
 {
-       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       u32 status;
 
-       mutex_lock(&omap->mutex);
-       omap->pdata->stop(omap->dm_timer);
-       mutex_unlock(&omap->mutex);
+       status = omap->pdata->get_pwm_status(omap->dm_timer);
+
+       return !!(status & OMAP_TIMER_CTRL_SCPWM);
 }
 
+/**
+ * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @duty_ns:   New duty cycle in nano seconds
+ * @period_ns: New period in nano seconds
+ *
+ * Return 0 if successfully changed the period/duty_cycle else appropriate
+ * error.
+ */
 static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
                                   struct pwm_device *pwm,
                                   int duty_ns, int period_ns)
@@ -96,31 +155,26 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
        u32 period_cycles, duty_cycles;
        u32 load_value, match_value;
-       struct clk *fclk;
        unsigned long clk_rate;
-       bool timer_active;
+       struct clk *fclk;
 
        dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
                duty_ns, period_ns);
 
-       mutex_lock(&omap->mutex);
        if (duty_ns == pwm_get_duty_cycle(pwm) &&
-           period_ns == pwm_get_period(pwm)) {
-               /* No change - don't cause any transients. */
-               mutex_unlock(&omap->mutex);
+           period_ns == pwm_get_period(pwm))
                return 0;
-       }
 
        fclk = omap->pdata->get_fclk(omap->dm_timer);
        if (!fclk) {
                dev_err(chip->dev, "invalid pmtimer fclk\n");
-               goto err_einval;
+               return -EINVAL;
        }
 
        clk_rate = clk_get_rate(fclk);
        if (!clk_rate) {
                dev_err(chip->dev, "invalid pmtimer fclk rate\n");
-               goto err_einval;
+               return -EINVAL;
        }
 
        dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
@@ -148,7 +202,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
                dev_info(chip->dev,
                         "period %d ns too short for clock rate %lu Hz\n",
                         period_ns, clk_rate);
-               goto err_einval;
+               return -EINVAL;
        }
 
        if (duty_cycles < 1) {
@@ -174,81 +228,103 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        load_value = (DM_TIMER_MAX - period_cycles) + 1;
        match_value = load_value + duty_cycles - 1;
 
-       /*
-        * We MUST stop the associated dual-mode timer before attempting to
-        * write its registers, but calls to omap_dm_timer_start/stop must
-        * be balanced so check if timer is active before calling timer_stop.
-        */
-       timer_active = pm_runtime_active(&omap->dm_timer_pdev->dev);
-       if (timer_active)
-               omap->pdata->stop(omap->dm_timer);
-
        omap->pdata->set_load(omap->dm_timer, load_value);
        omap->pdata->set_match(omap->dm_timer, true, match_value);
 
        dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
                load_value, load_value, match_value, match_value);
 
-       omap->pdata->set_pwm(omap->dm_timer,
-                             pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED,
-                             true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
-                             true);
-
-       /* If config was called while timer was running it must be reenabled. */
-       if (timer_active)
-               pwm_omap_dmtimer_start(omap);
+       return 0;
+}
 
-       mutex_unlock(&omap->mutex);
+/**
+ * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer.
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @polarity:  New pwm polarity to be set
+ */
+static void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
+                                         struct pwm_device *pwm,
+                                         enum pwm_polarity polarity)
+{
+       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       bool enabled;
 
-       return 0;
+       /* Disable the PWM before changing the polarity. */
+       enabled = pwm_omap_dmtimer_is_enabled(omap);
+       if (enabled)
+               omap->pdata->stop(omap->dm_timer);
 
-err_einval:
-       mutex_unlock(&omap->mutex);
+       omap->pdata->set_pwm(omap->dm_timer,
+                            polarity == PWM_POLARITY_INVERSED,
+                            true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                            true);
 
-       return -EINVAL;
+       if (enabled)
+               pwm_omap_dmtimer_start(omap);
 }
 
-static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
-                                        struct pwm_device *pwm,
-                                        enum pwm_polarity polarity)
+/**
+ * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer.
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @state:     New state to apply
+ *
+ * Return 0 if successfully changed the state else appropriate error.
+ */
+static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
+                                 struct pwm_device *pwm,
+                                 const struct pwm_state *state)
 {
        struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       int ret = 0;
 
-       /*
-        * PWM core will not call set_polarity while PWM is enabled so it's
-        * safe to reconfigure the timer here without stopping it first.
-        */
        mutex_lock(&omap->mutex);
-       omap->pdata->set_pwm(omap->dm_timer,
-                             polarity == PWM_POLARITY_INVERSED,
-                             true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
-                             true);
+
+       if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
+               omap->pdata->stop(omap->dm_timer);
+               goto unlock_mutex;
+       }
+
+       if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
+               pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity);
+
+       ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
+                                     state->period);
+       if (ret)
+               goto unlock_mutex;
+
+       if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
+               omap->pdata->set_pwm(omap->dm_timer,
+                                    state->polarity == PWM_POLARITY_INVERSED,
+                                    true,
+                                    OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                                    true);
+               pwm_omap_dmtimer_start(omap);
+       }
+
+unlock_mutex:
        mutex_unlock(&omap->mutex);
 
-       return 0;
+       return ret;
 }
 
 static const struct pwm_ops pwm_omap_dmtimer_ops = {
-       .enable = pwm_omap_dmtimer_enable,
-       .disable = pwm_omap_dmtimer_disable,
-       .config = pwm_omap_dmtimer_config,
-       .set_polarity = pwm_omap_dmtimer_set_polarity,
+       .apply = pwm_omap_dmtimer_apply,
        .owner = THIS_MODULE,
 };
 
 static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct device_node *timer;
-       struct platform_device *timer_pdev;
-       struct pwm_omap_dmtimer_chip *omap;
        struct dmtimer_platform_data *timer_pdata;
        const struct omap_dm_timer_ops *pdata;
-       pwm_omap_dmtimer *dm_timer;
-       u32 v;
+       struct platform_device *timer_pdev;
+       struct pwm_omap_dmtimer_chip *omap;
+       struct omap_dm_timer *dm_timer;
+       struct device_node *timer;
        int ret = 0;
+       u32 v;
 
        timer = of_parse_phandle(np, "ti,timers", 0);
        if (!timer)
@@ -281,6 +357,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
            !pdata->set_load ||
            !pdata->set_match ||
            !pdata->set_pwm ||
+           !pdata->get_pwm_status ||
            !pdata->set_prescaler ||
            !pdata->write_counter) {
                dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
index b07bdca..76cd22b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/bitmap.h>
 
 /*
  * Because the PCA9685 has only one prescaler per chip, changing the period of
 struct pca9685 {
        struct pwm_chip chip;
        struct regmap *regmap;
-       int duty_ns;
        int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
        struct mutex lock;
        struct gpio_chip gpio;
+       DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
 #endif
 };
 
@@ -83,51 +84,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
-static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
-       struct pca9685 *pca = gpiochip_get_data(gpio);
-       struct pwm_device *pwm;
+       bool is_inuse;
 
        mutex_lock(&pca->lock);
-
-       pwm = &pca->chip.pwms[offset];
-
-       if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
-               mutex_unlock(&pca->lock);
-               return -EBUSY;
+       if (pwm_idx >= PCA9685_MAXCHAN) {
+               /*
+                * "all LEDs" channel:
+                * pretend already in use if any of the PWMs are requested
+                */
+               if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) {
+                       is_inuse = true;
+                       goto out;
+               }
+       } else {
+               /*
+                * regular channel:
+                * pretend already in use if the "all LEDs" channel is requested
+                */
+               if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) {
+                       is_inuse = true;
+                       goto out;
+               }
        }
-
-       pwm_set_chip_data(pwm, (void *)1);
-
+       is_inuse = test_and_set_bit(pwm_idx, pca->pwms_inuse);
+out:
        mutex_unlock(&pca->lock);
-       pm_runtime_get_sync(pca->chip.dev);
-       return 0;
+       return is_inuse;
 }
 
-static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
+static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
 {
-       bool is_gpio = false;
-
        mutex_lock(&pca->lock);
+       clear_bit(pwm_idx, pca->pwms_inuse);
+       mutex_unlock(&pca->lock);
+}
 
-       if (pwm->hwpwm >= PCA9685_MAXCHAN) {
-               unsigned int i;
-
-               /*
-                * Check if any of the GPIOs are requested and in that case
-                * prevent using the "all LEDs" channel.
-                */
-               for (i = 0; i < pca->gpio.ngpio; i++)
-                       if (gpiochip_is_requested(&pca->gpio, i)) {
-                               is_gpio = true;
-                               break;
-                       }
-       } else if (pwm_get_chip_data(pwm)) {
-               is_gpio = true;
-       }
+static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+{
+       struct pca9685 *pca = gpiochip_get_data(gpio);
 
-       mutex_unlock(&pca->lock);
-       return is_gpio;
+       if (pca9685_pwm_test_and_set_inuse(pca, offset))
+               return -EBUSY;
+       pm_runtime_get_sync(pca->chip.dev);
+       return 0;
 }
 
 static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
@@ -162,13 +163,14 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
 
        pca9685_pwm_gpio_set(gpio, offset, 0);
        pm_runtime_put(pca->chip.dev);
+       pca9685_pwm_clear_inuse(pca, offset);
 }
 
 static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
                                          unsigned int offset)
 {
        /* Always out */
-       return 0;
+       return GPIO_LINE_DIRECTION_OUT;
 }
 
 static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio,
@@ -213,12 +215,17 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
        return devm_gpiochip_add_data(dev, &pca->gpio, pca);
 }
 #else
-static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
-                                      struct pwm_device *pwm)
+static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca,
+                                                 int pwm_idx)
 {
        return false;
 }
 
+static inline void
+pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
+{
+}
+
 static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
        return 0;
@@ -272,8 +279,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                }
        }
 
-       pca->duty_ns = duty_ns;
-
        if (duty_ns < 1) {
                if (pwm->hwpwm >= PCA9685_MAXCHAN)
                        reg = PCA9685_ALL_LED_OFF_H;
@@ -402,7 +407,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct pca9685 *pca = to_pca(chip);
 
-       if (pca9685_pwm_is_gpio(pca, pwm))
+       if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
                return -EBUSY;
        pm_runtime_get_sync(chip->dev);
 
@@ -411,8 +416,11 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       struct pca9685 *pca = to_pca(chip);
+
        pca9685_pwm_disable(chip, pwm);
        pm_runtime_put(chip->dev);
+       pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
 }
 
 static const struct pwm_ops pca9685_pwm_ops = {
@@ -449,7 +457,6 @@ static int pca9685_pwm_probe(struct i2c_client *client,
                        ret);
                return ret;
        }
-       pca->duty_ns = 0;
        pca->period_ns = PCA9685_DEFAULT_PERIOD;
 
        i2c_set_clientdata(client, pca);
@@ -512,8 +519,7 @@ static int pca9685_pwm_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int pca9685_pwm_runtime_suspend(struct device *dev)
+static int __maybe_unused pca9685_pwm_runtime_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct pca9685 *pca = i2c_get_clientdata(client);
@@ -522,7 +528,7 @@ static int pca9685_pwm_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int pca9685_pwm_runtime_resume(struct device *dev)
+static int __maybe_unused pca9685_pwm_runtime_resume(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct pca9685 *pca = i2c_get_clientdata(client);
@@ -530,7 +536,6 @@ static int pca9685_pwm_runtime_resume(struct device *dev)
        pca9685_set_sleep_mode(pca, false);
        return 0;
 }
-#endif
 
 static const struct i2c_device_id pca9685_id[] = {
        { "pca9685", 0 },
index 2685577..7ab9eb6 100644 (file)
@@ -229,24 +229,28 @@ static int rcar_pwm_probe(struct platform_device *pdev)
        rcar_pwm->chip.base = -1;
        rcar_pwm->chip.npwm = 1;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = pwmchip_add(&rcar_pwm->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
+               pm_runtime_disable(&pdev->dev);
                return ret;
        }
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 }
 
 static int rcar_pwm_remove(struct platform_device *pdev)
 {
        struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = pwmchip_remove(&rcar_pwm->chip);
 
        pm_runtime_disable(&pdev->dev);
 
-       return pwmchip_remove(&rcar_pwm->chip);
+       return ret;
 }
 
 static const struct of_device_id rcar_pwm_of_table[] = {
index 4a855a2..81ad5a5 100644 (file)
@@ -415,16 +415,15 @@ static int tpu_probe(struct platform_device *pdev)
        tpu->chip.base = -1;
        tpu->chip.npwm = TPU_CHANNEL_MAX;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = pwmchip_add(&tpu->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register PWM chip\n");
+               pm_runtime_disable(&pdev->dev);
                return ret;
        }
 
-       dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);
-
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 }
 
@@ -434,12 +433,10 @@ static int tpu_remove(struct platform_device *pdev)
        int ret;
 
        ret = pwmchip_remove(&tpu->chip);
-       if (ret)
-               return ret;
 
        pm_runtime_disable(&pdev->dev);
 
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_OF
index 3e3efa6..5c677c5 100644 (file)
@@ -90,7 +90,6 @@ struct sun4i_pwm_chip {
        spinlock_t ctrl_lock;
        const struct sun4i_pwm_data *data;
        unsigned long next_period[2];
-       bool needs_delay[2];
 };
 
 static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
@@ -287,7 +286,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
        sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
                usecs_to_jiffies(cstate.period / 1000 + 1);
-       sun4i_pwm->needs_delay[pwm->hwpwm] = true;
 
        if (state->polarity != PWM_POLARITY_NORMAL)
                ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
@@ -298,7 +296,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        if (state->enabled) {
                ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
-       } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
+       } else {
                ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm);
                ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
        }
@@ -310,15 +308,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        if (state->enabled)
                return 0;
 
-       if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
-               clk_disable_unprepare(sun4i_pwm->clk);
-               return 0;
-       }
-
        /* We need a full period to elapse before disabling the channel. */
        now = jiffies;
-       if (sun4i_pwm->needs_delay[pwm->hwpwm] &&
-           time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) {
+       if (time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) {
                delay_us = jiffies_to_usecs(sun4i_pwm->next_period[pwm->hwpwm] -
                                           now);
                if ((delay_us / 500) > MAX_UDELAY_MS)
@@ -326,7 +318,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                else
                        usleep_range(delay_us, delay_us * 2);
        }
-       sun4i_pwm->needs_delay[pwm->hwpwm] = false;
 
        spin_lock(&sun4i_pwm->ctrl_lock);
        ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
index aa12fb3..d26ed8f 100644 (file)
@@ -282,9 +282,15 @@ static const struct tegra_pwm_soc tegra186_pwm_soc = {
        .max_frequency = 102000000UL,
 };
 
+static const struct tegra_pwm_soc tegra194_pwm_soc = {
+       .num_channels = 1,
+       .max_frequency = 408000000UL,
+};
+
 static const struct of_device_id tegra_pwm_of_match[] = {
        { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc },
        { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
+       { .compatible = "nvidia,tegra194-pwm", .data = &tegra194_pwm_soc },
        { }
 };
 MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
index 50007cb..b29fe8d 100644 (file)
@@ -849,8 +849,10 @@ static void io_subchannel_register(struct ccw_device *cdev)
         * Now we know this subchannel will stay, we can throw
         * our delayed uevent.
         */
-       dev_set_uevent_suppress(&sch->dev, 0);
-       kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       if (dev_get_uevent_suppress(&sch->dev)) {
+               dev_set_uevent_suppress(&sch->dev, 0);
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       }
        /* make it known to the system */
        ret = ccw_device_add(cdev);
        if (ret) {
@@ -1058,8 +1060,11 @@ static int io_subchannel_probe(struct subchannel *sch)
                 * Throw the delayed uevent for the subchannel, register
                 * the ccw_device and exit.
                 */
-               dev_set_uevent_suppress(&sch->dev, 0);
-               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+               if (dev_get_uevent_suppress(&sch->dev)) {
+                       /* should always be the case for the console */
+                       dev_set_uevent_suppress(&sch->dev, 0);
+                       kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+               }
                cdev = sch_get_cdev(sch);
                rc = ccw_device_add(cdev);
                if (rc) {
index b0beafc..b8453b5 100644 (file)
@@ -374,7 +374,6 @@ int tiqdio_allocate_memory(void);
 void tiqdio_free_memory(void);
 int tiqdio_register_thinints(void);
 void tiqdio_unregister_thinints(void);
-void clear_nonshared_ind(struct qdio_irq *);
 int test_nonshared_ind(struct qdio_irq *);
 
 /* prototypes for setup */
index 5a3d9ee..286b044 100644 (file)
@@ -58,25 +58,11 @@ static void qdio_clear_dbf_list(void)
        mutex_unlock(&qdio_dbf_list_mutex);
 }
 
-int qdio_allocate_dbf(struct qdio_initialize *init_data,
-                      struct qdio_irq *irq_ptr)
+int qdio_allocate_dbf(struct qdio_irq *irq_ptr)
 {
        char text[QDIO_DBF_NAME_LEN];
        struct qdio_dbf_entry *new_entry;
 
-       DBF_EVENT("qfmt:%1d", init_data->q_format);
-       DBF_HEX(init_data->adapter_name, 8);
-       DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
-       DBF_HEX(&init_data->qib_param_field, sizeof(void *));
-       DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
-       DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
-       DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
-                 init_data->no_output_qs);
-       DBF_HEX(&init_data->input_handler, sizeof(void *));
-       DBF_HEX(&init_data->output_handler, sizeof(void *));
-       DBF_HEX(&init_data->int_parm, sizeof(long));
-       DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
-       DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
        DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
 
        /* allocate trace view for the interface */
index 122450b..0dfba08 100644 (file)
@@ -64,8 +64,7 @@ static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr,
        debug_event(dev->debug_area, level, addr, len);
 }
 
-int qdio_allocate_dbf(struct qdio_initialize *init_data,
-                      struct qdio_irq *irq_ptr);
+int qdio_allocate_dbf(struct qdio_irq *irq_ptr);
 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr);
 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr);
 int qdio_debug_init(void);
index c890848..bcc3ab1 100644 (file)
@@ -1220,27 +1220,21 @@ EXPORT_SYMBOL_GPL(qdio_free);
 
 /**
  * qdio_allocate - allocate qdio queues and associated data
- * @init_data: initialization data
+ * @cdev: associated ccw device
+ * @no_input_qs: allocate this number of Input Queues
+ * @no_output_qs: allocate this number of Output Queues
  */
-int qdio_allocate(struct qdio_initialize *init_data)
+int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
+                 unsigned int no_output_qs)
 {
-       struct ccw_device *cdev = init_data->cdev;
        struct subchannel_id schid;
        struct qdio_irq *irq_ptr;
 
        ccw_device_get_schid(cdev, &schid);
        DBF_EVENT("qallocate:%4x", schid.sch_no);
 
-       if ((init_data->no_input_qs && !init_data->input_handler) ||
-           (init_data->no_output_qs && !init_data->output_handler))
-               return -EINVAL;
-
-       if ((init_data->no_input_qs > QDIO_MAX_QUEUES_PER_IRQ) ||
-           (init_data->no_output_qs > QDIO_MAX_QUEUES_PER_IRQ))
-               return -EINVAL;
-
-       if ((!init_data->input_sbal_addr_array) ||
-           (!init_data->output_sbal_addr_array))
+       if (no_input_qs > QDIO_MAX_QUEUES_PER_IRQ ||
+           no_output_qs > QDIO_MAX_QUEUES_PER_IRQ)
                return -EINVAL;
 
        /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */
@@ -1250,9 +1244,12 @@ int qdio_allocate(struct qdio_initialize *init_data)
 
        irq_ptr->cdev = cdev;
        mutex_init(&irq_ptr->setup_mutex);
-       if (qdio_allocate_dbf(init_data, irq_ptr))
+       if (qdio_allocate_dbf(irq_ptr))
                goto out_rel;
 
+       DBF_DEV_EVENT(DBF_ERR, irq_ptr, "alloc niq:%1u noq:%1u", no_input_qs,
+                     no_output_qs);
+
        /*
         * Allocate a page for the chsc calls in qdio_establish.
         * Must be pre-allocated since a zfcp recovery will call
@@ -1268,8 +1265,7 @@ int qdio_allocate(struct qdio_initialize *init_data)
        if (!irq_ptr->qdr)
                goto out_rel;
 
-       if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs,
-                            init_data->no_output_qs))
+       if (qdio_allocate_qs(irq_ptr, no_input_qs, no_output_qs))
                goto out_rel;
 
        INIT_LIST_HEAD(&irq_ptr->entry);
@@ -1305,13 +1301,33 @@ static void qdio_detect_hsicq(struct qdio_irq *irq_ptr)
        DBF_EVENT("use_cq:%d", use_cq);
 }
 
+static void qdio_trace_init_data(struct qdio_irq *irq,
+                                struct qdio_initialize *data)
+{
+       DBF_DEV_EVENT(DBF_ERR, irq, "qfmt:%1u", data->q_format);
+       DBF_DEV_HEX(irq, data->adapter_name, 8, DBF_ERR);
+       DBF_DEV_EVENT(DBF_ERR, irq, "qpff%4x", data->qib_param_field_format);
+       DBF_DEV_HEX(irq, &data->qib_param_field, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->input_slib_elements, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_slib_elements, sizeof(void *), DBF_ERR);
+       DBF_DEV_EVENT(DBF_ERR, irq, "niq:%1u noq:%1u", data->no_input_qs,
+                     data->no_output_qs);
+       DBF_DEV_HEX(irq, &data->input_handler, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_handler, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->int_parm, sizeof(long), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->input_sbal_addr_array, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_sbal_addr_array, sizeof(void *),
+                   DBF_ERR);
+}
+
 /**
  * qdio_establish - establish queues on a qdio subchannel
+ * @cdev: associated ccw device
  * @init_data: initialization data
  */
-int qdio_establish(struct qdio_initialize *init_data)
+int qdio_establish(struct ccw_device *cdev,
+                  struct qdio_initialize *init_data)
 {
-       struct ccw_device *cdev = init_data->cdev;
        struct qdio_irq *irq_ptr = cdev->private->qdio_data;
        struct subchannel_id schid;
        int rc;
@@ -1322,7 +1338,16 @@ int qdio_establish(struct qdio_initialize *init_data)
        if (!irq_ptr)
                return -ENODEV;
 
+       if ((init_data->no_input_qs && !init_data->input_handler) ||
+           (init_data->no_output_qs && !init_data->output_handler))
+               return -EINVAL;
+
+       if (!init_data->input_sbal_addr_array ||
+           !init_data->output_sbal_addr_array)
+               return -EINVAL;
+
        mutex_lock(&irq_ptr->setup_mutex);
+       qdio_trace_init_data(irq_ptr, init_data);
        qdio_setup_irq(irq_ptr, init_data);
 
        rc = qdio_establish_thinint(irq_ptr);
@@ -1618,8 +1643,6 @@ int qdio_start_irq(struct ccw_device *cdev)
        if (!irq_ptr)
                return -ENODEV;
 
-       clear_nonshared_ind(irq_ptr);
-
        for_each_input_queue(irq_ptr, q, i)
                qdio_stop_polling(q);
 
index bbbefc9..3083edd 100644 (file)
@@ -213,8 +213,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,
                         struct qdio_initialize *qdio_init)
 {
        struct qdio_q *q;
-       struct qdio_buffer **input_sbal_array = qdio_init->input_sbal_addr_array;
-       struct qdio_buffer **output_sbal_array = qdio_init->output_sbal_addr_array;
        struct qdio_outbuf_state *output_sbal_state_array =
                                  qdio_init->output_sbal_state_array;
        int i;
@@ -225,8 +223,8 @@ static void setup_queues(struct qdio_irq *irq_ptr,
 
                q->is_input_q = 1;
 
-               setup_storage_lists(q, irq_ptr, input_sbal_array, i);
-               input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
+               setup_storage_lists(q, irq_ptr,
+                                   qdio_init->input_sbal_addr_array[i], i);
 
                if (is_thinint_irq(irq_ptr)) {
                        tasklet_init(&q->tasklet, tiqdio_inbound_processing,
@@ -245,8 +243,8 @@ static void setup_queues(struct qdio_irq *irq_ptr,
                output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
 
                q->is_input_q = 0;
-               setup_storage_lists(q, irq_ptr, output_sbal_array, i);
-               output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
+               setup_storage_lists(q, irq_ptr,
+                                   qdio_init->output_sbal_addr_array[i], i);
 
                tasklet_init(&q->tasklet, qdio_outbound_processing,
                             (unsigned long) q);
index ea09df7..ae50373 100644 (file)
@@ -82,36 +82,16 @@ void tiqdio_remove_device(struct qdio_irq *irq_ptr)
        INIT_LIST_HEAD(&irq_ptr->entry);
 }
 
-static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr)
-{
-       return irq_ptr->nr_input_qs > 1;
-}
-
 static inline int references_shared_dsci(struct qdio_irq *irq_ptr)
 {
        return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
 }
 
-static inline int shared_ind(struct qdio_irq *irq_ptr)
-{
-       return references_shared_dsci(irq_ptr) ||
-               has_multiple_inq_on_dsci(irq_ptr);
-}
-
-void clear_nonshared_ind(struct qdio_irq *irq_ptr)
-{
-       if (!is_thinint_irq(irq_ptr))
-               return;
-       if (shared_ind(irq_ptr))
-               return;
-       xchg(irq_ptr->dsci, 0);
-}
-
 int test_nonshared_ind(struct qdio_irq *irq_ptr)
 {
        if (!is_thinint_irq(irq_ptr))
                return 0;
-       if (shared_ind(irq_ptr))
+       if (references_shared_dsci(irq_ptr))
                return 0;
        if (*irq_ptr->dsci)
                return 1;
@@ -131,8 +111,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
        struct qdio_q *q;
        int i;
 
-       if (!references_shared_dsci(irq) &&
-           has_multiple_inq_on_dsci(irq))
+       if (!references_shared_dsci(irq))
                xchg(irq->dsci, 0);
 
        if (irq->irq_poll) {
@@ -145,9 +124,6 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
        }
 
        for_each_input_queue(irq, q, i) {
-               if (!shared_ind(irq))
-                       xchg(irq->dsci, 0);
-
                /*
                 * Call inbound processing but not directly
                 * since that could starve other thinint queues.
index e401a3d..339a6bc 100644 (file)
@@ -167,6 +167,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
        if (ret)
                goto out_disable;
 
+       if (dev_get_uevent_suppress(&sch->dev)) {
+               dev_set_uevent_suppress(&sch->dev, 0);
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       }
+
        VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n",
                           sch->schid.cssid, sch->schid.ssid,
                           sch->schid.sch_no);
index acda230..e0b2631 100644 (file)
@@ -181,11 +181,12 @@ struct qeth_vnicc_info {
 /*****************************************************************************/
 /* QDIO queue and buffer handling                                            */
 /*****************************************************************************/
-#define QETH_MAX_QUEUES 4
+#define QETH_MAX_OUT_QUEUES    4
 #define QETH_IQD_MIN_TXQ       2       /* One for ucast, one for mcast. */
 #define QETH_IQD_MCAST_TXQ     0
 #define QETH_IQD_MIN_UCAST_TXQ 1
 
+#define QETH_MAX_IN_QUEUES     2
 #define QETH_RX_COPYBREAK      (PAGE_SIZE >> 1)
 #define QETH_IN_BUF_SIZE_DEFAULT 65536
 #define QETH_IN_BUF_COUNT_DEFAULT 64
@@ -539,7 +540,7 @@ struct qeth_qdio_info {
 
        /* output */
        int no_out_queues;
-       struct qeth_qdio_out_q *out_qs[QETH_MAX_QUEUES];
+       struct qeth_qdio_out_q *out_qs[QETH_MAX_OUT_QUEUES];
        struct qdio_outbuf_state *out_bufstates;
 
        /* priority queueing */
index 24fd17b..f768946 100644 (file)
@@ -4812,28 +4812,13 @@ out:
        return;
 }
 
-static void qeth_qdio_establish_cq(struct qeth_card *card,
-                                  struct qdio_buffer **in_sbal_ptrs)
-{
-       int i;
-
-       if (card->options.cq == QETH_CQ_ENABLED) {
-               int offset = QDIO_MAX_BUFFERS_PER_Q *
-                            (card->qdio.no_in_queues - 1);
-
-               for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)
-                       in_sbal_ptrs[offset + i] =
-                               card->qdio.c_q->bufs[i].buffer;
-       }
-}
-
 static int qeth_qdio_establish(struct qeth_card *card)
 {
+       struct qdio_buffer **out_sbal_ptrs[QETH_MAX_OUT_QUEUES];
+       struct qdio_buffer **in_sbal_ptrs[QETH_MAX_IN_QUEUES];
        struct qdio_initialize init_data;
        char *qib_param_field;
-       struct qdio_buffer **in_sbal_ptrs;
-       struct qdio_buffer **out_sbal_ptrs;
-       int i, j, k;
+       unsigned int i;
        int rc = 0;
 
        QETH_CARD_TEXT(card, 2, "qdioest");
@@ -4847,35 +4832,14 @@ static int qeth_qdio_establish(struct qeth_card *card)
        qeth_create_qib_param_field(card, qib_param_field);
        qeth_create_qib_param_field_blkt(card, qib_param_field);
 
-       in_sbal_ptrs = kcalloc(card->qdio.no_in_queues * QDIO_MAX_BUFFERS_PER_Q,
-                              sizeof(void *),
-                              GFP_KERNEL);
-       if (!in_sbal_ptrs) {
-               rc = -ENOMEM;
-               goto out_free_qib_param;
-       }
-
-       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)
-               in_sbal_ptrs[i] = card->qdio.in_q->bufs[i].buffer;
-
-       qeth_qdio_establish_cq(card, in_sbal_ptrs);
-
-       out_sbal_ptrs =
-               kcalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q,
-                       sizeof(void *),
-                       GFP_KERNEL);
-       if (!out_sbal_ptrs) {
-               rc = -ENOMEM;
-               goto out_free_in_sbals;
-       }
+       in_sbal_ptrs[0] = card->qdio.in_q->qdio_bufs;
+       if (card->options.cq == QETH_CQ_ENABLED)
+               in_sbal_ptrs[1] = card->qdio.c_q->qdio_bufs;
 
-       for (i = 0, k = 0; i < card->qdio.no_out_queues; ++i)
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++, k++)
-                       out_sbal_ptrs[k] =
-                               card->qdio.out_qs[i]->bufs[j]->buffer;
+       for (i = 0; i < card->qdio.no_out_queues; i++)
+               out_sbal_ptrs[i] = card->qdio.out_qs[i]->qdio_bufs;
 
        memset(&init_data, 0, sizeof(struct qdio_initialize));
-       init_data.cdev                   = CARD_DDEV(card);
        init_data.q_format               = IS_IQD(card) ? QDIO_IQDIO_QFMT :
                                                          QDIO_QETH_QFMT;
        init_data.qib_param_field_format = 0;
@@ -4893,12 +4857,13 @@ static int qeth_qdio_establish(struct qeth_card *card)
 
        if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
                QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
-               rc = qdio_allocate(&init_data);
+               rc = qdio_allocate(CARD_DDEV(card), init_data.no_input_qs,
+                                  init_data.no_output_qs);
                if (rc) {
                        atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                        goto out;
                }
-               rc = qdio_establish(&init_data);
+               rc = qdio_establish(CARD_DDEV(card), &init_data);
                if (rc) {
                        atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                        qdio_free(CARD_DDEV(card));
@@ -4916,10 +4881,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
                break;
        }
 out:
-       kfree(out_sbal_ptrs);
-out_free_in_sbals:
-       kfree(in_sbal_ptrs);
-out_free_qib_param:
        kfree(qib_param_field);
 out_free_nothing:
        return rc;
@@ -5985,7 +5946,7 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card)
        switch (card->info.type) {
        case QETH_CARD_TYPE_IQD:
                dev = alloc_netdev_mqs(sizeof(*priv), "hsi%d", NET_NAME_UNKNOWN,
-                                      ether_setup, QETH_MAX_QUEUES, 1);
+                                      ether_setup, QETH_MAX_OUT_QUEUES, 1);
                break;
        case QETH_CARD_TYPE_OSM:
                dev = alloc_etherdev(sizeof(*priv));
@@ -5995,7 +5956,7 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card)
                                   ether_setup);
                break;
        default:
-               dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_QUEUES, 1);
+               dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_OUT_QUEUES, 1);
        }
 
        if (!dev)
index 18a6751..3d0bc00 100644 (file)
@@ -178,12 +178,12 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return 0;
                if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
                        need = ZFCP_ERP_ACTION_REOPEN_PORT;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
                p_status = atomic_read(&port->status);
                if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
                        need = ZFCP_ERP_ACTION_REOPEN_PORT;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT:
                p_status = atomic_read(&port->status);
                if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
@@ -196,7 +196,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return need;
                if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
                        need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
                a_status = atomic_read(&adapter->status);
                if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
@@ -1086,7 +1086,7 @@ static enum zfcp_erp_act_result zfcp_erp_lun_strategy(
                if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
                        return zfcp_erp_lun_strategy_close(erp_action);
                /* already closed */
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_STEP_LUN_CLOSING:
                if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
                        return ZFCP_ERP_FAILED;
@@ -1415,7 +1415,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act,
                if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
                        if (result == ZFCP_ERP_SUCCEEDED)
                                zfcp_erp_try_rport_unblock(port);
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
                put_device(&port->dev);
                break;
index 7c603e5..111fe3f 100644 (file)
@@ -564,7 +564,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
        case FSF_TOPO_AL:
                fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
                fc_host_fabric_name(shost) = 0;
-               /* fall through */
+               fallthrough;
        default:
                fc_host_fabric_name(shost) = 0;
                dev_err(&adapter->ccw_device->dev,
@@ -1032,7 +1032,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
                switch (fsq->word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -1127,7 +1127,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_PORT_HANDLE_NOT_VALID:
                zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");
-               /* fall through */
+               fallthrough;
        case FSF_GENERIC_COMMAND_REJECTED:
        case FSF_PAYLOAD_SIZE_MISMATCH:
        case FSF_REQUEST_SIZE_TOO_LARGE:
@@ -1313,7 +1313,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_SBAL_MISMATCH:
                /* should never occur, avoided in zfcp_fsf_send_els */
-               /* fall through */
+               fallthrough;
        default:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
@@ -1736,7 +1736,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        /* no zfcp_fc_test_link() with failed open port */
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                case FSF_SQ_NO_RETRY_POSSIBLE:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1909,14 +1909,14 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
        case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
                dev_warn(&req->adapter->ccw_device->dev,
                         "Opening WKA port 0x%x failed\n", wka_port->d_id);
-               /* fall through */
+               fallthrough;
        case FSF_ADAPTER_STATUS_AVAILABLE:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
                break;
        case FSF_GOOD:
                wka_port->handle = header->port_handle;
-               /* fall through */
+               fallthrough;
        case FSF_PORT_ALREADY_OPEN:
                wka_port->status = ZFCP_FC_WKA_PORT_ONLINE;
        }
@@ -2059,7 +2059,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
        case FSF_ADAPTER_STATUS_AVAILABLE:
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
-                       /* fall through */
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -2144,7 +2143,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
 
        case FSF_PORT_HANDLE_NOT_VALID:
                zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");
-               /* fall through */
+               fallthrough;
        case FSF_LUN_ALREADY_OPEN:
                break;
        case FSF_PORT_BOXED:
@@ -2175,7 +2174,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
                         (unsigned long long)zfcp_scsi_dev_lun(sdev),
                         (unsigned long long)zfcp_sdev->port->wwpn);
                zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
-               /* fall through */
+               fallthrough;
        case FSF_INVALID_COMMAND_OPTION:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
@@ -2183,7 +2182,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -2277,7 +2276,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
                switch (req->qtcb->header.fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
index f0d6296..26702b5 100644 (file)
@@ -277,29 +277,6 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
        return 0;
 }
 
-
-static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
-                                     struct zfcp_qdio *qdio)
-{
-       memset(id, 0, sizeof(*id));
-       id->cdev = qdio->adapter->ccw_device;
-       id->q_format = QDIO_ZFCP_QFMT;
-       memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
-       ASCEBC(id->adapter_name, 8);
-       id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
-       if (enable_multibuffer)
-               id->qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
-       id->no_input_qs = 1;
-       id->no_output_qs = 1;
-       id->input_handler = zfcp_qdio_int_resp;
-       id->output_handler = zfcp_qdio_int_req;
-       id->int_parm = (unsigned long) qdio;
-       id->input_sbal_addr_array = qdio->res_q;
-       id->output_sbal_addr_array = qdio->req_q;
-       id->scan_threshold =
-               QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
-}
-
 /**
  * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
  * @qdio: pointer to struct zfcp_qdio
@@ -308,7 +285,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
  */
 static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
 {
-       struct qdio_initialize init_data;
        int ret;
 
        ret = qdio_alloc_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q);
@@ -319,10 +295,9 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
        if (ret)
                goto free_req_q;
 
-       zfcp_qdio_setup_init_data(&init_data, qdio);
        init_waitqueue_head(&qdio->req_q_wq);
 
-       ret = qdio_allocate(&init_data);
+       ret = qdio_allocate(qdio->adapter->ccw_device, 1, 1);
        if (ret)
                goto free_res_q;
 
@@ -374,8 +349,10 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio)
  */
 int zfcp_qdio_open(struct zfcp_qdio *qdio)
 {
+       struct qdio_buffer **input_sbals[1] = {qdio->res_q};
+       struct qdio_buffer **output_sbals[1] = {qdio->req_q};
        struct qdio_buffer_element *sbale;
-       struct qdio_initialize init_data;
+       struct qdio_initialize init_data = {0};
        struct zfcp_adapter *adapter = qdio->adapter;
        struct ccw_device *cdev = adapter->ccw_device;
        struct qdio_ssqd_desc ssqd;
@@ -387,12 +364,26 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
        atomic_andnot(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
                          &qdio->adapter->status);
 
-       zfcp_qdio_setup_init_data(&init_data, qdio);
+       init_data.q_format = QDIO_ZFCP_QFMT;
+       memcpy(init_data.adapter_name, dev_name(&cdev->dev), 8);
+       ASCEBC(init_data.adapter_name, 8);
+       init_data.qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
+       if (enable_multibuffer)
+               init_data.qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
+       init_data.no_input_qs = 1;
+       init_data.no_output_qs = 1;
+       init_data.input_handler = zfcp_qdio_int_resp;
+       init_data.output_handler = zfcp_qdio_int_req;
+       init_data.int_parm = (unsigned long) qdio;
+       init_data.input_sbal_addr_array = input_sbals;
+       init_data.output_sbal_addr_array = output_sbals;
+       init_data.scan_threshold =
+               QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
 
-       if (qdio_establish(&init_data))
+       if (qdio_establish(cdev, &init_data))
                goto failed_establish;
 
-       if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+       if (qdio_get_ssqd_desc(cdev, &ssqd))
                goto failed_qdio;
 
        if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
index 4725e4c..ddd73f6 100644 (file)
@@ -1626,7 +1626,7 @@ out:
 int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
 {
        unsigned long flagv = 0;
-       int retval;
+       int retval, unblock_retval;
        struct Scsi_Host *host = aac->scsi_host_ptr;
        int bled;
 
@@ -1656,8 +1656,9 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
        retval = _aac_reset_adapter(aac, bled, reset_type);
        spin_unlock_irqrestore(host->host_lock, flagv);
 
-       retval = scsi_host_unblock(host, SDEV_RUNNING);
-
+       unblock_retval = scsi_host_unblock(host, SDEV_RUNNING);
+       if (!retval)
+               retval = unblock_retval;
        if ((forced < 2) && (retval == -ENODEV)) {
                /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
                struct fib * fibctx = aac_fib_alloc(aac);
index 4190a02..84fc499 100644 (file)
@@ -1834,21 +1834,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
                                printerror = 0;
                        } else if (ahc_sent_msg(ahc, AHCMSG_1B,
                                                MSG_BUS_DEV_RESET, TRUE)) {
-#ifdef __FreeBSD__
-                               /*
-                                * Don't mark the user's request for this BDR
-                                * as completing with CAM_BDR_SENT.  CAM3
-                                * specifies CAM_REQ_CMP.
-                                */
-                               if (scb != NULL
-                                && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV
-                                && ahc_match_scb(ahc, scb, target, channel,
-                                                 CAM_LUN_WILDCARD,
-                                                 SCB_LIST_NULL,
-                                                 ROLE_INITIATOR)) {
-                                       ahc_set_transaction_status(scb, CAM_REQ_CMP);
-                               }
-#endif
                                ahc_compile_devinfo(&devinfo,
                                                    initiator_role_id,
                                                    target,
@@ -4399,22 +4384,16 @@ ahc_alloc(void *platform_arg, char *name)
        struct  ahc_softc *ahc;
        int     i;
 
-#ifndef        __FreeBSD__
        ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC);
        if (!ahc) {
                printk("aic7xxx: cannot malloc softc!\n");
                kfree(name);
                return NULL;
        }
-#else
-       ahc = device_get_softc((device_t)platform_arg);
-#endif
        memset(ahc, 0, sizeof(*ahc));
        ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
        if (ahc->seep_config == NULL) {
-#ifndef        __FreeBSD__
                kfree(ahc);
-#endif
                kfree(name);
                return (NULL);
        }
@@ -4540,9 +4519,7 @@ ahc_free(struct ahc_softc *ahc)
                kfree(ahc->name);
        if (ahc->seep_config != NULL)
                kfree(ahc->seep_config);
-#ifndef __FreeBSD__
        kfree(ahc);
-#endif
        return;
 }
 
index 3b84db8..b6e8ed7 100644 (file)
@@ -66,7 +66,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME            "bnx2fc"
-#define BNX2FC_VERSION         "2.12.10"
+#define BNX2FC_VERSION         "2.12.13"
 
 #define PFX                    "bnx2fc: "
 
@@ -482,7 +482,10 @@ struct io_bdt {
 struct bnx2fc_work {
        struct list_head list;
        struct bnx2fc_rport *tgt;
+       struct fcoe_task_ctx_entry *task;
+       unsigned char rq_data[BNX2FC_RQ_BUF_SZ];
        u16 wqe;
+       u8 num_rq;
 };
 struct bnx2fc_unsol_els {
        struct fc_lport *lport;
@@ -550,7 +553,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                                enum fc_rport_event event);
 void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                                   struct fcoe_task_ctx_entry *task,
-                                  u8 num_rq);
+                                  u8 num_rq, unsigned char *rq_data);
 void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
                               struct fcoe_task_ctx_entry *task,
                               u8 num_rq);
@@ -559,7 +562,7 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
                               u8 num_rq);
 void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                             struct fcoe_task_ctx_entry *task,
-                            u8 num_rq);
+                            u8 num_rq, unsigned char *rq_data);
 void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
                              struct fcoe_task_ctx_entry *task,
                              u8 num_rq);
@@ -577,7 +580,9 @@ struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
                                      void *arg, u32 timeout);
 void bnx2fc_arm_cq(struct bnx2fc_rport *tgt);
 int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt);
-void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe);
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe,
+                            unsigned char *rq_data, u8 num_rq,
+                            struct fcoe_task_ctx_entry *task);
 struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                             u32 port_id);
 void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
index b4bfab5..1cbb431 100644 (file)
@@ -660,7 +660,10 @@ static int bnx2fc_percpu_io_thread(void *arg)
 
                        list_for_each_entry_safe(work, tmp, &work_list, list) {
                                list_del_init(&work->list);
-                               bnx2fc_process_cq_compl(work->tgt, work->wqe);
+                               bnx2fc_process_cq_compl(work->tgt, work->wqe,
+                                                       work->rq_data,
+                                                       work->num_rq,
+                                                       work->task);
                                kfree(work);
                        }
 
@@ -2655,7 +2658,8 @@ static int bnx2fc_cpu_offline(unsigned int cpu)
        /* Free all work in the list */
        list_for_each_entry_safe(work, tmp, &p->work_list, list) {
                list_del_init(&work->list);
-               bnx2fc_process_cq_compl(work->tgt, work->wqe);
+               bnx2fc_process_cq_compl(work->tgt, work->wqe, work->rq_data,
+                                       work->num_rq, work->task);
                kfree(work);
        }
 
index 6f8335d..1f7c58b 100644 (file)
@@ -863,36 +863,22 @@ ret_warn_rqe:
        }
 }
 
-void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe,
+                            unsigned char *rq_data, u8 num_rq,
+                            struct fcoe_task_ctx_entry *task)
 {
-       struct fcoe_task_ctx_entry *task;
-       struct fcoe_task_ctx_entry *task_page;
        struct fcoe_port *port = tgt->port;
        struct bnx2fc_interface *interface = port->priv;
        struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_cmd *io_req;
-       int task_idx, index;
+
        u16 xid;
        u8  cmd_type;
        u8 rx_state = 0;
-       u8 num_rq;
 
        spin_lock_bh(&tgt->tgt_lock);
-       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
-       if (xid >= hba->max_tasks) {
-               printk(KERN_ERR PFX "ERROR:xid out of range\n");
-               spin_unlock_bh(&tgt->tgt_lock);
-               return;
-       }
-       task_idx = xid / BNX2FC_TASKS_PER_PAGE;
-       index = xid % BNX2FC_TASKS_PER_PAGE;
-       task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
-       task = &(task_page[index]);
-
-       num_rq = ((task->rxwr_txrd.var_ctx.rx_flags &
-                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >>
-                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT);
 
+       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
        io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
 
        if (io_req == NULL) {
@@ -912,7 +898,8 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        switch (cmd_type) {
        case BNX2FC_SCSI_CMD:
                if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) {
-                       bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq);
+                       bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq,
+                                                     rq_data);
                        spin_unlock_bh(&tgt->tgt_lock);
                        return;
                }
@@ -929,7 +916,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
 
        case BNX2FC_TASK_MGMT_CMD:
                BNX2FC_IO_DBG(io_req, "Processing TM complete\n");
-               bnx2fc_process_tm_compl(io_req, task, num_rq);
+               bnx2fc_process_tm_compl(io_req, task, num_rq, rq_data);
                break;
 
        case BNX2FC_ABTS:
@@ -987,7 +974,9 @@ void bnx2fc_arm_cq(struct bnx2fc_rport *tgt)
 
 }
 
-static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
+static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe,
+                                            unsigned char *rq_data, u8 num_rq,
+                                            struct fcoe_task_ctx_entry *task)
 {
        struct bnx2fc_work *work;
        work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC);
@@ -997,29 +986,87 @@ static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
        INIT_LIST_HEAD(&work->list);
        work->tgt = tgt;
        work->wqe = wqe;
+       work->num_rq = num_rq;
+       work->task = task;
+       if (rq_data)
+               memcpy(work->rq_data, rq_data, BNX2FC_RQ_BUF_SZ);
+
        return work;
 }
 
 /* Pending work request completion */
-static void bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe)
+static bool bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe)
 {
        unsigned int cpu = wqe % num_possible_cpus();
        struct bnx2fc_percpu_s *fps;
        struct bnx2fc_work *work;
+       struct fcoe_task_ctx_entry *task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct fcoe_port *port = tgt->port;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
+       unsigned char *rq_data = NULL;
+       unsigned char rq_data_buff[BNX2FC_RQ_BUF_SZ];
+       int task_idx, index;
+       unsigned char *dummy;
+       u16 xid;
+       u8 num_rq;
+       int i;
+
+       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
+       if (xid >= hba->max_tasks) {
+               pr_err(PFX "ERROR:xid out of range\n");
+               return false;
+       }
+
+       task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+       index = xid % BNX2FC_TASKS_PER_PAGE;
+       task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
+       task = &task_page[index];
+
+       num_rq = ((task->rxwr_txrd.var_ctx.rx_flags &
+                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >>
+                 FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT);
+
+       memset(rq_data_buff, 0, BNX2FC_RQ_BUF_SZ);
+
+       if (!num_rq)
+               goto num_rq_zero;
+
+       rq_data = bnx2fc_get_next_rqe(tgt, 1);
+
+       if (num_rq > 1) {
+               /* We do not need extra sense data */
+               for (i = 1; i < num_rq; i++)
+                       dummy = bnx2fc_get_next_rqe(tgt, 1);
+       }
+
+       if (rq_data)
+               memcpy(rq_data_buff, rq_data, BNX2FC_RQ_BUF_SZ);
+
+       /* return RQ entries */
+       for (i = 0; i < num_rq; i++)
+               bnx2fc_return_rqe(tgt, 1);
+
+num_rq_zero:
 
        fps = &per_cpu(bnx2fc_percpu, cpu);
        spin_lock_bh(&fps->fp_work_lock);
        if (fps->iothread) {
-               work = bnx2fc_alloc_work(tgt, wqe);
+               work = bnx2fc_alloc_work(tgt, wqe, rq_data_buff,
+                                        num_rq, task);
                if (work) {
                        list_add_tail(&work->list, &fps->work_list);
                        wake_up_process(fps->iothread);
                        spin_unlock_bh(&fps->fp_work_lock);
-                       return;
+                       return true;
                }
        }
        spin_unlock_bh(&fps->fp_work_lock);
-       bnx2fc_process_cq_compl(tgt, wqe);
+       bnx2fc_process_cq_compl(tgt, wqe,
+                               rq_data_buff, num_rq, task);
+
+       return true;
 }
 
 int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
@@ -1056,8 +1103,8 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
                        /* Unsolicited event notification */
                        bnx2fc_process_unsol_compl(tgt, wqe);
                } else {
-                       bnx2fc_pending_work(tgt, wqe);
-                       num_free_sqes++;
+                       if (bnx2fc_pending_work(tgt, wqe))
+                               num_free_sqes++;
                }
                cqe++;
                tgt->cq_cons_idx++;
index 4c8122a..2b070f0 100644 (file)
@@ -24,7 +24,7 @@ static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req);
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req);
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                                 struct fcoe_fcp_rsp_payload *fcp_rsp,
-                                u8 num_rq);
+                                u8 num_rq, unsigned char *rq_data);
 
 void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
                          unsigned int timer_msec)
@@ -1518,7 +1518,8 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req)
 }
 
 void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
-                            struct fcoe_task_ctx_entry *task, u8 num_rq)
+                            struct fcoe_task_ctx_entry *task, u8 num_rq,
+                                 unsigned char *rq_data)
 {
        struct bnx2fc_mp_req *tm_req;
        struct fc_frame_header *fc_hdr;
@@ -1557,7 +1558,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
        if (fc_hdr->fh_r_ctl == FC_RCTL_DD_CMD_STATUS) {
                bnx2fc_parse_fcp_rsp(io_req,
                                     (struct fcoe_fcp_rsp_payload *)
-                                    rsp_buf, num_rq);
+                                    rsp_buf, num_rq, rq_data);
                if (io_req->fcp_rsp_code == 0) {
                        /* TM successful */
                        if (tm_req->tm_flags & FCP_TMF_LUN_RESET)
@@ -1755,15 +1756,11 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
 
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                                 struct fcoe_fcp_rsp_payload *fcp_rsp,
-                                u8 num_rq)
+                                u8 num_rq, unsigned char *rq_data)
 {
        struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
-       struct bnx2fc_rport *tgt = io_req->tgt;
        u8 rsp_flags = fcp_rsp->fcp_flags.flags;
        u32 rq_buff_len = 0;
-       int i;
-       unsigned char *rq_data;
-       unsigned char *dummy;
        int fcp_sns_len = 0;
        int fcp_rsp_len = 0;
 
@@ -1809,14 +1806,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                        rq_buff_len =  num_rq * BNX2FC_RQ_BUF_SZ;
                }
 
-               rq_data = bnx2fc_get_next_rqe(tgt, 1);
-
-               if (num_rq > 1) {
-                       /* We do not need extra sense data */
-                       for (i = 1; i < num_rq; i++)
-                               dummy = bnx2fc_get_next_rqe(tgt, 1);
-               }
-
                /* fetch fcp_rsp_code */
                if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) {
                        /* Only for task management function */
@@ -1837,9 +1826,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                if (fcp_sns_len)
                        memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len);
 
-               /* return RQ entries */
-               for (i = 0; i < num_rq; i++)
-                       bnx2fc_return_rqe(tgt, 1);
        }
 }
 
@@ -1918,7 +1904,7 @@ exit_qcmd:
 
 void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                                   struct fcoe_task_ctx_entry *task,
-                                  u8 num_rq)
+                                  u8 num_rq, unsigned char *rq_data)
 {
        struct fcoe_fcp_rsp_payload *fcp_rsp;
        struct bnx2fc_rport *tgt = io_req->tgt;
@@ -1931,6 +1917,12 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                /* we will not receive ABTS response for this IO */
                BNX2FC_IO_DBG(io_req, "Timer context finished processing "
                           "this scsi cmd\n");
+               if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
+                                      &io_req->req_flags)) {
+                       BNX2FC_IO_DBG(io_req,
+                                     "Actual completion after cleanup request cleaning up\n");
+                       bnx2fc_process_cleanup_compl(io_req, task, num_rq);
+               }
                return;
        }
 
@@ -1950,7 +1942,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                   &(task->rxwr_only.union_ctx.comp_info.fcp_rsp.payload);
 
        /* parse fcp_rsp and obtain sense data from RQ if available */
-       bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq);
+       bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq, rq_data);
 
        if (!sc_cmd->SCp.ptr) {
                printk(KERN_ERR PFX "SCp.ptr is NULL\n");
index d4c2a2e..84d73f5 100644 (file)
@@ -404,7 +404,7 @@ static const char * const hostbyte_table[]={
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
 "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE",
 "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
-"DID_NEXUS_FAILURE" };
+"DID_NEXUS_FAILURE", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR" };
 
 static const char * const driverbyte_table[]={
 "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR",
index da6e97d..773c45a 100644 (file)
@@ -632,6 +632,8 @@ static void fc_rport_error(struct fc_rport_priv *rdata, int err)
                fc_rport_enter_ready(rdata);
                break;
        case RPORT_ST_PRLI:
+               fc_rport_enter_plogi(rdata);
+               break;
        case RPORT_ST_ADISC:
                fc_rport_enter_logo(rdata);
                break;
@@ -1208,9 +1210,15 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
                rjt = fc_frame_payload_get(fp, sizeof(*rjt));
                if (!rjt)
                        FC_RPORT_DBG(rdata, "PRLI bad response\n");
-               else
+               else {
                        FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n",
                                     rjt->er_reason, rjt->er_explan);
+                       if (rjt->er_reason == ELS_RJT_UNAB &&
+                           rjt->er_explan == ELS_EXPL_PLOGI_REQD) {
+                               fc_rport_enter_plogi(rdata);
+                               goto out;
+                       }
+               }
                fc_rport_error_retry(rdata, FC_EX_ELS_RJT);
        }
 
index 357fdec..8e2a356 100644 (file)
@@ -207,8 +207,7 @@ typedef struct lpfc_vpd {
        } rev;
        struct {
 #ifdef __BIG_ENDIAN_BITFIELD
-               uint32_t rsvd3  :19;  /* Reserved                             */
-               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
+               uint32_t rsvd3  :20;  /* Reserved                             */
                uint32_t rsvd2  : 3;  /* Reserved                             */
                uint32_t cbg    : 1;  /* Configure BlockGuard                 */
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
@@ -230,8 +229,7 @@ typedef struct lpfc_vpd {
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
                uint32_t cbg    : 1;  /* Configure BlockGuard                 */
                uint32_t rsvd2  : 3;  /* Reserved                             */
-               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
-               uint32_t rsvd3  :19;  /* Reserved                             */
+               uint32_t rsvd3  :20;  /* Reserved                             */
 #endif
        } sli3Feat;
 } lpfc_vpd_t;
@@ -480,8 +478,8 @@ struct lpfc_vport {
        struct dentry *debug_nodelist;
        struct dentry *debug_nvmestat;
        struct dentry *debug_scsistat;
-       struct dentry *debug_nvmektime;
-       struct dentry *debug_cpucheck;
+       struct dentry *debug_ioktime;
+       struct dentry *debug_hdwqstat;
        struct dentry *vport_debugfs_root;
        struct lpfc_debugfs_trc *disc_trc;
        atomic_t disc_trc_cnt;
@@ -887,7 +885,6 @@ struct lpfc_hba {
 #define LPFC_INITIALIZE_LINK              0    /* do normal init_link mbox */
 #define LPFC_DELAY_INIT_LINK              1    /* layered driver hold off */
 #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2    /* wait, manual intervention */
-       uint32_t cfg_enable_dss;
        uint32_t cfg_fdmi_on;
 #define LPFC_FDMI_NO_SUPPORT   0       /* FDMI not supported */
 #define LPFC_FDMI_SUPPORT      1       /* FDMI supported? */
@@ -1156,8 +1153,6 @@ struct lpfc_hba {
        uint32_t iocb_cnt;
        uint32_t iocb_max;
        atomic_t sdev_cnt;
-       uint8_t fips_spec_rev;
-       uint8_t fips_level;
        spinlock_t devicelock;  /* lock for luns list */
        mempool_t *device_data_mem_pool;
        struct list_head luns;
@@ -1175,12 +1170,11 @@ struct lpfc_hba {
        uint16_t sfp_warning;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       uint16_t cpucheck_on;
+       uint16_t hdwqstat_on;
 #define LPFC_CHECK_OFF         0
 #define LPFC_CHECK_NVME_IO     1
-#define LPFC_CHECK_NVMET_RCV   2
-#define LPFC_CHECK_NVMET_IO    4
-#define LPFC_CHECK_SCSI_IO     8
+#define LPFC_CHECK_NVMET_IO    2
+#define LPFC_CHECK_SCSI_IO     4
        uint16_t ktime_on;
        uint64_t ktime_data_samples;
        uint64_t ktime_status_samples;
@@ -1225,6 +1219,11 @@ struct lpfc_hba {
 #define LPFC_POLL_SLOWPATH     1       /* called from slowpath */
 
        char os_host_name[MAXHOSTNAMELEN];
+
+       /* SCSI host template information - for physical port */
+       struct scsi_host_template port_template;
+       /* SCSI host template information - for all vports */
+       struct scsi_host_template vport_template;
 };
 
 static inline struct Scsi_Host *
index be3b0cc..1354c14 100644 (file)
@@ -2231,66 +2231,6 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * lpfc_fips_level_show - Return the current FIPS level for the HBA
- * @dev: class unused variable.
- * @attr: device attribute, not used.
- * @buf: on return contains the module description text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_fips_level_show(struct device *dev,  struct device_attribute *attr,
-                    char *buf)
-{
-       struct Scsi_Host  *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level);
-}
-
-/**
- * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA
- * @dev: class unused variable.
- * @attr: device attribute, not used.
- * @buf: on return contains the module description text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_fips_rev_show(struct device *dev,  struct device_attribute *attr,
-                  char *buf)
-{
-       struct Scsi_Host  *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev);
-}
-
-/**
- * lpfc_dss_show - Return the current state of dss and the configured state
- * @dev: class converted to a Scsi_host structure.
- * @attr: device attribute, not used.
- * @buf: on return contains the formatted text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_dss_show(struct device *dev, struct device_attribute *attr,
-             char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n",
-                       (phba->cfg_enable_dss) ? "Enabled" : "Disabled",
-                       (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ?
-                               "" : "Not ");
-}
-
-/**
  * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions
  * @dev: class converted to a Scsi_host structure.
  * @attr: device attribute, not used.
@@ -2705,9 +2645,6 @@ static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
 static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
 static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
 static DEVICE_ATTR_RO(lpfc_temp_sensor);
-static DEVICE_ATTR_RO(lpfc_fips_level);
-static DEVICE_ATTR_RO(lpfc_fips_rev);
-static DEVICE_ATTR_RO(lpfc_dss);
 static DEVICE_ATTR_RO(lpfc_sriov_hw_max_virtfn);
 static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL);
 static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show,
@@ -3868,9 +3805,9 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1,
 
 /*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
-# commands per FCP LUN. Value range is [1,512]. Default value is 30.
+# commands per FCP LUN.
 */
-LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
+LPFC_VPORT_ATTR_R(lun_queue_depth, 64, 1, 512,
                  "Max number of FCP commands we can queue to a specific LUN");
 
 /*
@@ -6251,9 +6188,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_pt,
        &dev_attr_txq_hw,
        &dev_attr_txcmplq_hw,
-       &dev_attr_lpfc_fips_level,
-       &dev_attr_lpfc_fips_rev,
-       &dev_attr_lpfc_dss,
        &dev_attr_lpfc_sriov_hw_max_virtfn,
        &dev_attr_protocol,
        &dev_attr_lpfc_xlane_supported,
@@ -6289,8 +6223,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
        &dev_attr_lpfc_max_scsicmpl_time,
        &dev_attr_lpfc_stat_data_ctrl,
        &dev_attr_lpfc_static_vport,
-       &dev_attr_lpfc_fips_level,
-       &dev_attr_lpfc_fips_rev,
        NULL,
 };
 
@@ -7399,7 +7331,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
        lpfc_delay_discovery_init(phba, lpfc_delay_discovery);
        lpfc_sli_mode_init(phba, lpfc_sli_mode);
-       phba->cfg_enable_dss = 1;
        lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags);
        lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize);
        lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level);
index a450477..76dc8d9 100644 (file)
@@ -404,9 +404,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *);
 extern struct device_attribute *lpfc_hba_attrs[];
 extern struct device_attribute *lpfc_vport_attrs[];
 extern struct scsi_host_template lpfc_template;
-extern struct scsi_host_template lpfc_template_no_hr;
 extern struct scsi_host_template lpfc_template_nvme;
-extern struct scsi_host_template lpfc_vport_template;
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 
@@ -590,6 +588,7 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba,
                                int);
 void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd,
                         struct lpfc_sli4_hdw_queue *qp);
+void lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd);
 void lpfc_nvme_cmd_template(void);
 void lpfc_nvmet_cmd_template(void);
 void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn);
index 819335b..8a6e02a 100644 (file)
@@ -1300,8 +1300,88 @@ buffer_done:
        return len;
 }
 
+void
+lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
+{
+       uint64_t seg1, seg2, seg3, seg4;
+       uint64_t segsum;
+
+       if (!lpfc_cmd->ts_last_cmd ||
+           !lpfc_cmd->ts_cmd_start ||
+           !lpfc_cmd->ts_cmd_wqput ||
+           !lpfc_cmd->ts_isr_cmpl ||
+           !lpfc_cmd->ts_data_io)
+               return;
+
+       if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start)
+               return;
+       if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd)
+               return;
+       if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start)
+               return;
+       if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput)
+               return;
+       if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl)
+               return;
+       /*
+        * Segment 1 - Time from Last FCP command cmpl is handed
+        * off to NVME Layer to start of next command.
+        * Segment 2 - Time from Driver receives a IO cmd start
+        * from NVME Layer to WQ put is done on IO cmd.
+        * Segment 3 - Time from Driver WQ put is done on IO cmd
+        * to MSI-X ISR for IO cmpl.
+        * Segment 4 - Time from MSI-X ISR for IO cmpl to when
+        * cmpl is handled off to the NVME Layer.
+        */
+       seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd;
+       if (seg1 > 5000000)  /* 5 ms - for sequential IOs only */
+               seg1 = 0;
+
+       /* Calculate times relative to start of IO */
+       seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start);
+       segsum = seg2;
+       seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start;
+       if (segsum > seg3)
+               return;
+       seg3 -= segsum;
+       segsum += seg3;
+
+       seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start;
+       if (segsum > seg4)
+               return;
+       seg4 -= segsum;
+
+       phba->ktime_data_samples++;
+       phba->ktime_seg1_total += seg1;
+       if (seg1 < phba->ktime_seg1_min)
+               phba->ktime_seg1_min = seg1;
+       else if (seg1 > phba->ktime_seg1_max)
+               phba->ktime_seg1_max = seg1;
+       phba->ktime_seg2_total += seg2;
+       if (seg2 < phba->ktime_seg2_min)
+               phba->ktime_seg2_min = seg2;
+       else if (seg2 > phba->ktime_seg2_max)
+               phba->ktime_seg2_max = seg2;
+       phba->ktime_seg3_total += seg3;
+       if (seg3 < phba->ktime_seg3_min)
+               phba->ktime_seg3_min = seg3;
+       else if (seg3 > phba->ktime_seg3_max)
+               phba->ktime_seg3_max = seg3;
+       phba->ktime_seg4_total += seg4;
+       if (seg4 < phba->ktime_seg4_min)
+               phba->ktime_seg4_min = seg4;
+       else if (seg4 > phba->ktime_seg4_max)
+               phba->ktime_seg4_max = seg4;
+
+       lpfc_cmd->ts_last_cmd = 0;
+       lpfc_cmd->ts_cmd_start = 0;
+       lpfc_cmd->ts_cmd_wqput  = 0;
+       lpfc_cmd->ts_isr_cmpl = 0;
+       lpfc_cmd->ts_data_io = 0;
+}
+
 /**
- * lpfc_debugfs_nvmektime_data - Dump target node list to a buffer
+ * lpfc_debugfs_ioktime_data - Dump target node list to a buffer
  * @vport: The vport to gather target node info from.
  * @buf: The buffer to dump log into.
  * @size: The maximum amount of data to process.
@@ -1314,13 +1394,13 @@ buffer_done:
  * not exceed @size.
  **/
 static int
-lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
+lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size)
 {
        struct lpfc_hba   *phba = vport->phba;
        int len = 0;
 
        if (phba->nvmet_support == 0) {
-               /* NVME Initiator */
+               /* Initiator */
                len += scnprintf(buf + len, PAGE_SIZE - len,
                                "ktime %s: Total Samples: %lld\n",
                                (phba->ktime_on ?  "Enabled" : "Disabled"),
@@ -1330,8 +1410,8 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
 
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
-                       "Segment 1: Last NVME Cmd cmpl "
-                       "done -to- Start of next NVME cnd (in driver)\n");
+                       "Segment 1: Last Cmd cmpl "
+                       "done -to- Start of next Cmd (in driver)\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "avg:%08lld min:%08lld max %08lld\n",
@@ -1341,7 +1421,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
                        phba->ktime_seg1_max);
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
-                       "Segment 2: Driver start of NVME cmd "
+                       "Segment 2: Driver start of Cmd "
                        "-to- Firmware WQ doorbell\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
@@ -1364,7 +1444,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "Segment 4: MSI-X ISR cmpl -to- "
-                       "NVME cmpl done\n");
+                       "Cmd cmpl done\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "avg:%08lld min:%08lld max %08lld\n",
@@ -1603,42 +1683,50 @@ out:
 }
 
 /**
- * lpfc_debugfs_cpucheck_data - Dump target node list to a buffer
+ * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer
  * @vport: The vport to gather target node info from.
  * @buf: The buffer to dump log into.
  * @size: The maximum amount of data to process.
  *
  * Description:
- * This routine dumps the NVME statistics associated with @vport
+ * This routine dumps the NVME + SCSI statistics associated with @vport
  *
  * Return Value:
  * This routine returns the amount of bytes that were dumped into @buf and will
  * not exceed @size.
  **/
 static int
-lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
+lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size)
 {
        struct lpfc_hba   *phba = vport->phba;
        struct lpfc_sli4_hdw_queue *qp;
-       int i, j, max_cnt;
-       int len = 0;
+       struct lpfc_hdwq_stat *c_stat;
+       int i, j, len;
        uint32_t tot_xmt;
        uint32_t tot_rcv;
        uint32_t tot_cmpl;
+       char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
 
-       len += scnprintf(buf + len, PAGE_SIZE - len,
-                       "CPUcheck %s ",
-                       (phba->cpucheck_on & LPFC_CHECK_NVME_IO ?
-                               "Enabled" : "Disabled"));
-       if (phba->nvmet_support) {
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "%s\n",
-                               (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ?
-                                       "Rcv Enabled\n" : "Rcv Disabled\n"));
-       } else {
-               len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
-       }
-       max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ;
+       scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n");
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ",
+                 (phba->hdwqstat_on &
+                 (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ?
+                 "Enabled" : "Disabled"));
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ",
+                 (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ?
+                 "Enabled" : "Disabled"));
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "\n\n");
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
 
        for (i = 0; i < phba->cfg_hdw_queue; i++) {
                qp = &phba->sli4_hba.hdwq[i];
@@ -1646,46 +1734,76 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
                tot_rcv = 0;
                tot_xmt = 0;
                tot_cmpl = 0;
-               for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
-                       tot_xmt += qp->cpucheck_xmt_io[j];
-                       tot_cmpl += qp->cpucheck_cmpl_io[j];
-                       if (phba->nvmet_support)
-                               tot_rcv += qp->cpucheck_rcv_io[j];
-               }
 
-               /* Only display Hardware Qs with something */
-               if (!tot_xmt && !tot_cmpl && !tot_rcv)
-                       continue;
+               for_each_present_cpu(j) {
+                       c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j);
+
+                       /* Only display for this HDWQ */
+                       if (i != c_stat->hdwq_no)
+                               continue;
 
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "HDWQ %03d: ", i);
-               for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
                        /* Only display non-zero counters */
-                       if (!qp->cpucheck_xmt_io[j] &&
-                           !qp->cpucheck_cmpl_io[j] &&
-                           !qp->cpucheck_rcv_io[j])
+                       if (!c_stat->xmt_io && !c_stat->cmpl_io &&
+                           !c_stat->rcv_io)
                                continue;
+
+                       if (!tot_xmt && !tot_cmpl && !tot_rcv) {
+                               /* Print HDWQ string only the first time */
+                               scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
+                       }
+
+                       tot_xmt += c_stat->xmt_io;
+                       tot_cmpl += c_stat->cmpl_io;
+                       if (phba->nvmet_support)
+                               tot_rcv += c_stat->rcv_io;
+
+                       scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
+
                        if (phba->nvmet_support) {
-                               len += scnprintf(buf + len, PAGE_SIZE - len,
-                                               "CPU %03d: %x/%x/%x ", j,
-                                               qp->cpucheck_rcv_io[j],
-                                               qp->cpucheck_xmt_io[j],
-                                               qp->cpucheck_cmpl_io[j]);
+                               scnprintf(tmp, sizeof(tmp),
+                                         "XMT 0x%x CMPL 0x%x RCV 0x%x |",
+                                         c_stat->xmt_io, c_stat->cmpl_io,
+                                         c_stat->rcv_io);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
                        } else {
-                               len += scnprintf(buf + len, PAGE_SIZE - len,
-                                               "CPU %03d: %x/%x ", j,
-                                               qp->cpucheck_xmt_io[j],
-                                               qp->cpucheck_cmpl_io[j]);
+                               scnprintf(tmp, sizeof(tmp),
+                                         "XMT 0x%x CMPL 0x%x |",
+                                         c_stat->xmt_io, c_stat->cmpl_io);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
                        }
                }
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "Total: %x\n", tot_xmt);
-               if (len >= max_cnt) {
-                       len += scnprintf(buf + len, PAGE_SIZE - len,
-                                       "Truncated ...\n");
-                       return len;
+
+               /* Check if nothing to display */
+               if (!tot_xmt && !tot_cmpl && !tot_rcv)
+                       continue;
+
+               scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: ");
+               if (strlcat(buf, tmp, size) >= size)
+                       goto buffer_done;
+
+               if (phba->nvmet_support) {
+                       scnprintf(tmp, sizeof(tmp),
+                                 "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n",
+                                 tot_xmt, tot_cmpl, tot_rcv);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
+               } else {
+                       scnprintf(tmp, sizeof(tmp),
+                                 "XMT 0x%x CMPL 0x%x]\n\n",
+                                 tot_xmt, tot_cmpl);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
                }
        }
+
+buffer_done:
+       len = strnlen(buf, size);
        return len;
 }
 
@@ -2689,7 +2807,7 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
 }
 
 static int
-lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file)
+lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file)
 {
        struct lpfc_vport *vport = inode->i_private;
        struct lpfc_debug *debug;
@@ -2700,14 +2818,14 @@ lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file)
                goto out;
 
         /* Round to page boundary */
-       debug->buffer = kmalloc(LPFC_NVMEKTIME_SIZE, GFP_KERNEL);
+       debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL);
        if (!debug->buffer) {
                kfree(debug);
                goto out;
        }
 
-       debug->len = lpfc_debugfs_nvmektime_data(vport, debug->buffer,
-               LPFC_NVMEKTIME_SIZE);
+       debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer,
+               LPFC_IOKTIME_SIZE);
 
        debug->i_private = inode->i_private;
        file->private_data = debug;
@@ -2718,8 +2836,8 @@ out:
 }
 
 static ssize_t
-lpfc_debugfs_nvmektime_write(struct file *file, const char __user *buf,
-                            size_t nbytes, loff_t *ppos)
+lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf,
+                          size_t nbytes, loff_t *ppos)
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
@@ -2921,7 +3039,7 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
 }
 
 static int
-lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file)
+lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file)
 {
        struct lpfc_vport *vport = inode->i_private;
        struct lpfc_debug *debug;
@@ -2932,14 +3050,14 @@ lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file)
                goto out;
 
         /* Round to page boundary */
-       debug->buffer = kmalloc(LPFC_CPUCHECK_SIZE, GFP_KERNEL);
+       debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL);
        if (!debug->buffer) {
                kfree(debug);
                goto out;
        }
 
-       debug->len = lpfc_debugfs_cpucheck_data(vport, debug->buffer,
-               LPFC_CPUCHECK_SIZE);
+       debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer,
+                                               LPFC_SCSISTAT_SIZE);
 
        debug->i_private = inode->i_private;
        file->private_data = debug;
@@ -2950,16 +3068,16 @@ out:
 }
 
 static ssize_t
-lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf,
+lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf,
                            size_t nbytes, loff_t *ppos)
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
        struct lpfc_hba   *phba = vport->phba;
-       struct lpfc_sli4_hdw_queue *qp;
+       struct lpfc_hdwq_stat *c_stat;
        char mybuf[64];
        char *pbuf;
-       int i, j;
+       int i;
 
        if (nbytes > 64)
                nbytes = 64;
@@ -2972,41 +3090,39 @@ lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf,
 
        if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
                if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
                else
-                       phba->cpucheck_on |= (LPFC_CHECK_NVME_IO |
+                       phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO |
                                LPFC_CHECK_SCSI_IO);
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) {
                if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
                else
-                       phba->cpucheck_on |= LPFC_CHECK_NVME_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVME_IO;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) {
-               phba->cpucheck_on |= LPFC_CHECK_SCSI_IO;
+               if (!phba->nvmet_support)
+                       phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO;
                return strlen(pbuf);
-       } else if ((strncmp(pbuf, "rcv",
-                  sizeof("rcv") - 1) == 0)) {
-               if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_RCV;
-               else
-                       return -EINVAL;
+       } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) {
+               phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO |
+                                      LPFC_CHECK_NVMET_IO);
+               return strlen(pbuf);
+       } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) {
+               phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "off",
                   sizeof("off") - 1) == 0)) {
-               phba->cpucheck_on = LPFC_CHECK_OFF;
+               phba->hdwqstat_on = LPFC_CHECK_OFF;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "zero",
                   sizeof("zero") - 1) == 0)) {
-               for (i = 0; i < phba->cfg_hdw_queue; i++) {
-                       qp = &phba->sli4_hba.hdwq[i];
-
-                       for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
-                               qp->cpucheck_rcv_io[j] = 0;
-                               qp->cpucheck_xmt_io[j] = 0;
-                               qp->cpucheck_cmpl_io[j] = 0;
-                       }
+               for_each_present_cpu(i) {
+                       c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i);
+                       c_stat->xmt_io = 0;
+                       c_stat->cmpl_io = 0;
+                       c_stat->rcv_io = 0;
                }
                return strlen(pbuf);
        }
@@ -5431,13 +5547,13 @@ static const struct file_operations lpfc_debugfs_op_scsistat = {
        .release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_nvmektime
-static const struct file_operations lpfc_debugfs_op_nvmektime = {
+#undef lpfc_debugfs_op_ioktime
+static const struct file_operations lpfc_debugfs_op_ioktime = {
        .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_nvmektime_open,
+       .open =         lpfc_debugfs_ioktime_open,
        .llseek =       lpfc_debugfs_lseek,
        .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_nvmektime_write,
+       .write =        lpfc_debugfs_ioktime_write,
        .release =      lpfc_debugfs_release,
 };
 
@@ -5451,13 +5567,13 @@ static const struct file_operations lpfc_debugfs_op_nvmeio_trc = {
        .release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_cpucheck
-static const struct file_operations lpfc_debugfs_op_cpucheck = {
+#undef lpfc_debugfs_op_hdwqstat
+static const struct file_operations lpfc_debugfs_op_hdwqstat = {
        .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_cpucheck_open,
+       .open =         lpfc_debugfs_hdwqstat_open,
        .llseek =       lpfc_debugfs_lseek,
        .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_cpucheck_write,
+       .write =        lpfc_debugfs_hdwqstat_write,
        .release =      lpfc_debugfs_release,
 };
 
@@ -6075,17 +6191,22 @@ nvmeio_off:
                goto debug_failed;
        }
 
-       snprintf(name, sizeof(name), "nvmektime");
-       vport->debug_nvmektime =
+       snprintf(name, sizeof(name), "ioktime");
+       vport->debug_ioktime =
                debugfs_create_file(name, 0644,
                                    vport->vport_debugfs_root,
-                                   vport, &lpfc_debugfs_op_nvmektime);
+                                   vport, &lpfc_debugfs_op_ioktime);
+       if (!vport->debug_ioktime) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                "0815 Cannot create debugfs ioktime\n");
+               goto debug_failed;
+       }
 
-       snprintf(name, sizeof(name), "cpucheck");
-       vport->debug_cpucheck =
+       snprintf(name, sizeof(name), "hdwqstat");
+       vport->debug_hdwqstat =
                debugfs_create_file(name, 0644,
                                    vport->vport_debugfs_root,
-                                   vport, &lpfc_debugfs_op_cpucheck);
+                                   vport, &lpfc_debugfs_op_hdwqstat);
 
        /*
         * The following section is for additional directories/files for the
@@ -6216,11 +6337,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
        debugfs_remove(vport->debug_scsistat); /* scsistat */
        vport->debug_scsistat = NULL;
 
-       debugfs_remove(vport->debug_nvmektime); /* nvmektime */
-       vport->debug_nvmektime = NULL;
+       debugfs_remove(vport->debug_ioktime); /* ioktime */
+       vport->debug_ioktime = NULL;
 
-       debugfs_remove(vport->debug_cpucheck); /* cpucheck */
-       vport->debug_cpucheck = NULL;
+       debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */
+       vport->debug_hdwqstat = NULL;
 
        if (vport->vport_debugfs_root) {
                debugfs_remove(vport->vport_debugfs_root); /* vportX */
index 20f2537..7ab6d3b 100644 (file)
@@ -46,8 +46,7 @@
 
 /* nvmestat output buffer size */
 #define LPFC_NVMESTAT_SIZE 8192
-#define LPFC_NVMEKTIME_SIZE 8192
-#define LPFC_CPUCHECK_SIZE 8192
+#define LPFC_IOKTIME_SIZE 8192
 #define LPFC_NVMEIO_TRC_SIZE 8192
 
 /* scsistat output buffer size */
index ae51c0d..c20034b 100644 (file)
@@ -3262,8 +3262,7 @@ typedef struct {
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd1     : 19;  /* Reserved                             */
-       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd1     : 20;  /* Reserved                             */
        uint32_t casabt    :  1;  /* Configure async abts status notice   */
        uint32_t rsvd2     :  2;  /* Reserved                             */
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
@@ -3287,12 +3286,10 @@ typedef struct {
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
        uint32_t rsvd2     :  2;  /* Reserved                             */
        uint32_t casabt    :  1;  /* Configure async abts status notice   */
-       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
-       uint32_t rsvd1     : 19;  /* Reserved                             */
+       uint32_t rsvd1     : 20;  /* Reserved                             */
 #endif
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd3     : 19;  /* Reserved                             */
-       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd3     : 20;  /* Reserved                             */
        uint32_t gasabt    :  1;  /* Grant async abts status notice       */
        uint32_t rsvd4     :  2;  /* Reserved                             */
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
@@ -3316,8 +3313,7 @@ typedef struct {
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
        uint32_t rsvd4     :  2;  /* Reserved                             */
        uint32_t gasabt    :  1;  /* Grant async abts status notice       */
-       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
-       uint32_t rsvd3     : 19;  /* Reserved                             */
+       uint32_t rsvd3     : 20;  /* Reserved                             */
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -3339,15 +3335,11 @@ typedef struct {
        uint32_t rsvd6;           /* Reserved                             */
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t fips_rev   : 3;   /* FIPS Spec Revision                   */
-       uint32_t fips_level : 4;   /* FIPS Level                           */
-       uint32_t sec_err    : 9;   /* security crypto error                */
+       uint32_t rsvd7      : 16;
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
 #else  /*  __LITTLE_ENDIAN */
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
-       uint32_t sec_err    : 9;   /* security crypto error                */
-       uint32_t fips_level : 4;   /* FIPS Level                           */
-       uint32_t fips_rev   : 3;   /* FIPS Spec Revision                   */
+       uint32_t rsvd7      : 16;
 #endif
 
 } CONFIG_PORT_VAR;
index 9d03e9b..4104bdc 100644 (file)
@@ -4231,6 +4231,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 {
        struct lpfc_vport *vport;
        struct Scsi_Host  *shost = NULL;
+       struct scsi_host_template *template;
        int error = 0;
        int i;
        uint64_t wwn;
@@ -4259,22 +4260,50 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
                }
        }
 
-       if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) {
-               if (dev != &phba->pcidev->dev) {
-                       shost = scsi_host_alloc(&lpfc_vport_template,
-                                               sizeof(struct lpfc_vport));
+       /* Seed template for SCSI host registration */
+       if (dev == &phba->pcidev->dev) {
+               template = &phba->port_template;
+
+               if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) {
+                       /* Seed physical port template */
+                       memcpy(template, &lpfc_template, sizeof(*template));
+
+                       if (use_no_reset_hba) {
+                               /* template is for a no reset SCSI Host */
+                               template->max_sectors = 0xffff;
+                               template->eh_host_reset_handler = NULL;
+                       }
+
+                       /* Template for all vports this physical port creates */
+                       memcpy(&phba->vport_template, &lpfc_template,
+                              sizeof(*template));
+                       phba->vport_template.max_sectors = 0xffff;
+                       phba->vport_template.shost_attrs = lpfc_vport_attrs;
+                       phba->vport_template.eh_bus_reset_handler = NULL;
+                       phba->vport_template.eh_host_reset_handler = NULL;
+                       phba->vport_template.vendor_id = 0;
+
+                       /* Initialize the host templates with updated value */
+                       if (phba->sli_rev == LPFC_SLI_REV4) {
+                               template->sg_tablesize = phba->cfg_scsi_seg_cnt;
+                               phba->vport_template.sg_tablesize =
+                                       phba->cfg_scsi_seg_cnt;
+                       } else {
+                               template->sg_tablesize = phba->cfg_sg_seg_cnt;
+                               phba->vport_template.sg_tablesize =
+                                       phba->cfg_sg_seg_cnt;
+                       }
+
                } else {
-                       if (!use_no_reset_hba)
-                               shost = scsi_host_alloc(&lpfc_template,
-                                               sizeof(struct lpfc_vport));
-                       else
-                               shost = scsi_host_alloc(&lpfc_template_no_hr,
-                                               sizeof(struct lpfc_vport));
+                       /* NVMET is for physical port only */
+                       memcpy(template, &lpfc_template_nvme,
+                              sizeof(*template));
                }
-       } else if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
-               shost = scsi_host_alloc(&lpfc_template_nvme,
-                                       sizeof(struct lpfc_vport));
+       } else {
+               template = &phba->vport_template;
        }
+
+       shost = scsi_host_alloc(template, sizeof(struct lpfc_vport));
        if (!shost)
                goto out;
 
@@ -4329,6 +4358,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
                vport->port_type = LPFC_PHYSICAL_PORT;
        }
 
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
+                       "9081 CreatePort TMPLATE type %x TBLsize %d "
+                       "SEGcnt %d/%d\n",
+                       vport->port_type, shost->sg_tablesize,
+                       phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt);
+
        /* Initialize all internally managed lists. */
        INIT_LIST_HEAD(&vport->fc_nodes);
        INIT_LIST_HEAD(&vport->rcv_buffer_list);
@@ -6301,11 +6336,6 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
         * used to create the sg_dma_buf_pool must be dynamically calculated.
         */
 
-       /* Initialize the host templates the configured values. */
-       lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-       lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt;
-       lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-
        if (phba->sli_rev == LPFC_SLI_REV4)
                entry_sz = sizeof(struct sli4_sge);
        else
@@ -6346,7 +6376,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
        }
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
-                       "9088 sg_tablesize:%d dmabuf_size:%d total_bde:%d\n",
+                       "9088 INIT sg_tablesize:%d dmabuf_size:%d total_bde:%d\n",
                        phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size,
                        phba->cfg_total_seg_cnt);
 
@@ -6816,11 +6846,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                        phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt;
        }
 
-       /* Initialize the host templates with the updated values. */
-       lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
-       lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
-       lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt;
-
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
                        "9087 sg_seg_cnt:%d dmabuf_size:%d "
                        "total:%d scsi:%d nvme:%d\n",
@@ -6926,6 +6951,17 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                rc = -ENOMEM;
                goto out_free_hba_cpu_map;
        }
+
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       phba->sli4_hba.c_stat = alloc_percpu(struct lpfc_hdwq_stat);
+       if (!phba->sli4_hba.c_stat) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3332 Failed allocating per cpu hdwq stats\n");
+               rc = -ENOMEM;
+               goto out_free_hba_eq_info;
+       }
+#endif
+
        /*
         * Enable sr-iov virtual functions if supported and configured
         * through the module parameter.
@@ -6945,6 +6981,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 
        return 0;
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+out_free_hba_eq_info:
+       free_percpu(phba->sli4_hba.eq_info);
+#endif
 out_free_hba_cpu_map:
        kfree(phba->sli4_hba.cpu_map);
 out_free_hba_eq_hdl:
@@ -6983,6 +7023,9 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
 
        free_percpu(phba->sli4_hba.eq_info);
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       free_percpu(phba->sli4_hba.c_stat);
+#endif
 
        /* Free memory allocated for msi-x interrupt vector to CPU mapping */
        kfree(phba->sli4_hba.cpu_map);
@@ -10823,6 +10866,9 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
 #ifdef CONFIG_X86
        struct cpuinfo_x86 *cpuinfo;
 #endif
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       struct lpfc_hdwq_stat *c_stat;
+#endif
 
        max_phys_id = 0;
        min_phys_id = LPFC_VECTOR_MAP_EMPTY;
@@ -11074,10 +11120,17 @@ found_any:
        idx = 0;
        for_each_possible_cpu(cpu) {
                cpup = &phba->sli4_hba.cpu_map[cpu];
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+               c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, cpu);
+               c_stat->hdwq_no = cpup->hdwq;
+#endif
                if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY)
                        continue;
 
                cpup->hdwq = idx++ % phba->cfg_hdw_queue;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+               c_stat->hdwq_no = cpup->hdwq;
+#endif
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                "3340 Set Affinity: not present "
                                "CPU %d hdwq %d\n",
@@ -11173,11 +11226,9 @@ static void lpfc_cpuhp_add(struct lpfc_hba *phba)
 
        rcu_read_lock();
 
-       if (!list_empty(&phba->poll_list)) {
-               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
+       if (!list_empty(&phba->poll_list))
                mod_timer(&phba->cpuhp_poll_timer,
                          jiffies + msecs_to_jiffies(LPFC_POLL_HB));
-       }
 
        rcu_read_unlock();
 
@@ -13145,6 +13196,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        lpfc_sli4_ras_setup(phba);
 
        INIT_LIST_HEAD(&phba->poll_list);
+       timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
        cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp);
 
        return 0;
index d1773c0..e35b52b 100644 (file)
@@ -1299,8 +1299,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
                if (phba->cfg_enable_bg)
                        mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
-               if (phba->cfg_enable_dss)
-                       mb->un.varCfgPort.cdss = 1; /* Configure Security */
                mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
                mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
                mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
index f6c8963..a45936e 100644 (file)
@@ -382,13 +382,15 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport)
        if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) {
                ndlp->nrport = NULL;
                ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG;
-       }
-       spin_unlock_irq(&vport->phba->hbalock);
+               spin_unlock_irq(&vport->phba->hbalock);
 
-       /* Remove original register reference. The host transport
-        * won't reference this rport/remoteport any further.
-        */
-       lpfc_nlp_put(ndlp);
+               /* Remove original register reference. The host transport
+                * won't reference this rport/remoteport any further.
+                */
+               lpfc_nlp_put(ndlp);
+       } else {
+               spin_unlock_irq(&vport->phba->hbalock);
+       }
 
  rport_err:
        return;
@@ -897,88 +899,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
        sgl->sge_len = cpu_to_le32(nCmd->rsplen);
 }
 
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-static void
-lpfc_nvme_ktime(struct lpfc_hba *phba,
-               struct lpfc_io_buf *lpfc_ncmd)
-{
-       uint64_t seg1, seg2, seg3, seg4;
-       uint64_t segsum;
-
-       if (!lpfc_ncmd->ts_last_cmd ||
-           !lpfc_ncmd->ts_cmd_start ||
-           !lpfc_ncmd->ts_cmd_wqput ||
-           !lpfc_ncmd->ts_isr_cmpl ||
-           !lpfc_ncmd->ts_data_nvme)
-               return;
-
-       if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_cmd_start)
-               return;
-       if (lpfc_ncmd->ts_cmd_start < lpfc_ncmd->ts_last_cmd)
-               return;
-       if (lpfc_ncmd->ts_cmd_wqput < lpfc_ncmd->ts_cmd_start)
-               return;
-       if (lpfc_ncmd->ts_isr_cmpl < lpfc_ncmd->ts_cmd_wqput)
-               return;
-       if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_isr_cmpl)
-               return;
-       /*
-        * Segment 1 - Time from Last FCP command cmpl is handed
-        * off to NVME Layer to start of next command.
-        * Segment 2 - Time from Driver receives a IO cmd start
-        * from NVME Layer to WQ put is done on IO cmd.
-        * Segment 3 - Time from Driver WQ put is done on IO cmd
-        * to MSI-X ISR for IO cmpl.
-        * Segment 4 - Time from MSI-X ISR for IO cmpl to when
-        * cmpl is handled off to the NVME Layer.
-        */
-       seg1 = lpfc_ncmd->ts_cmd_start - lpfc_ncmd->ts_last_cmd;
-       if (seg1 > 5000000)  /* 5 ms - for sequential IOs only */
-               seg1 = 0;
-
-       /* Calculate times relative to start of IO */
-       seg2 = (lpfc_ncmd->ts_cmd_wqput - lpfc_ncmd->ts_cmd_start);
-       segsum = seg2;
-       seg3 = lpfc_ncmd->ts_isr_cmpl - lpfc_ncmd->ts_cmd_start;
-       if (segsum > seg3)
-               return;
-       seg3 -= segsum;
-       segsum += seg3;
-
-       seg4 = lpfc_ncmd->ts_data_nvme - lpfc_ncmd->ts_cmd_start;
-       if (segsum > seg4)
-               return;
-       seg4 -= segsum;
-
-       phba->ktime_data_samples++;
-       phba->ktime_seg1_total += seg1;
-       if (seg1 < phba->ktime_seg1_min)
-               phba->ktime_seg1_min = seg1;
-       else if (seg1 > phba->ktime_seg1_max)
-               phba->ktime_seg1_max = seg1;
-       phba->ktime_seg2_total += seg2;
-       if (seg2 < phba->ktime_seg2_min)
-               phba->ktime_seg2_min = seg2;
-       else if (seg2 > phba->ktime_seg2_max)
-               phba->ktime_seg2_max = seg2;
-       phba->ktime_seg3_total += seg3;
-       if (seg3 < phba->ktime_seg3_min)
-               phba->ktime_seg3_min = seg3;
-       else if (seg3 > phba->ktime_seg3_max)
-               phba->ktime_seg3_max = seg3;
-       phba->ktime_seg4_total += seg4;
-       if (seg4 < phba->ktime_seg4_min)
-               phba->ktime_seg4_min = seg4;
-       else if (seg4 > phba->ktime_seg4_max)
-               phba->ktime_seg4_max = seg4;
-
-       lpfc_ncmd->ts_last_cmd = 0;
-       lpfc_ncmd->ts_cmd_start = 0;
-       lpfc_ncmd->ts_cmd_wqput  = 0;
-       lpfc_ncmd->ts_isr_cmpl = 0;
-       lpfc_ncmd->ts_data_nvme = 0;
-}
-#endif
 
 /**
  * lpfc_nvme_io_cmd_wqe_cmpl - Complete an NVME-over-FCP IO
@@ -1010,6 +930,9 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
        uint32_t code, status, idx;
        uint16_t cid, sqhd, data;
        uint32_t *ptr;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       int cpu;
+#endif
 
        /* Sanity check on return of outstanding command */
        if (!lpfc_ncmd) {
@@ -1178,23 +1101,19 @@ out_err:
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        if (lpfc_ncmd->ts_cmd_start) {
                lpfc_ncmd->ts_isr_cmpl = pwqeIn->isr_timestamp;
-               lpfc_ncmd->ts_data_nvme = ktime_get_ns();
-               phba->ktime_last_cmd = lpfc_ncmd->ts_data_nvme;
-               lpfc_nvme_ktime(phba, lpfc_ncmd);
+               lpfc_ncmd->ts_data_io = ktime_get_ns();
+               phba->ktime_last_cmd = lpfc_ncmd->ts_data_io;
+               lpfc_io_ktime(phba, lpfc_ncmd);
        }
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_NVME_IO)) {
-               uint32_t cpu;
-               idx = lpfc_ncmd->cur_iocbq.hba_wqidx;
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_NVME_IO)) {
                cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       if (lpfc_ncmd->cpu != cpu)
-                               lpfc_printf_vlog(vport,
-                                                KERN_INFO, LOG_NVME_IOERR,
-                                                "6701 CPU Check cmpl: "
-                                                "cpu %d expect %d\n",
-                                                cpu, lpfc_ncmd->cpu);
-                       phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
+               if (lpfc_ncmd->cpu != cpu)
+                       lpfc_printf_vlog(vport,
+                                        KERN_INFO, LOG_NVME_IOERR,
+                                        "6701 CPU Check cmpl: "
+                                        "cpu %d expect %d\n",
+                                        cpu, lpfc_ncmd->cpu);
        }
 #endif
 
@@ -1743,19 +1662,17 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport,
        if (lpfc_ncmd->ts_cmd_start)
                lpfc_ncmd->ts_cmd_wqput = ktime_get_ns();
 
-       if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) {
+       if (phba->hdwqstat_on & LPFC_CHECK_NVME_IO) {
                cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       lpfc_ncmd->cpu = cpu;
-                       if (idx != cpu)
-                               lpfc_printf_vlog(vport,
-                                                KERN_INFO, LOG_NVME_IOERR,
-                                               "6702 CPU Check cmd: "
-                                               "cpu %d wq %d\n",
-                                               lpfc_ncmd->cpu,
-                                               lpfc_queue_info->index);
-                       phba->sli4_hba.hdwq[idx].cpucheck_xmt_io[cpu]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
+               lpfc_ncmd->cpu = cpu;
+               if (idx != cpu)
+                       lpfc_printf_vlog(vport,
+                                        KERN_INFO, LOG_NVME_IOERR,
+                                       "6702 CPU Check cmd: "
+                                       "cpu %d wq %d\n",
+                                       lpfc_ncmd->cpu,
+                                       lpfc_queue_info->index);
        }
 #endif
        return 0;
@@ -1985,8 +1902,6 @@ out_unlock:
 
 /* Declare and initialization an instance of the FC NVME template. */
 static struct nvme_fc_port_template lpfc_nvme_template = {
-       .module = THIS_MODULE,
-
        /* initiator-based functions */
        .localport_delete  = lpfc_nvme_localport_delete,
        .remoteport_delete = lpfc_nvme_remoteport_delete,
index 9dc9afe..565419b 100644 (file)
@@ -707,7 +707,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        struct lpfc_nvmet_rcv_ctx *ctxp;
        uint32_t status, result, op, start_clean, logerr;
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       uint32_t id;
+       int id;
 #endif
 
        ctxp = cmdwqe->context2;
@@ -814,16 +814,14 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
                rsp->done(rsp);
        }
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
                id = raw_smp_processor_id();
-               if (id < LPFC_CHECK_CPU_CNT) {
-                       if (ctxp->cpu != id)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6704 CPU Check cmdcmpl: "
-                                               "cpu %d expect %d\n",
-                                               id, ctxp->cpu);
-                       phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_cmpl_io[id]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
+               if (ctxp->cpu != id)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6704 CPU Check cmdcmpl: "
+                                       "cpu %d expect %d\n",
+                                       id, ctxp->cpu);
        }
 #endif
 }
@@ -931,6 +929,9 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
        struct lpfc_sli_ring *pring;
        unsigned long iflags;
        int rc;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       int id;
+#endif
 
        if (phba->pport->load_flag & FC_UNLOADING) {
                rc = -ENODEV;
@@ -954,16 +955,14 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
        if (!ctxp->hdwq)
                ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid];
 
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
-               int id = raw_smp_processor_id();
-               if (id < LPFC_CHECK_CPU_CNT) {
-                       if (rsp->hwqid != id)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6705 CPU Check OP: "
-                                               "cpu %d expect %d\n",
-                                               id, rsp->hwqid);
-                       phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_xmt_io[id]++;
-               }
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
+               id = raw_smp_processor_id();
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
+               if (rsp->hwqid != id)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6705 CPU Check OP: "
+                                       "cpu %d expect %d\n",
+                                       id, rsp->hwqid);
                ctxp->cpu = id; /* Setup cpu for cmpl check */
        }
 #endif
@@ -2270,15 +2269,13 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
        size = nvmebuf->bytes_recv;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV) {
-               if (current_cpu < LPFC_CHECK_CPU_CNT) {
-                       if (idx != current_cpu)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6703 CPU Check rcv: "
-                                               "cpu %d expect %d\n",
-                                               current_cpu, idx);
-                       phba->sli4_hba.hdwq[idx].cpucheck_rcv_io[current_cpu]++;
-               }
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
+               this_cpu_inc(phba->sli4_hba.c_stat->rcv_io);
+               if (idx != current_cpu)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6703 CPU Check rcv: "
+                                       "cpu %d expect %d\n",
+                                       current_cpu, idx);
        }
 #endif
 
@@ -2598,7 +2595,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        union lpfc_wqe128 *wqe;
        struct ulp_bde64 *bde;
        dma_addr_t physaddr;
-       int i, cnt;
+       int i, cnt, nsegs;
        int do_pbde;
        int xc = 1;
 
@@ -2629,6 +2626,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                                phba->cfg_nvme_seg_cnt);
                return NULL;
        }
+       nsegs = rsp->sg_cnt;
 
        tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
        nvmewqe = ctxp->wqeq;
@@ -2868,7 +2866,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                wqe->fcp_trsp.rsvd_12_15[0] = 0;
 
                /* Use rspbuf, NOT sg list */
-               rsp->sg_cnt = 0;
+               nsegs = 0;
                sgl->word2 = 0;
                atomic_inc(&tgtp->xmt_fcp_rsp);
                break;
@@ -2885,7 +2883,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
        nvmewqe->context1 = ndlp;
 
-       for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) {
+       for_each_sg(rsp->sg, sgel, nsegs, i) {
                physaddr = sg_dma_address(sgel);
                cnt = sg_dma_len(sgel);
                sgl->addr_hi = putPaddrHigh(physaddr);
index 0fc9a24..ad62fb3 100644 (file)
@@ -3805,9 +3805,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        struct Scsi_Host *shost;
        int idx;
        uint32_t logit = LOG_FCP;
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       int cpu;
-#endif
 
        /* Guard against abort handler being called at same time */
        spin_lock(&lpfc_cmd->buf_lock);
@@ -3826,11 +3823,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
-               cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq)
-                       phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
-       }
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
 #endif
        shost = cmd->device->host;
 
@@ -4031,6 +4025,14 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        lpfc_cmd->pCmd = NULL;
        spin_unlock(&lpfc_cmd->buf_lock);
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       if (lpfc_cmd->ts_cmd_start) {
+               lpfc_cmd->ts_isr_cmpl = pIocbIn->isr_timestamp;
+               lpfc_cmd->ts_data_io = ktime_get_ns();
+               phba->ktime_last_cmd = lpfc_cmd->ts_data_io;
+               lpfc_io_ktime(phba, lpfc_cmd);
+       }
+#endif
        /* The sdev is not guaranteed to be valid post scsi_done upcall. */
        cmd->scsi_done(cmd);
 
@@ -4504,7 +4506,10 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
        struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
        int err, idx;
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       int cpu;
+       uint64_t start = 0L;
+
+       if (phba->ktime_on)
+               start = ktime_get_ns();
 #endif
 
        rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
@@ -4626,17 +4631,20 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
        lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
-               cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       struct lpfc_sli4_hdw_queue *hdwq =
-                                       &phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no];
-                       hdwq->cpucheck_xmt_io[cpu]++;
-               }
-       }
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
 #endif
        err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
                                  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       if (start) {
+               lpfc_cmd->ts_cmd_start = start;
+               lpfc_cmd->ts_last_cmd = phba->ktime_last_cmd;
+               lpfc_cmd->ts_cmd_wqput = ktime_get_ns();
+       } else {
+               lpfc_cmd->ts_cmd_start = 0;
+       }
+#endif
        if (err) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
                                 "3376 FCP could not issue IOCB err %x"
@@ -6023,31 +6031,6 @@ struct scsi_host_template lpfc_template_nvme = {
        .track_queue_depth      = 0,
 };
 
-struct scsi_host_template lpfc_template_no_hr = {
-       .module                 = THIS_MODULE,
-       .name                   = LPFC_DRIVER_NAME,
-       .proc_name              = LPFC_DRIVER_NAME,
-       .info                   = lpfc_info,
-       .queuecommand           = lpfc_queuecommand,
-       .eh_timed_out           = fc_eh_timed_out,
-       .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler = lpfc_device_reset_handler,
-       .eh_target_reset_handler = lpfc_target_reset_handler,
-       .eh_bus_reset_handler   = lpfc_bus_reset_handler,
-       .slave_alloc            = lpfc_slave_alloc,
-       .slave_configure        = lpfc_slave_configure,
-       .slave_destroy          = lpfc_slave_destroy,
-       .scan_finished          = lpfc_scan_finished,
-       .this_id                = -1,
-       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
-       .cmd_per_lun            = LPFC_CMD_PER_LUN,
-       .shost_attrs            = lpfc_hba_attrs,
-       .max_sectors            = 0xFFFFFFFF,
-       .vendor_id              = LPFC_NL_VENDOR_ID,
-       .change_queue_depth     = scsi_change_queue_depth,
-       .track_queue_depth      = 1,
-};
-
 struct scsi_host_template lpfc_template = {
        .module                 = THIS_MODULE,
        .name                   = LPFC_DRIVER_NAME,
@@ -6073,26 +6056,3 @@ struct scsi_host_template lpfc_template = {
        .change_queue_depth     = scsi_change_queue_depth,
        .track_queue_depth      = 1,
 };
-
-struct scsi_host_template lpfc_vport_template = {
-       .module                 = THIS_MODULE,
-       .name                   = LPFC_DRIVER_NAME,
-       .proc_name              = LPFC_DRIVER_NAME,
-       .info                   = lpfc_info,
-       .queuecommand           = lpfc_queuecommand,
-       .eh_timed_out           = fc_eh_timed_out,
-       .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler = lpfc_device_reset_handler,
-       .eh_target_reset_handler = lpfc_target_reset_handler,
-       .slave_alloc            = lpfc_slave_alloc,
-       .slave_configure        = lpfc_slave_configure,
-       .slave_destroy          = lpfc_slave_destroy,
-       .scan_finished          = lpfc_scan_finished,
-       .this_id                = -1,
-       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
-       .cmd_per_lun            = LPFC_CMD_PER_LUN,
-       .shost_attrs            = lpfc_vport_attrs,
-       .max_sectors            = 0xFFFF,
-       .change_queue_depth     = scsi_change_queue_depth,
-       .track_queue_depth      = 1,
-};
index 0b26b5c..b6fb665 100644 (file)
@@ -230,25 +230,16 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
  * This routine will update the HBA index of a queue to reflect consumption of
  * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
  * an entry the host calls this function to update the queue's internal
- * pointers. This routine returns the number of entries that were consumed by
- * the HBA.
+ * pointers.
  **/
-static uint32_t
+static void
 lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
 {
-       uint32_t released = 0;
-
        /* sanity check on queue memory */
        if (unlikely(!q))
-               return 0;
+               return;
 
-       if (q->hba_index == index)
-               return 0;
-       do {
-               q->hba_index = ((q->hba_index + 1) % q->entry_count);
-               released++;
-       } while (q->hba_index != index);
-       return released;
+       q->hba_index = index;
 }
 
 /**
@@ -2511,6 +2502,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
            !pmb->u.mb.mbxStatus) {
                rpi = pmb->u.mb.un.varWords[0];
                vpi = pmb->u.mb.un.varRegLogin.vpi;
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       vpi -= phba->sli4_hba.max_cfg_param.vpi_base;
                lpfc_unreg_login(phba, vpi, rpi, pmb);
                pmb->vport = vport;
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -4044,6 +4037,11 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
        struct lpfc_iocbq *piocb, *next_iocb;
 
        spin_lock_irq(&phba->hbalock);
+       if (phba->hba_flag & HBA_IOQ_FLUSH ||
+           !phba->sli4_hba.hdwq) {
+               spin_unlock_irq(&phba->hbalock);
+               return;
+       }
        /* Indicate the I/O queues are flushed */
        phba->hba_flag |= HBA_IOQ_FLUSH;
        spin_unlock_irq(&phba->hbalock);
@@ -5034,23 +5032,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
 
                } else
                        phba->max_vpi = 0;
-               phba->fips_level = 0;
-               phba->fips_spec_rev = 0;
-               if (pmb->u.mb.un.varCfgPort.gdss) {
-                       phba->sli3_options |= LPFC_SLI3_DSS_ENABLED;
-                       phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level;
-                       phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev;
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "2850 Security Crypto Active. FIPS x%d "
-                                       "(Spec Rev: x%d)",
-                                       phba->fips_level, phba->fips_spec_rev);
-               }
-               if (pmb->u.mb.un.varCfgPort.sec_err) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "2856 Config Port Security Crypto "
-                                       "Error: x%x ",
-                                       pmb->u.mb.un.varCfgPort.sec_err);
-               }
                if (pmb->u.mb.un.varCfgPort.gerbm)
                        phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
                if (pmb->u.mb.un.varCfgPort.gcrp)
@@ -14442,12 +14423,10 @@ static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq)
 {
        struct lpfc_hba *phba = eq->phba;
 
-       if (list_empty(&phba->poll_list)) {
-               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
-               /* kickstart slowpath processing for this eq */
+       /* kickstart slowpath processing if needed */
+       if (list_empty(&phba->poll_list))
                mod_timer(&phba->cpuhp_poll_timer,
                          jiffies + msecs_to_jiffies(LPFC_POLL_HB));
-       }
 
        list_add_rcu(&eq->_poll_list, &phba->poll_list);
        synchronize_rcu();
index 7bcf922..93d976e 100644 (file)
@@ -446,6 +446,6 @@ struct lpfc_io_buf {
        uint64_t ts_last_cmd;
        uint64_t ts_cmd_wqput;
        uint64_t ts_isr_cmpl;
-       uint64_t ts_data_nvme;
+       uint64_t ts_data_io;
 #endif
 };
index d963ca8..8da7429 100644 (file)
@@ -697,13 +697,6 @@ struct lpfc_sli4_hdw_queue {
        struct lpfc_lock_stat lock_conflict;
 #endif
 
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-#define LPFC_CHECK_CPU_CNT    128
-       uint32_t cpucheck_rcv_io[LPFC_CHECK_CPU_CNT];
-       uint32_t cpucheck_xmt_io[LPFC_CHECK_CPU_CNT];
-       uint32_t cpucheck_cmpl_io[LPFC_CHECK_CPU_CNT];
-#endif
-
        /* Per HDWQ pool resources */
        struct list_head sgl_list;
        struct list_head cmd_rsp_buf_list;
@@ -740,6 +733,15 @@ struct lpfc_sli4_hdw_queue {
 #define lpfc_qp_spin_lock(lock, qp, lstat) spin_lock(lock)
 #endif
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+struct lpfc_hdwq_stat {
+       u32 hdwq_no;
+       u32 rcv_io;
+       u32 xmt_io;
+       u32 cmpl_io;
+};
+#endif
+
 struct lpfc_sli4_hba {
        void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
                                           * config space registers
@@ -921,6 +923,9 @@ struct lpfc_sli4_hba {
        struct cpumask numa_mask;
        uint16_t curr_disp_cpu;
        struct lpfc_eq_intr_info __percpu *eq_info;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       struct lpfc_hdwq_stat __percpu *c_stat;
+#endif
        uint32_t conf_trunk;
 #define lpfc_conf_trunk_port0_WORD     conf_trunk
 #define lpfc_conf_trunk_port0_SHIFT    0
index c4ab006..ca40c47 100644 (file)
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "12.6.0.4"
+#define LPFC_DRIVER_VERSION "12.8.0.0"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 778d5e6..04a40af 100644 (file)
@@ -9908,8 +9908,8 @@ static void scsih_remove(struct pci_dev *pdev)
 
        ioc->remove_host = 1;
 
-       mpt3sas_wait_for_commands_to_complete(ioc);
-       _scsih_flush_running_cmds(ioc);
+       if (!pci_device_is_present(pdev))
+               _scsih_flush_running_cmds(ioc);
 
        _scsih_fw_event_cleanup_queue(ioc);
 
@@ -9992,8 +9992,8 @@ scsih_shutdown(struct pci_dev *pdev)
 
        ioc->remove_host = 1;
 
-       mpt3sas_wait_for_commands_to_complete(ioc);
-       _scsih_flush_running_cmds(ioc);
+       if (!pci_device_is_present(pdev))
+               _scsih_flush_running_cmds(ioc);
 
        _scsih_fw_event_cleanup_queue(ioc);
 
index 84e2a98..4886d24 100644 (file)
@@ -610,7 +610,6 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
 }
 
 static struct nvme_fc_port_template qla_nvme_fc_transport = {
-       .module = THIS_MODULE,
        .localport_delete = qla_nvme_localport_delete,
        .remoteport_delete = qla_nvme_remoteport_delete,
        .create_queue   = qla_nvme_alloc_queue,
index 0ec1b31..b2a803c 100644 (file)
@@ -2022,7 +2022,7 @@ static void __iscsi_unbind_session(struct work_struct *work)
        if (session->target_id == ISCSI_MAX_TARGET) {
                spin_unlock_irqrestore(&session->lock, flags);
                mutex_unlock(&ihost->mutex);
-               return;
+               goto unbind_session_exit;
        }
 
        target_id = session->target_id;
@@ -2034,6 +2034,8 @@ static void __iscsi_unbind_session(struct work_struct *work)
                ida_simple_remove(&iscsi_sess_ida, target_id);
 
        scsi_remove_target(&session->dev);
+
+unbind_session_exit:
        iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
        ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
 }
index 1c270e6..d2fe3fa 100644 (file)
@@ -550,10 +550,12 @@ out:
 static void sr_block_release(struct gendisk *disk, fmode_t mode)
 {
        struct scsi_cd *cd = scsi_cd(disk);
+
        mutex_lock(&cd->lock);
        cdrom_release(&cd->cdi, mode);
-       scsi_cd_put(cd);
        mutex_unlock(&cd->lock);
+
+       scsi_cd_put(cd);
 }
 
 static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
index 40a66b3..673c165 100644 (file)
@@ -499,8 +499,15 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 
        if (ufshcd_is_link_hibern8(hba)) {
                err = ufs_mtk_link_set_lpm(hba);
-               if (err)
+               if (err) {
+                       /*
+                        * Set link as off state enforcedly to trigger
+                        * ufshcd_host_reset_and_restore() in ufshcd_suspend()
+                        * for completed host reset.
+                        */
+                       ufshcd_set_link_off(hba);
                        return -EAGAIN;
+               }
        }
 
        if (!ufshcd_is_link_active(hba))
@@ -519,8 +526,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 
        if (ufshcd_is_link_hibern8(hba)) {
                err = ufs_mtk_link_set_hpm(hba);
-               if (err)
+               if (err) {
+                       err = ufshcd_link_recovery(hba);
                        return err;
+               }
        }
 
        return 0;
index e04e8b8..698e8d2 100644 (file)
@@ -172,19 +172,6 @@ enum {
 #define ufshcd_clear_eh_in_progress(h) \
        ((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS)
 
-#define ufshcd_set_ufs_dev_active(h) \
-       ((h)->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE)
-#define ufshcd_set_ufs_dev_sleep(h) \
-       ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
-#define ufshcd_set_ufs_dev_poweroff(h) \
-       ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
-#define ufshcd_is_ufs_dev_active(h) \
-       ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
-#define ufshcd_is_ufs_dev_sleep(h) \
-       ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
-#define ufshcd_is_ufs_dev_poweroff(h) \
-       ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
-
 struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
        {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
        {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
@@ -868,28 +855,29 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
                return false;
 }
 
-static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+/**
+ * ufshcd_set_clk_freq - set UFS controller clock frequencies
+ * @hba: per adapter instance
+ * @scale_up: If True, set max possible frequency othewise set low frequency
+ *
+ * Returns 0 if successful
+ * Returns < 0 for any other errors
+ */
+static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up)
 {
        int ret = 0;
        struct ufs_clk_info *clki;
        struct list_head *head = &hba->clk_list_head;
-       ktime_t start = ktime_get();
-       bool clk_state_changed = false;
 
        if (list_empty(head))
                goto out;
 
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
-       if (ret)
-               return ret;
-
        list_for_each_entry(clki, head, list) {
                if (!IS_ERR_OR_NULL(clki->clk)) {
                        if (scale_up && clki->max_freq) {
                                if (clki->curr_freq == clki->max_freq)
                                        continue;
 
-                               clk_state_changed = true;
                                ret = clk_set_rate(clki->clk, clki->max_freq);
                                if (ret) {
                                        dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
@@ -908,7 +896,6 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                if (clki->curr_freq == clki->min_freq)
                                        continue;
 
-                               clk_state_changed = true;
                                ret = clk_set_rate(clki->clk, clki->min_freq);
                                if (ret) {
                                        dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
@@ -927,11 +914,37 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                clki->name, clk_get_rate(clki->clk));
        }
 
+out:
+       return ret;
+}
+
+/**
+ * ufshcd_scale_clks - scale up or scale down UFS controller clocks
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns 0 if successful
+ * Returns < 0 for any other errors
+ */
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+       int ret = 0;
+       ktime_t start = ktime_get();
+
+       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+       if (ret)
+               goto out;
+
+       ret = ufshcd_set_clk_freq(hba, scale_up);
+       if (ret)
+               goto out;
+
        ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+       if (ret)
+               ufshcd_set_clk_freq(hba, !scale_up);
 
 out:
-       if (clk_state_changed)
-               trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+       trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
                        (scale_up ? "up" : "down"),
                        ktime_to_us(ktime_sub(ktime_get(), start)), ret);
        return ret;
@@ -1065,8 +1078,7 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
        }
 
        /* check if the power mode needs to be changed or not? */
-       ret = ufshcd_change_power_mode(hba, &new_pwr_info);
-
+       ret = ufshcd_config_pwr_mode(hba, &new_pwr_info);
        if (ret)
                dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d)",
                        __func__, ret,
@@ -1119,35 +1131,32 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
 
        ret = ufshcd_clock_scaling_prepare(hba);
        if (ret)
-               return ret;
+               goto out;
 
        /* scale down the gear before scaling down clocks */
        if (!scale_up) {
                ret = ufshcd_scale_gear(hba, false);
                if (ret)
-                       goto out;
+                       goto out_unprepare;
        }
 
        ret = ufshcd_scale_clks(hba, scale_up);
        if (ret) {
                if (!scale_up)
                        ufshcd_scale_gear(hba, true);
-               goto out;
+               goto out_unprepare;
        }
 
        /* scale up the gear after scaling up clocks */
        if (scale_up) {
                ret = ufshcd_scale_gear(hba, true);
-               if (ret) {
+               if (ret)
                        ufshcd_scale_clks(hba, false);
-                       goto out;
-               }
        }
 
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
-
-out:
+out_unprepare:
        ufshcd_clock_scaling_unprepare(hba);
+out:
        ufshcd_release(hba);
        return ret;
 }
@@ -3785,7 +3794,7 @@ out:
        return ret;
 }
 
-static int ufshcd_link_recovery(struct ufs_hba *hba)
+int ufshcd_link_recovery(struct ufs_hba *hba)
 {
        int ret;
        unsigned long flags;
@@ -3812,6 +3821,7 @@ static int ufshcd_link_recovery(struct ufs_hba *hba)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(ufshcd_link_recovery);
 
 static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
 {
@@ -4112,8 +4122,6 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba,
                memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
 
        ret = ufshcd_change_power_mode(hba, &final_params);
-       if (!ret)
-               ufshcd_print_pwr_info(hba);
 
        return ret;
 }
@@ -6299,7 +6307,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
        /* scale up clocks to max frequency before full reinitialization */
-       ufshcd_scale_clks(hba, true);
+       ufshcd_set_clk_freq(hba, true);
 
        err = ufshcd_hba_enable(hba);
        if (err)
@@ -7127,6 +7135,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
                                        __func__, ret);
                        goto out;
                }
+               ufshcd_print_pwr_info(hba);
        }
 
        /*
index dd1ee27..6ffc08a 100644 (file)
@@ -130,6 +130,19 @@ enum uic_link_state {
 #define ufshcd_set_link_hibern8(hba) ((hba)->uic_link_state = \
                                    UIC_LINK_HIBERN8_STATE)
 
+#define ufshcd_set_ufs_dev_active(h) \
+       ((h)->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE)
+#define ufshcd_set_ufs_dev_sleep(h) \
+       ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
+#define ufshcd_set_ufs_dev_poweroff(h) \
+       ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
+#define ufshcd_is_ufs_dev_active(h) \
+       ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
+#define ufshcd_is_ufs_dev_sleep(h) \
+       ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
+#define ufshcd_is_ufs_dev_poweroff(h) \
+       ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
+
 /*
  * UFS Power management levels.
  * Each level is in increasing order of power savings.
@@ -788,6 +801,7 @@ int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 void ufshcd_dealloc_host(struct ufs_hba *);
 int ufshcd_hba_enable(struct ufs_hba *hba);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
+int ufshcd_link_recovery(struct ufs_hba *hba);
 int ufshcd_make_hba_operational(struct ufs_hba *hba);
 void ufshcd_remove(struct ufs_hba *);
 int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
@@ -1083,6 +1097,7 @@ static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)
 {
        if (hba->vops && hba->vops->device_reset) {
                hba->vops->device_reset(hba);
+               ufshcd_set_ufs_dev_active(hba);
                ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, 0);
        }
 }
index 425c107..bd3ed6c 100644 (file)
@@ -134,7 +134,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
         * Assigned designator
         */
        desig_len = desc[7];
-       if (desig_len != 16) {
+       if (desig_len != XCOPY_NAA_IEEE_REGEX_LEN) {
                pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len);
                return -EINVAL;
        }
@@ -315,11 +315,6 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
                xop->nolb, (unsigned long long)xop->src_lba,
                (unsigned long long)xop->dst_lba);
 
-       if (dc != 0) {
-               xop->dbl = get_unaligned_be24(&desc[29]);
-
-               pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
-       }
        return 0;
 }
 
@@ -415,7 +410,8 @@ static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
        struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
                                struct xcopy_pt_cmd, se_cmd);
 
-       kfree(xpt_cmd);
+       /* xpt_cmd is on the stack, nothing to free here */
+       pr_debug("xpt_cmd done: %p\n", xpt_cmd);
 }
 
 static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd)
@@ -504,7 +500,6 @@ void target_xcopy_release_pt(void)
  * @cdb:        SCSI CDB to be copied into @xpt_cmd.
  * @remote_port: If false, use the LUN through which the XCOPY command has
  *              been received. If true, use @se_dev->xcopy_lun.
- * @alloc_mem:  Whether or not to allocate an SGL list.
  *
  * Set up a SCSI command (READ or WRITE) that will be used to execute an
  * XCOPY command.
@@ -514,12 +509,9 @@ static int target_xcopy_setup_pt_cmd(
        struct xcopy_op *xop,
        struct se_device *se_dev,
        unsigned char *cdb,
-       bool remote_port,
-       bool alloc_mem)
+       bool remote_port)
 {
        struct se_cmd *cmd = &xpt_cmd->se_cmd;
-       sense_reason_t sense_rc;
-       int ret = 0, rc;
 
        /*
         * Setup LUN+port to honor reservations based upon xop->op_origin for
@@ -535,46 +527,17 @@ static int target_xcopy_setup_pt_cmd(
        cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
 
        cmd->tag = 0;
-       sense_rc = target_setup_cmd_from_cdb(cmd, cdb);
-       if (sense_rc) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (target_setup_cmd_from_cdb(cmd, cdb))
+               return -EINVAL;
 
-       if (alloc_mem) {
-               rc = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
-                                     cmd->data_length, false, false);
-               if (rc < 0) {
-                       ret = rc;
-                       goto out;
-               }
-               /*
-                * Set this bit so that transport_free_pages() allows the
-                * caller to release SGLs + physical memory allocated by
-                * transport_generic_get_mem()..
-                */
-               cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-       } else {
-               /*
-                * Here the previously allocated SGLs for the internal READ
-                * are mapped zero-copy to the internal WRITE.
-                */
-               sense_rc = transport_generic_map_mem_to_cmd(cmd,
-                                       xop->xop_data_sg, xop->xop_data_nents,
-                                       NULL, 0);
-               if (sense_rc) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       if (transport_generic_map_mem_to_cmd(cmd, xop->xop_data_sg,
+                                       xop->xop_data_nents, NULL, 0))
+               return -EINVAL;
 
-               pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
-                        " %u\n", cmd->t_data_sg, cmd->t_data_nents);
-       }
+       pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
+                " %u\n", cmd->t_data_sg, cmd->t_data_nents);
 
        return 0;
-
-out:
-       return ret;
 }
 
 static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
@@ -604,20 +567,15 @@ static int target_xcopy_read_source(
        sector_t src_lba,
        u32 src_sectors)
 {
-       struct xcopy_pt_cmd *xpt_cmd;
-       struct se_cmd *se_cmd;
+       struct xcopy_pt_cmd xpt_cmd;
+       struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
        u32 length = (src_sectors * src_dev->dev_attrib.block_size);
        int rc;
        unsigned char cdb[16];
        bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP);
 
-       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
-       if (!xpt_cmd) {
-               pr_err("Unable to allocate xcopy_pt_cmd\n");
-               return -ENOMEM;
-       }
-       init_completion(&xpt_cmd->xpt_passthrough_sem);
-       se_cmd = &xpt_cmd->se_cmd;
+       memset(&xpt_cmd, 0, sizeof(xpt_cmd));
+       init_completion(&xpt_cmd.xpt_passthrough_sem);
 
        memset(&cdb[0], 0, 16);
        cdb[0] = READ_16;
@@ -627,36 +585,24 @@ static int target_xcopy_read_source(
                (unsigned long long)src_lba, src_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
-                             DMA_FROM_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
-       xop->src_pt_cmd = xpt_cmd;
+                             DMA_FROM_DEVICE, 0, &xpt_cmd.sense_buffer[0]);
 
-       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
-                               remote_port, true);
+       rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, src_dev, &cdb[0],
+                               remote_port);
        if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+               goto out;
        }
 
-       xop->xop_data_sg = se_cmd->t_data_sg;
-       xop->xop_data_nents = se_cmd->t_data_nents;
        pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ"
                " memory\n", xop->xop_data_sg, xop->xop_data_nents);
 
-       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
-       if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
-       }
-       /*
-        * Clear off the allocated t_data_sg, that has been saved for
-        * zero-copy WRITE submission reuse in struct xcopy_op..
-        */
-       se_cmd->t_data_sg = NULL;
-       se_cmd->t_data_nents = 0;
-
-       return 0;
+       rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
+       if (rc < 0)
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+out:
+       transport_generic_free_cmd(se_cmd, 0);
+       return rc;
 }
 
 static int target_xcopy_write_destination(
@@ -666,20 +612,15 @@ static int target_xcopy_write_destination(
        sector_t dst_lba,
        u32 dst_sectors)
 {
-       struct xcopy_pt_cmd *xpt_cmd;
-       struct se_cmd *se_cmd;
+       struct xcopy_pt_cmd xpt_cmd;
+       struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
        u32 length = (dst_sectors * dst_dev->dev_attrib.block_size);
        int rc;
        unsigned char cdb[16];
        bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP);
 
-       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
-       if (!xpt_cmd) {
-               pr_err("Unable to allocate xcopy_pt_cmd\n");
-               return -ENOMEM;
-       }
-       init_completion(&xpt_cmd->xpt_passthrough_sem);
-       se_cmd = &xpt_cmd->se_cmd;
+       memset(&xpt_cmd, 0, sizeof(xpt_cmd));
+       init_completion(&xpt_cmd.xpt_passthrough_sem);
 
        memset(&cdb[0], 0, 16);
        cdb[0] = WRITE_16;
@@ -689,36 +630,21 @@ static int target_xcopy_write_destination(
                (unsigned long long)dst_lba, dst_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
-                             DMA_TO_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
-       xop->dst_pt_cmd = xpt_cmd;
+                             DMA_TO_DEVICE, 0, &xpt_cmd.sense_buffer[0]);
 
-       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, dst_dev, &cdb[0],
-                               remote_port, false);
+       rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, dst_dev, &cdb[0],
+                               remote_port);
        if (rc < 0) {
-               struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               /*
-                * If the failure happened before the t_mem_list hand-off in
-                * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
-                * core releases this memory on error during X-COPY WRITE I/O.
-                */
-               src_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-               src_cmd->t_data_sg = xop->xop_data_sg;
-               src_cmd->t_data_nents = xop->xop_data_nents;
-
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
-       }
-
-       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
-       if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+               goto out;
        }
 
-       return 0;
+       rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
+       if (rc < 0)
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+out:
+       transport_generic_free_cmd(se_cmd, 0);
+       return rc;
 }
 
 static void target_xcopy_do_work(struct work_struct *work)
@@ -729,7 +655,7 @@ static void target_xcopy_do_work(struct work_struct *work)
        sector_t src_lba, dst_lba, end_lba;
        unsigned int max_sectors;
        int rc = 0;
-       unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0;
+       unsigned short nolb, max_nolb, copied_nolb = 0;
 
        if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE)
                goto err_free;
@@ -759,7 +685,23 @@ static void target_xcopy_do_work(struct work_struct *work)
                        (unsigned long long)src_lba, (unsigned long long)dst_lba);
 
        while (src_lba < end_lba) {
-               cur_nolb = min(nolb, max_nolb);
+               unsigned short cur_nolb = min(nolb, max_nolb);
+               u32 cur_bytes = cur_nolb * src_dev->dev_attrib.block_size;
+
+               if (cur_bytes != xop->xop_data_bytes) {
+                       /*
+                        * (Re)allocate a buffer large enough to hold the XCOPY
+                        * I/O size, which can be reused each read / write loop.
+                        */
+                       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
+                       rc = target_alloc_sgl(&xop->xop_data_sg,
+                                             &xop->xop_data_nents,
+                                             cur_bytes,
+                                             false, false);
+                       if (rc < 0)
+                               goto out;
+                       xop->xop_data_bytes = cur_bytes;
+               }
 
                pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu,"
                        " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb);
@@ -777,10 +719,8 @@ static void target_xcopy_do_work(struct work_struct *work)
 
                rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev,
                                                dst_lba, cur_nolb);
-               if (rc < 0) {
-                       transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
+               if (rc < 0)
                        goto out;
-               }
 
                dst_lba += cur_nolb;
                pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n",
@@ -788,14 +728,10 @@ static void target_xcopy_do_work(struct work_struct *work)
 
                copied_nolb += cur_nolb;
                nolb -= cur_nolb;
-
-               transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
-               xop->dst_pt_cmd->se_cmd.se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-
-               transport_generic_free_cmd(&xop->dst_pt_cmd->se_cmd, 0);
        }
 
        xcopy_pt_undepend_remotedev(xop);
+       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
        kfree(xop);
 
        pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n",
@@ -809,6 +745,7 @@ static void target_xcopy_do_work(struct work_struct *work)
 
 out:
        xcopy_pt_undepend_remotedev(xop);
+       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
 
 err_free:
        kfree(xop);
index 26ba4c3..c56a1bd 100644 (file)
@@ -5,7 +5,7 @@
 #define XCOPY_TARGET_DESC_LEN          32
 #define XCOPY_SEGMENT_DESC_LEN         28
 #define XCOPY_NAA_IEEE_REGEX_LEN       16
-#define XCOPY_MAX_SECTORS              1024
+#define XCOPY_MAX_SECTORS              4096
 
 /*
  * SPC4r37 6.4.6.1
@@ -18,8 +18,6 @@ enum xcopy_origin_list {
        XCOL_DEST_RECV_OP = 0x02,
 };
 
-struct xcopy_pt_cmd;
-
 struct xcopy_op {
        int op_origin;
 
@@ -35,11 +33,8 @@ struct xcopy_op {
        unsigned short stdi;
        unsigned short dtdi;
        unsigned short nolb;
-       unsigned int dbl;
-
-       struct xcopy_pt_cmd *src_pt_cmd;
-       struct xcopy_pt_cmd *dst_pt_cmd;
 
+       u32 xop_data_bytes;
        u32 xop_data_nents;
        struct scatterlist *xop_data_sg;
        struct work_struct xop_work;
index 8edef51..64df919 100644 (file)
@@ -53,37 +53,37 @@ static void evtchn_2l_bind_to_cpu(struct irq_info *info, unsigned cpu)
        set_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
 }
 
-static void evtchn_2l_clear_pending(unsigned port)
+static void evtchn_2l_clear_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_clear_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static void evtchn_2l_set_pending(unsigned port)
+static void evtchn_2l_set_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_set_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_is_pending(unsigned port)
+static bool evtchn_2l_is_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        return sync_test_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_test_and_set_mask(unsigned port)
+static bool evtchn_2l_test_and_set_mask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
 }
 
-static void evtchn_2l_mask(unsigned port)
+static void evtchn_2l_mask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_set_bit(port, BM(&s->evtchn_mask[0]));
 }
 
-static void evtchn_2l_unmask(unsigned port)
+static void evtchn_2l_unmask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        unsigned int cpu = get_cpu();
@@ -173,7 +173,7 @@ static void evtchn_2l_handle_events(unsigned cpu)
        /* Timer interrupt has highest priority. */
        irq = irq_from_virq(cpu, VIRQ_TIMER);
        if (irq != -1) {
-               unsigned int evtchn = evtchn_from_irq(irq);
+               evtchn_port_t evtchn = evtchn_from_irq(irq);
                word_idx = evtchn / BITS_PER_LONG;
                bit_idx = evtchn % BITS_PER_LONG;
                if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx))
@@ -228,7 +228,7 @@ static void evtchn_2l_handle_events(unsigned cpu)
 
                do {
                        xen_ulong_t bits;
-                       int port;
+                       evtchn_port_t port;
 
                        bits = MASK_LSBS(pending_bits, bit_idx);
 
index 499eff7..3a791c8 100644 (file)
@@ -116,7 +116,7 @@ static void clear_evtchn_to_irq_all(void)
        }
 }
 
-static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
+static int set_evtchn_to_irq(evtchn_port_t evtchn, unsigned int irq)
 {
        unsigned row;
        unsigned col;
@@ -143,7 +143,7 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
        return 0;
 }
 
-int get_evtchn_to_irq(unsigned evtchn)
+int get_evtchn_to_irq(evtchn_port_t evtchn)
 {
        if (evtchn >= xen_evtchn_max_channels())
                return -1;
@@ -162,7 +162,7 @@ struct irq_info *info_for_irq(unsigned irq)
 static int xen_irq_info_common_setup(struct irq_info *info,
                                     unsigned irq,
                                     enum xen_irq_type type,
-                                    unsigned evtchn,
+                                    evtchn_port_t evtchn,
                                     unsigned short cpu)
 {
        int ret;
@@ -184,7 +184,7 @@ static int xen_irq_info_common_setup(struct irq_info *info,
 }
 
 static int xen_irq_info_evtchn_setup(unsigned irq,
-                                    unsigned evtchn)
+                                    evtchn_port_t evtchn)
 {
        struct irq_info *info = info_for_irq(irq);
 
@@ -193,7 +193,7 @@ static int xen_irq_info_evtchn_setup(unsigned irq,
 
 static int xen_irq_info_ipi_setup(unsigned cpu,
                                  unsigned irq,
-                                 unsigned evtchn,
+                                 evtchn_port_t evtchn,
                                  enum ipi_vector ipi)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -207,7 +207,7 @@ static int xen_irq_info_ipi_setup(unsigned cpu,
 
 static int xen_irq_info_virq_setup(unsigned cpu,
                                   unsigned irq,
-                                  unsigned evtchn,
+                                  evtchn_port_t evtchn,
                                   unsigned virq)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -220,7 +220,7 @@ static int xen_irq_info_virq_setup(unsigned cpu,
 }
 
 static int xen_irq_info_pirq_setup(unsigned irq,
-                                  unsigned evtchn,
+                                  evtchn_port_t evtchn,
                                   unsigned pirq,
                                   unsigned gsi,
                                   uint16_t domid,
@@ -245,7 +245,7 @@ static void xen_irq_info_cleanup(struct irq_info *info)
 /*
  * Accessors for packed IRQ information.
  */
-unsigned int evtchn_from_irq(unsigned irq)
+evtchn_port_t evtchn_from_irq(unsigned irq)
 {
        if (WARN(irq >= nr_irqs, "Invalid irq %d!\n", irq))
                return 0;
@@ -253,7 +253,7 @@ unsigned int evtchn_from_irq(unsigned irq)
        return info_for_irq(irq)->evtchn;
 }
 
-unsigned irq_from_evtchn(unsigned int evtchn)
+unsigned int irq_from_evtchn(evtchn_port_t evtchn)
 {
        return get_evtchn_to_irq(evtchn);
 }
@@ -304,7 +304,7 @@ unsigned cpu_from_irq(unsigned irq)
        return info_for_irq(irq)->cpu;
 }
 
-unsigned int cpu_from_evtchn(unsigned int evtchn)
+unsigned int cpu_from_evtchn(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        unsigned ret = 0;
@@ -330,9 +330,9 @@ static bool pirq_needs_eoi_flag(unsigned irq)
        return info->u.pirq.flags & PIRQ_NEEDS_EOI;
 }
 
-static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+static void bind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int cpu)
 {
-       int irq = get_evtchn_to_irq(chn);
+       int irq = get_evtchn_to_irq(evtchn);
        struct irq_info *info = info_for_irq(irq);
 
        BUG_ON(irq == -1);
@@ -354,7 +354,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
  */
 void notify_remote_via_irq(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                notify_remote_via_evtchn(evtchn);
@@ -445,7 +445,7 @@ static void xen_free_irq(unsigned irq)
        irq_free_desc(irq);
 }
 
-static void xen_evtchn_close(unsigned int port)
+static void xen_evtchn_close(evtchn_port_t port)
 {
        struct evtchn_close close;
 
@@ -472,7 +472,7 @@ static void pirq_query_unmask(int irq)
 
 static void eoi_pirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
        struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
        int rc = 0;
 
@@ -508,7 +508,7 @@ static unsigned int __startup_pirq(unsigned int irq)
 {
        struct evtchn_bind_pirq bind_pirq;
        struct irq_info *info = info_for_irq(irq);
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        int rc;
 
        BUG_ON(info->type != IRQT_PIRQ);
@@ -561,7 +561,7 @@ static void shutdown_pirq(struct irq_data *data)
 {
        unsigned int irq = data->irq;
        struct irq_info *info = info_for_irq(irq);
-       unsigned evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        BUG_ON(info->type != IRQT_PIRQ);
 
@@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi);
 
 static void __unbind_from_irq(unsigned int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        struct irq_info *info = irq_get_handler_data(irq);
 
        if (info->refcnt > 0) {
@@ -827,7 +827,7 @@ int xen_pirq_from_irq(unsigned irq)
 }
 EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 
-int bind_evtchn_to_irq(unsigned int evtchn)
+int bind_evtchn_to_irq(evtchn_port_t evtchn)
 {
        int irq;
        int ret;
@@ -870,8 +870,8 @@ EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
-       int evtchn, irq;
-       int ret;
+       evtchn_port_t evtchn;
+       int ret, irq;
 
        mutex_lock(&irq_mapping_update_lock);
 
@@ -909,7 +909,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 }
 
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port)
+                                  evtchn_port_t remote_port)
 {
        struct evtchn_bind_interdomain bind_interdomain;
        int err;
@@ -924,10 +924,11 @@ int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
 }
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
 
-static int find_virq(unsigned int virq, unsigned int cpu)
+static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
 {
        struct evtchn_status status;
-       int port, rc = -ENOENT;
+       evtchn_port_t port;
+       int rc = -ENOENT;
 
        memset(&status, 0, sizeof(status));
        for (port = 0; port < xen_evtchn_max_channels(); port++) {
@@ -939,7 +940,7 @@ static int find_virq(unsigned int virq, unsigned int cpu)
                if (status.status != EVTCHNSTAT_virq)
                        continue;
                if (status.u.virq == virq && status.vcpu == xen_vcpu_nr(cpu)) {
-                       rc = port;
+                       *evtchn = port;
                        break;
                }
        }
@@ -962,7 +963,8 @@ EXPORT_SYMBOL_GPL(xen_evtchn_nr_channels);
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
 {
        struct evtchn_bind_virq bind_virq;
-       int evtchn, irq, ret;
+       evtchn_port_t evtchn = 0;
+       int irq, ret;
 
        mutex_lock(&irq_mapping_update_lock);
 
@@ -988,9 +990,8 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
                        evtchn = bind_virq.port;
                else {
                        if (ret == -EEXIST)
-                               ret = find_virq(virq, cpu);
+                               ret = find_virq(virq, cpu, &evtchn);
                        BUG_ON(ret < 0);
-                       evtchn = ret;
                }
 
                ret = xen_irq_info_virq_setup(cpu, irq, evtchn, virq);
@@ -1019,7 +1020,7 @@ static void unbind_from_irq(unsigned int irq)
        mutex_unlock(&irq_mapping_update_lock);
 }
 
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags,
                              const char *devname, void *dev_id)
@@ -1040,7 +1041,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
 
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
+                                         evtchn_port_t remote_port,
                                          irq_handler_t handler,
                                          unsigned long irqflags,
                                          const char *devname,
@@ -1132,7 +1133,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority)
 }
 EXPORT_SYMBOL_GPL(xen_set_irq_priority);
 
-int evtchn_make_refcounted(unsigned int evtchn)
+int evtchn_make_refcounted(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        struct irq_info *info;
@@ -1153,7 +1154,7 @@ int evtchn_make_refcounted(unsigned int evtchn)
 }
 EXPORT_SYMBOL_GPL(evtchn_make_refcounted);
 
-int evtchn_get(unsigned int evtchn)
+int evtchn_get(evtchn_port_t evtchn)
 {
        int irq;
        struct irq_info *info;
@@ -1186,7 +1187,7 @@ int evtchn_get(unsigned int evtchn)
 }
 EXPORT_SYMBOL_GPL(evtchn_get);
 
-void evtchn_put(unsigned int evtchn)
+void evtchn_put(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        if (WARN_ON(irq == -1))
@@ -1252,7 +1253,7 @@ void xen_hvm_evtchn_do_upcall(void)
 EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);
 
 /* Rebind a new event channel to an existing irq. */
-void rebind_evtchn_irq(int evtchn, int irq)
+void rebind_evtchn_irq(evtchn_port_t evtchn, int irq)
 {
        struct irq_info *info = info_for_irq(irq);
 
@@ -1284,7 +1285,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
 }
 
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
-static int xen_rebind_evtchn_to_cpu(int evtchn, unsigned int tcpu)
+static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
 {
        struct evtchn_bind_vcpu bind_vcpu;
        int masked;
@@ -1342,7 +1343,7 @@ EXPORT_SYMBOL_GPL(xen_set_affinity_evtchn);
 
 static void enable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                unmask_evtchn(evtchn);
@@ -1350,7 +1351,7 @@ static void enable_dynirq(struct irq_data *data)
 
 static void disable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                mask_evtchn(evtchn);
@@ -1358,7 +1359,7 @@ static void disable_dynirq(struct irq_data *data)
 
 static void ack_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (!VALID_EVTCHN(evtchn))
                return;
@@ -1385,7 +1386,7 @@ static void mask_ack_dynirq(struct irq_data *data)
 
 static int retrigger_dynirq(struct irq_data *data)
 {
-       unsigned int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
        int masked;
 
        if (!VALID_EVTCHN(evtchn))
@@ -1440,7 +1441,8 @@ static void restore_pirqs(void)
 static void restore_cpu_virqs(unsigned int cpu)
 {
        struct evtchn_bind_virq bind_virq;
-       int virq, irq, evtchn;
+       evtchn_port_t evtchn;
+       int virq, irq;
 
        for (virq = 0; virq < NR_VIRQS; virq++) {
                if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
@@ -1465,7 +1467,8 @@ static void restore_cpu_virqs(unsigned int cpu)
 static void restore_cpu_ipis(unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
-       int ipi, irq, evtchn;
+       evtchn_port_t evtchn;
+       int ipi, irq;
 
        for (ipi = 0; ipi < XEN_NR_IPIS; ipi++) {
                if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
@@ -1489,7 +1492,7 @@ static void restore_cpu_ipis(unsigned int cpu)
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                clear_evtchn(evtchn);
@@ -1497,7 +1500,7 @@ void xen_clear_irq_pending(int irq)
 EXPORT_SYMBOL(xen_clear_irq_pending);
 void xen_set_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                set_evtchn(evtchn);
@@ -1505,7 +1508,7 @@ void xen_set_irq_pending(int irq)
 
 bool xen_test_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        bool ret = false;
 
        if (VALID_EVTCHN(evtchn))
@@ -1667,7 +1670,7 @@ module_param(fifo_events, bool, 0);
 void __init xen_init_IRQ(void)
 {
        int ret = -EINVAL;
-       unsigned int evtchn;
+       evtchn_port_t evtchn;
 
        if (fifo_events)
                ret = xen_evtchn_fifo_init();
index 76b318e..c60ee04 100644 (file)
@@ -82,7 +82,7 @@ static unsigned event_array_pages __read_mostly;
 
 #endif
 
-static inline event_word_t *event_word_from_port(unsigned port)
+static inline event_word_t *event_word_from_port(evtchn_port_t port)
 {
        unsigned i = port / EVENT_WORDS_PER_PAGE;
 
@@ -140,7 +140,7 @@ static void init_array_page(event_word_t *array_page)
 
 static int evtchn_fifo_setup(struct irq_info *info)
 {
-       unsigned port = info->evtchn;
+       evtchn_port_t port = info->evtchn;
        unsigned new_array_pages;
        int ret;
 
@@ -191,37 +191,37 @@ static void evtchn_fifo_bind_to_cpu(struct irq_info *info, unsigned cpu)
        /* no-op */
 }
 
-static void evtchn_fifo_clear_pending(unsigned port)
+static void evtchn_fifo_clear_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_clear_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static void evtchn_fifo_set_pending(unsigned port)
+static void evtchn_fifo_set_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_set_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_is_pending(unsigned port)
+static bool evtchn_fifo_is_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_test_and_set_mask(unsigned port)
+static bool evtchn_fifo_test_and_set_mask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
 }
 
-static void evtchn_fifo_mask(unsigned port)
+static void evtchn_fifo_mask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
 }
 
-static bool evtchn_fifo_is_masked(unsigned port)
+static bool evtchn_fifo_is_masked(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
@@ -242,7 +242,7 @@ static void clear_masked(volatile event_word_t *word)
        } while (w != old);
 }
 
-static void evtchn_fifo_unmask(unsigned port)
+static void evtchn_fifo_unmask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
 
@@ -270,7 +270,7 @@ static uint32_t clear_linked(volatile event_word_t *word)
        return w & EVTCHN_FIFO_LINK_MASK;
 }
 
-static void handle_irq_for_port(unsigned port)
+static void handle_irq_for_port(evtchn_port_t port)
 {
        int irq;
 
@@ -286,7 +286,7 @@ static void consume_one_event(unsigned cpu,
 {
        struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
        uint32_t head;
-       unsigned port;
+       evtchn_port_t port;
        event_word_t *word;
 
        head = q->head[priority];
index 82938cf..10684fe 100644 (file)
@@ -33,7 +33,7 @@ struct irq_info {
        int refcnt;
        enum xen_irq_type type; /* type */
        unsigned irq;
-       unsigned int evtchn;    /* event channel */
+       evtchn_port_t evtchn;   /* event channel */
        unsigned short cpu;     /* cpu bound */
 
        union {
@@ -60,12 +60,12 @@ struct evtchn_ops {
        int (*setup)(struct irq_info *info);
        void (*bind_to_cpu)(struct irq_info *info, unsigned cpu);
 
-       void (*clear_pending)(unsigned port);
-       void (*set_pending)(unsigned port);
-       bool (*is_pending)(unsigned port);
-       bool (*test_and_set_mask)(unsigned port);
-       void (*mask)(unsigned port);
-       void (*unmask)(unsigned port);
+       void (*clear_pending)(evtchn_port_t port);
+       void (*set_pending)(evtchn_port_t port);
+       bool (*is_pending)(evtchn_port_t port);
+       bool (*test_and_set_mask)(evtchn_port_t port);
+       void (*mask)(evtchn_port_t port);
+       void (*unmask)(evtchn_port_t port);
 
        void (*handle_events)(unsigned cpu);
        void (*resume)(void);
@@ -74,11 +74,11 @@ struct evtchn_ops {
 extern const struct evtchn_ops *evtchn_ops;
 
 extern int **evtchn_to_irq;
-int get_evtchn_to_irq(unsigned int evtchn);
+int get_evtchn_to_irq(evtchn_port_t evtchn);
 
 struct irq_info *info_for_irq(unsigned irq);
 unsigned cpu_from_irq(unsigned irq);
-unsigned cpu_from_evtchn(unsigned int evtchn);
+unsigned int cpu_from_evtchn(evtchn_port_t evtchn);
 
 static inline unsigned xen_evtchn_max_channels(void)
 {
@@ -102,32 +102,32 @@ static inline void xen_evtchn_port_bind_to_cpu(struct irq_info *info,
        evtchn_ops->bind_to_cpu(info, cpu);
 }
 
-static inline void clear_evtchn(unsigned port)
+static inline void clear_evtchn(evtchn_port_t port)
 {
        evtchn_ops->clear_pending(port);
 }
 
-static inline void set_evtchn(unsigned port)
+static inline void set_evtchn(evtchn_port_t port)
 {
        evtchn_ops->set_pending(port);
 }
 
-static inline bool test_evtchn(unsigned port)
+static inline bool test_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->is_pending(port);
 }
 
-static inline bool test_and_set_mask(unsigned port)
+static inline bool test_and_set_mask(evtchn_port_t port)
 {
        return evtchn_ops->test_and_set_mask(port);
 }
 
-static inline void mask_evtchn(unsigned port)
+static inline void mask_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->mask(port);
 }
 
-static inline void unmask_evtchn(unsigned port)
+static inline void unmask_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->unmask(port);
 }
index 052b55a..6e0b1dd 100644 (file)
@@ -83,7 +83,7 @@ struct per_user_data {
 struct user_evtchn {
        struct rb_node node;
        struct per_user_data *user;
-       unsigned port;
+       evtchn_port_t port;
        bool enabled;
 };
 
@@ -138,7 +138,8 @@ static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
        kfree(evtchn);
 }
 
-static struct user_evtchn *find_evtchn(struct per_user_data *u, unsigned port)
+static struct user_evtchn *find_evtchn(struct per_user_data *u,
+                                      evtchn_port_t port)
 {
        struct rb_node *node = u->evtchns.rb_node;
 
@@ -163,7 +164,7 @@ static irqreturn_t evtchn_interrupt(int irq, void *data)
        struct per_user_data *u = evtchn->user;
 
        WARN(!evtchn->enabled,
-            "Interrupt for port %d, but apparently not enabled; per-user %p\n",
+            "Interrupt for port %u, but apparently not enabled; per-user %p\n",
             evtchn->port, u);
 
        disable_irq_nosync(irq);
@@ -286,7 +287,7 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
        mutex_lock(&u->bind_mutex);
 
        for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
-               unsigned port = kbuf[i];
+               evtchn_port_t port = kbuf[i];
                struct user_evtchn *evtchn;
 
                evtchn = find_evtchn(u, port);
@@ -361,7 +362,7 @@ static int evtchn_resize_ring(struct per_user_data *u)
        return 0;
 }
 
-static int evtchn_bind_to_user(struct per_user_data *u, int port)
+static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port)
 {
        struct user_evtchn *evtchn;
        struct evtchn_close close;
@@ -423,7 +424,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u,
 
 static DEFINE_PER_CPU(int, bind_last_selected_cpu);
 
-static void evtchn_bind_interdom_next_vcpu(int evtchn)
+static void evtchn_bind_interdom_next_vcpu(evtchn_port_t evtchn)
 {
        unsigned int selected_cpu, irq;
        struct irq_desc *desc;
index 9a3960e..20d7d05 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/mmu_notifier.h>
 #include <linux/types.h>
+#include <xen/interface/event_channel.h>
 
 struct gntdev_dmabuf_priv;
 
@@ -38,7 +39,7 @@ struct gntdev_unmap_notify {
        int flags;
        /* Address relative to the start of the gntdev_grant_map. */
        int addr;
-       int event;
+       evtchn_port_t event;
 };
 
 struct gntdev_grant_map {
index 0258415..50651e5 100644 (file)
@@ -652,7 +652,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
        struct gntdev_grant_map *map;
        int rc;
        int out_flags;
-       unsigned int out_event;
+       evtchn_port_t out_event;
 
        if (copy_from_user(&op, u, sizeof(op)))
                return -EFAULT;
index c57c71b..cf4ce3e 100644 (file)
@@ -300,7 +300,7 @@ static struct sock_mapping *pvcalls_new_active_socket(
                struct pvcalls_fedata *fedata,
                uint64_t id,
                grant_ref_t ref,
-               uint32_t evtchn,
+               evtchn_port_t evtchn,
                struct socket *sock)
 {
        int ret;
@@ -905,7 +905,8 @@ static irqreturn_t pvcalls_back_conn_event(int irq, void *sock_map)
 
 static int backend_connect(struct xenbus_device *dev)
 {
-       int err, evtchn;
+       int err;
+       evtchn_port_t evtchn;
        grant_ref_t ring_ref;
        struct pvcalls_fedata *fedata = NULL;
 
index 57592a6..b43b559 100644 (file)
@@ -368,12 +368,12 @@ out:
        return -ENOMEM;
 }
 
-static int create_active(struct sock_mapping *map, int *evtchn)
+static int create_active(struct sock_mapping *map, evtchn_port_t *evtchn)
 {
        void *bytes;
        int ret = -ENOMEM, irq = -1, i;
 
-       *evtchn = -1;
+       *evtchn = 0;
        init_waitqueue_head(&map->active.inflight_conn_req);
 
        bytes = map->active.data.in;
@@ -404,7 +404,7 @@ static int create_active(struct sock_mapping *map, int *evtchn)
        return 0;
 
 out_error:
-       if (*evtchn >= 0)
+       if (*evtchn > 0)
                xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
        return ret;
 }
@@ -415,7 +415,8 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
        struct pvcalls_bedata *bedata;
        struct sock_mapping *map = NULL;
        struct xen_pvcalls_request *req;
-       int notify, req_id, ret, evtchn;
+       int notify, req_id, ret;
+       evtchn_port_t evtchn;
 
        if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
                return -EOPNOTSUPP;
@@ -765,7 +766,8 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sock_mapping *map;
        struct sock_mapping *map2 = NULL;
        struct xen_pvcalls_request *req;
-       int notify, req_id, ret, evtchn, nonblock;
+       int notify, req_id, ret, nonblock;
+       evtchn_port_t evtchn;
 
        map = pvcalls_enter_sock(sock);
        if (IS_ERR(map))
@@ -1125,7 +1127,8 @@ static int pvcalls_front_remove(struct xenbus_device *dev)
 static int pvcalls_front_probe(struct xenbus_device *dev,
                          const struct xenbus_device_id *id)
 {
-       int ret = -ENOMEM, evtchn, i;
+       int ret = -ENOMEM, i;
+       evtchn_port_t evtchn;
        unsigned int max_page_order, function_calls, len;
        char *versions;
        grant_ref_t gref_head = 0;
index 833b2d2..f211558 100644 (file)
@@ -105,13 +105,13 @@ static void free_pdev(struct xen_pcibk_device *pdev)
 }
 
 static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
-                            int remote_evtchn)
+                            evtchn_port_t remote_evtchn)
 {
        int err = 0;
        void *vaddr;
 
        dev_dbg(&pdev->xdev->dev,
-               "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+               "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n",
                gnt_ref, remote_evtchn);
 
        err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr);
@@ -142,7 +142,8 @@ out:
 static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
 {
        int err = 0;
-       int gnt_ref, remote_evtchn;
+       int gnt_ref;
+       evtchn_port_t remote_evtchn;
        char *magic = NULL;
 
 
index ba0942e..75c0a2e 100644 (file)
@@ -854,7 +854,8 @@ unmap_page:
 static int scsiback_map(struct vscsibk_info *info)
 {
        struct xenbus_device *dev = info->dev;
-       unsigned int ring_ref, evtchn;
+       unsigned int ring_ref;
+       evtchn_port_t evtchn;
        int err;
 
        err = xenbus_gather(XBT_NIL, dev->otherend,
index 31eb822..3858432 100644 (file)
@@ -391,7 +391,7 @@ EXPORT_SYMBOL_GPL(xenbus_grant_ring);
  * error, the device will switch to XenbusStateClosing, and the error will be
  * saved in the store.
  */
-int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port)
 {
        struct evtchn_alloc_unbound alloc_unbound;
        int err;
@@ -414,7 +414,7 @@ EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
 /**
  * Free an existing event channel. Returns 0 on success or -errno on error.
  */
-int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port)
 {
        struct evtchn_close close;
        int err;
@@ -423,7 +423,7 @@ int xenbus_free_evtchn(struct xenbus_device *dev, int port)
 
        err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
        if (err)
-               xenbus_dev_error(dev, err, "freeing event channel %d", port);
+               xenbus_dev_error(dev, err, "freeing event channel %u", port);
 
        return err;
 }
index cc5cf22..4023c98 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kthread.h>
 #include <linux/rculist_nulls.h>
 #include <linux/fs_struct.h>
+#include <linux/task_work.h>
 
 #include "io-wq.h"
 
@@ -716,6 +717,9 @@ static int io_wq_manager(void *data)
        complete(&wq->done);
 
        while (!kthread_should_stop()) {
+               if (current->task_works)
+                       task_work_run();
+
                for_each_node(node) {
                        struct io_wqe *wqe = wq->wqes[node];
                        bool fork_worker[2] = { false, false };
@@ -738,6 +742,9 @@ static int io_wq_manager(void *data)
                schedule_timeout(HZ);
        }
 
+       if (current->task_works)
+               task_work_run();
+
        return 0;
 err:
        set_bit(IO_WQ_BIT_ERROR, &wq->state);
@@ -1124,3 +1131,8 @@ void io_wq_destroy(struct io_wq *wq)
        if (refcount_dec_and_test(&wq->use_refs))
                __io_wq_destroy(wq);
 }
+
+struct task_struct *io_wq_get_task(struct io_wq *wq)
+{
+       return wq->manager;
+}
index 3ee7356..5ba12de 100644 (file)
@@ -136,6 +136,8 @@ typedef bool (work_cancel_fn)(struct io_wq_work *, void *);
 enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
                                        void *data);
 
+struct task_struct *io_wq_get_task(struct io_wq *wq);
+
 #if defined(CONFIG_IO_WQ)
 extern void io_wq_worker_sleeping(struct task_struct *);
 extern void io_wq_worker_running(struct task_struct *);
index 358f97b..5190bfb 100644 (file)
@@ -186,14 +186,23 @@ struct fixed_file_table {
        struct file             **files;
 };
 
+struct fixed_file_ref_node {
+       struct percpu_ref               refs;
+       struct list_head                node;
+       struct list_head                file_list;
+       struct fixed_file_data          *file_data;
+       struct work_struct              work;
+};
+
 struct fixed_file_data {
        struct fixed_file_table         *table;
        struct io_ring_ctx              *ctx;
 
+       struct percpu_ref               *cur_refs;
        struct percpu_ref               refs;
-       struct llist_head               put_llist;
-       struct work_struct              ref_work;
        struct completion               done;
+       struct list_head                ref_list;
+       spinlock_t                      lock;
 };
 
 struct io_buffer {
@@ -317,6 +326,8 @@ struct io_ring_ctx {
                spinlock_t              inflight_lock;
                struct list_head        inflight_list;
        } ____cacheline_aligned_in_smp;
+
+       struct work_struct              exit_work;
 };
 
 /*
@@ -599,6 +610,7 @@ struct io_kiocb {
        };
 
        struct io_async_ctx             *io;
+       int                             cflags;
        bool                            needs_fixed_file;
        u8                              opcode;
 
@@ -606,10 +618,8 @@ struct io_kiocb {
        struct list_head        list;
        unsigned int            flags;
        refcount_t              refs;
-       union {
-               struct task_struct      *task;
-               unsigned long           fsize;
-       };
+       struct task_struct      *task;
+       unsigned long           fsize;
        u64                     user_data;
        u32                     result;
        u32                     sequence;
@@ -618,6 +628,8 @@ struct io_kiocb {
 
        struct list_head        inflight_entry;
 
+       struct percpu_ref       *fixed_file_refs;
+
        union {
                /*
                 * Only commands that never go async can use the below fields,
@@ -629,7 +641,6 @@ struct io_kiocb {
                        struct callback_head    task_work;
                        struct hlist_node       hash_node;
                        struct async_poll       *apoll;
-                       int                     cflags;
                };
                struct io_wq_work       work;
        };
@@ -848,7 +859,6 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                                 struct io_uring_files_update *ip,
                                 unsigned nr_args);
 static int io_grab_files(struct io_kiocb *req);
-static void io_ring_file_ref_flush(struct fixed_file_data *data);
 static void io_cleanup_req(struct io_kiocb *req);
 static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
                       int fd, struct file **out_file, bool fixed);
@@ -1285,8 +1295,8 @@ static struct io_kiocb *io_get_fallback_req(struct io_ring_ctx *ctx)
        return NULL;
 }
 
-static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
-                                  struct io_submit_state *state)
+static struct io_kiocb *io_alloc_req(struct io_ring_ctx *ctx,
+                                    struct io_submit_state *state)
 {
        gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
        struct io_kiocb *req;
@@ -1319,41 +1329,20 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
                req = state->reqs[state->free_reqs];
        }
 
-got_it:
-       req->io = NULL;
-       req->file = NULL;
-       req->ctx = ctx;
-       req->flags = 0;
-       /* one is dropped after submission, the other at completion */
-       refcount_set(&req->refs, 2);
-       req->result = 0;
-       INIT_IO_WORK(&req->work, io_wq_submit_work);
        return req;
 fallback:
-       req = io_get_fallback_req(ctx);
-       if (req)
-               goto got_it;
-       percpu_ref_put(&ctx->refs);
-       return NULL;
+       return io_get_fallback_req(ctx);
 }
 
 static inline void io_put_file(struct io_kiocb *req, struct file *file,
                          bool fixed)
 {
        if (fixed)
-               percpu_ref_put(&req->ctx->file_data->refs);
+               percpu_ref_put(req->fixed_file_refs);
        else
                fput(file);
 }
 
-static void __io_req_do_free(struct io_kiocb *req)
-{
-       if (likely(!io_is_fallback_req(req)))
-               kmem_cache_free(req_cachep, req);
-       else
-               clear_bit_unlock(0, (unsigned long *) req->ctx->fallback_req);
-}
-
 static void __io_req_aux_free(struct io_kiocb *req)
 {
        if (req->flags & REQ_F_NEED_CLEANUP)
@@ -1362,6 +1351,8 @@ static void __io_req_aux_free(struct io_kiocb *req)
        kfree(req->io);
        if (req->file)
                io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
+       if (req->task)
+               put_task_struct(req->task);
 
        io_req_work_drop_env(req);
 }
@@ -1382,7 +1373,10 @@ static void __io_free_req(struct io_kiocb *req)
        }
 
        percpu_ref_put(&req->ctx->refs);
-       __io_req_do_free(req);
+       if (likely(!io_is_fallback_req(req)))
+               kmem_cache_free(req_cachep, req);
+       else
+               clear_bit_unlock(0, (unsigned long *) req->ctx->fallback_req);
 }
 
 struct req_batch {
@@ -1393,21 +1387,18 @@ struct req_batch {
 
 static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb)
 {
-       int fixed_refs = rb->to_free;
-
        if (!rb->to_free)
                return;
        if (rb->need_iter) {
                int i, inflight = 0;
                unsigned long flags;
 
-               fixed_refs = 0;
                for (i = 0; i < rb->to_free; i++) {
                        struct io_kiocb *req = rb->reqs[i];
 
                        if (req->flags & REQ_F_FIXED_FILE) {
                                req->file = NULL;
-                               fixed_refs++;
+                               percpu_ref_put(req->fixed_file_refs);
                        }
                        if (req->flags & REQ_F_INFLIGHT)
                                inflight++;
@@ -1433,8 +1424,6 @@ static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb)
        }
 do_free:
        kmem_cache_free_bulk(req_cachep, rb->to_free, rb->reqs);
-       if (fixed_refs)
-               percpu_ref_put_many(&ctx->file_data->refs, fixed_refs);
        percpu_ref_put_many(&ctx->refs, rb->to_free);
        rb->to_free = rb->need_iter = 0;
 }
@@ -1738,11 +1727,24 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
        io_free_req_many(ctx, &rb);
 }
 
+static void io_iopoll_queue(struct list_head *again)
+{
+       struct io_kiocb *req;
+
+       do {
+               req = list_first_entry(again, struct io_kiocb, list);
+               list_del(&req->list);
+               refcount_inc(&req->refs);
+               io_queue_async_work(req);
+       } while (!list_empty(again));
+}
+
 static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                        long min)
 {
        struct io_kiocb *req, *tmp;
        LIST_HEAD(done);
+       LIST_HEAD(again);
        bool spin;
        int ret;
 
@@ -1757,9 +1759,9 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                struct kiocb *kiocb = &req->rw.kiocb;
 
                /*
-                * Move completed entries to our local list. If we find a
-                * request that requires polling, break out and complete
-                * the done list first, if we have entries there.
+                * Move completed and retryable entries to our local lists.
+                * If we find a request that requires polling, break out
+                * and complete those lists first, if we have entries there.
                 */
                if (req->flags & REQ_F_IOPOLL_COMPLETED) {
                        list_move_tail(&req->list, &done);
@@ -1768,6 +1770,13 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                if (!list_empty(&done))
                        break;
 
+               if (req->result == -EAGAIN) {
+                       list_move_tail(&req->list, &again);
+                       continue;
+               }
+               if (!list_empty(&again))
+                       break;
+
                ret = kiocb->ki_filp->f_op->iopoll(kiocb, spin);
                if (ret < 0)
                        break;
@@ -1780,6 +1789,9 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
        if (!list_empty(&done))
                io_iopoll_complete(ctx, nr_events, &done);
 
+       if (!list_empty(&again))
+               io_iopoll_queue(&again);
+
        return ret;
 }
 
@@ -2465,8 +2477,9 @@ static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
        req->io->rw.iov = iovec;
        if (!req->io->rw.iov) {
                req->io->rw.iov = req->io->rw.fast_iov;
-               memcpy(req->io->rw.iov, fast_iov,
-                       sizeof(struct iovec) * iter->nr_segs);
+               if (req->io->rw.iov != fast_iov)
+                       memcpy(req->io->rw.iov, fast_iov,
+                              sizeof(struct iovec) * iter->nr_segs);
        } else {
                req->flags |= REQ_F_NEED_CLEANUP;
        }
@@ -2920,7 +2933,7 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -2929,6 +2942,8 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        req->open.how.mode = READ_ONCE(sqe->len);
        fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
        req->open.how.flags = READ_ONCE(sqe->open_flags);
+       if (force_o_largefile())
+               req->open.how.flags |= O_LARGEFILE;
 
        req->open.filename = getname(fname);
        if (IS_ERR(req->open.filename)) {
@@ -2951,7 +2966,7 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -3305,7 +3320,7 @@ static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -3382,7 +3397,7 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (sqe->ioprio || sqe->off || sqe->addr || sqe->len ||
            sqe->rw_flags || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
 
        req->close.fd = READ_ONCE(sqe->fd);
@@ -3481,14 +3496,11 @@ static void __io_sync_file_range(struct io_kiocb *req)
 static void io_sync_file_range_finish(struct io_wq_work **workptr)
 {
        struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
 
        if (io_req_cancelled(req))
                return;
        __io_sync_file_range(req);
        io_put_req(req); /* put submission ref */
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
 }
 
 static int io_sync_file_range(struct io_kiocb *req, bool force_nonblock)
@@ -4114,6 +4126,7 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
                           __poll_t mask, task_work_func_t func)
 {
        struct task_struct *tsk;
+       int ret;
 
        /* for instances that support it check for an event match first: */
        if (mask && !(mask & poll->events))
@@ -4127,11 +4140,15 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
        req->result = mask;
        init_task_work(&req->task_work, func);
        /*
-        * If this fails, then the task is exiting. If that is the case, then
-        * the exit check will ultimately cancel these work items. Hence we
-        * don't need to check here and handle it specifically.
+        * If this fails, then the task is exiting. Punt to one of the io-wq
+        * threads to ensure the work gets run, we can't always rely on exit
+        * cancelation taking care of this.
         */
-       task_work_add(tsk, &req->task_work, true);
+       ret = task_work_add(tsk, &req->task_work, true);
+       if (unlikely(ret)) {
+               tsk = io_wq_get_task(req->ctx->io_wq);
+               task_work_add(tsk, &req->task_work, true);
+       }
        wake_up_process(tsk);
        return 1;
 }
@@ -4251,10 +4268,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req)
        req->flags |= REQ_F_POLLED;
        memcpy(&apoll->work, &req->work, sizeof(req->work));
 
-       /*
-        * Don't need a reference here, as we're adding it to the task
-        * task_works list. If the task exits, the list is pruned.
-        */
+       get_task_struct(current);
        req->task = current;
        req->apoll = apoll;
        INIT_HLIST_NODE(&req->hash_node);
@@ -4407,8 +4421,20 @@ static void io_poll_complete(struct io_kiocb *req, __poll_t mask, int error)
 static void io_poll_task_handler(struct io_kiocb *req, struct io_kiocb **nxt)
 {
        struct io_ring_ctx *ctx = req->ctx;
+       struct io_poll_iocb *poll = &req->poll;
+
+       if (!req->result && !READ_ONCE(poll->canceled)) {
+               struct poll_table_struct pt = { ._key = poll->events };
+
+               req->result = vfs_poll(req->file, &pt) & poll->events;
+       }
 
        spin_lock_irq(&ctx->completion_lock);
+       if (!req->result && !READ_ONCE(poll->canceled)) {
+               add_wait_queue(poll->head, &poll->wait);
+               spin_unlock_irq(&ctx->completion_lock);
+               return;
+       }
        hash_del(&req->hash_node);
        io_poll_complete(req, req->result, 0);
        req->flags |= REQ_F_COMP_LOCKED;
@@ -4465,10 +4491,7 @@ static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
        events = READ_ONCE(sqe->poll_events);
        poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP;
 
-       /*
-        * Don't need a reference here, as we're adding it to the task
-        * task_works list. If the task exits, the list is pruned.
-        */
+       get_task_struct(current);
        req->task = current;
        return 0;
 }
@@ -5331,7 +5354,8 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
                file = io_file_from_index(ctx, fd);
                if (!file)
                        return -EBADF;
-               percpu_ref_get(&ctx->file_data->refs);
+               req->fixed_file_refs = ctx->file_data->cur_refs;
+               percpu_ref_get(req->fixed_file_refs);
        } else {
                trace_io_uring_file_get(ctx, fd);
                file = __io_file_get(state, fd);
@@ -5344,15 +5368,10 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
 }
 
 static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
-                          const struct io_uring_sqe *sqe)
+                          int fd, unsigned int flags)
 {
-       unsigned flags;
-       int fd;
        bool fixed;
 
-       flags = READ_ONCE(sqe->flags);
-       fd = READ_ONCE(sqe->fd);
-
        if (!io_req_needs_file(req, fd))
                return 0;
 
@@ -5594,7 +5613,7 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 {
        struct io_ring_ctx *ctx = req->ctx;
        unsigned int sqe_flags;
-       int ret, id;
+       int ret, id, fd;
 
        sqe_flags = READ_ONCE(sqe->flags);
 
@@ -5625,7 +5644,8 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                        IOSQE_ASYNC | IOSQE_FIXED_FILE |
                                        IOSQE_BUFFER_SELECT);
 
-       ret = io_req_set_file(state, req, sqe);
+       fd = READ_ONCE(sqe->fd);
+       ret = io_req_set_file(state, req, fd, sqe_flags);
        if (unlikely(ret)) {
 err_req:
                io_cqring_add_event(req, ret);
@@ -5741,8 +5761,7 @@ static void io_commit_sqring(struct io_ring_ctx *ctx)
  * used, it's important that those reads are done through READ_ONCE() to
  * prevent a re-load down the line.
  */
-static bool io_get_sqring(struct io_ring_ctx *ctx, struct io_kiocb *req,
-                         const struct io_uring_sqe **sqe_ptr)
+static const struct io_uring_sqe *io_get_sqe(struct io_ring_ctx *ctx)
 {
        u32 *sq_array = ctx->sq_array;
        unsigned head;
@@ -5756,25 +5775,40 @@ static bool io_get_sqring(struct io_ring_ctx *ctx, struct io_kiocb *req,
         *    though the application is the one updating it.
         */
        head = READ_ONCE(sq_array[ctx->cached_sq_head & ctx->sq_mask]);
-       if (likely(head < ctx->sq_entries)) {
-               /*
-                * All io need record the previous position, if LINK vs DARIN,
-                * it can be used to mark the position of the first IO in the
-                * link list.
-                */
-               req->sequence = ctx->cached_sq_head;
-               *sqe_ptr = &ctx->sq_sqes[head];
-               req->opcode = READ_ONCE((*sqe_ptr)->opcode);
-               req->user_data = READ_ONCE((*sqe_ptr)->user_data);
-               ctx->cached_sq_head++;
-               return true;
-       }
+       if (likely(head < ctx->sq_entries))
+               return &ctx->sq_sqes[head];
 
        /* drop invalid entries */
-       ctx->cached_sq_head++;
        ctx->cached_sq_dropped++;
        WRITE_ONCE(ctx->rings->sq_dropped, ctx->cached_sq_dropped);
-       return false;
+       return NULL;
+}
+
+static inline void io_consume_sqe(struct io_ring_ctx *ctx)
+{
+       ctx->cached_sq_head++;
+}
+
+static void io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
+                       const struct io_uring_sqe *sqe)
+{
+       /*
+        * All io need record the previous position, if LINK vs DARIN,
+        * it can be used to mark the position of the first IO in the
+        * link list.
+        */
+       req->sequence = ctx->cached_sq_head;
+       req->opcode = READ_ONCE(sqe->opcode);
+       req->user_data = READ_ONCE(sqe->user_data);
+       req->io = NULL;
+       req->file = NULL;
+       req->ctx = ctx;
+       req->flags = 0;
+       /* one is dropped after submission, the other at completion */
+       refcount_set(&req->refs, 2);
+       req->task = NULL;
+       req->result = 0;
+       INIT_IO_WORK(&req->work, io_wq_submit_work);
 }
 
 static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
@@ -5812,17 +5846,20 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
                struct io_kiocb *req;
                int err;
 
-               req = io_get_req(ctx, statep);
+               sqe = io_get_sqe(ctx);
+               if (unlikely(!sqe)) {
+                       io_consume_sqe(ctx);
+                       break;
+               }
+               req = io_alloc_req(ctx, statep);
                if (unlikely(!req)) {
                        if (!submitted)
                                submitted = -EAGAIN;
                        break;
                }
-               if (!io_get_sqring(ctx, req, &sqe)) {
-                       __io_req_do_free(req);
-                       break;
-               }
 
+               io_init_req(ctx, req, sqe);
+               io_consume_sqe(ctx);
                /* will complete beyond this point, count as submitted */
                submitted++;
 
@@ -5962,6 +5999,7 @@ static int io_sq_thread(void *data)
                                }
                                if (current->task_works) {
                                        task_work_run();
+                                       finish_wait(&ctx->sqo_wait, &wait);
                                        continue;
                                }
                                if (signal_pending(current))
@@ -6124,43 +6162,36 @@ static void io_file_ref_kill(struct percpu_ref *ref)
        complete(&data->done);
 }
 
-static void io_file_ref_exit_and_free(struct work_struct *work)
-{
-       struct fixed_file_data *data;
-
-       data = container_of(work, struct fixed_file_data, ref_work);
-
-       /*
-        * Ensure any percpu-ref atomic switch callback has run, it could have
-        * been in progress when the files were being unregistered. Once
-        * that's done, we can safely exit and free the ref and containing
-        * data structure.
-        */
-       rcu_barrier();
-       percpu_ref_exit(&data->refs);
-       kfree(data);
-}
-
 static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 {
        struct fixed_file_data *data = ctx->file_data;
+       struct fixed_file_ref_node *ref_node = NULL;
        unsigned nr_tables, i;
+       unsigned long flags;
 
        if (!data)
                return -ENXIO;
 
-       percpu_ref_kill_and_confirm(&data->refs, io_file_ref_kill);
-       flush_work(&data->ref_work);
+       spin_lock_irqsave(&data->lock, flags);
+       if (!list_empty(&data->ref_list))
+               ref_node = list_first_entry(&data->ref_list,
+                               struct fixed_file_ref_node, node);
+       spin_unlock_irqrestore(&data->lock, flags);
+       if (ref_node)
+               percpu_ref_kill(&ref_node->refs);
+
+       percpu_ref_kill(&data->refs);
+
+       /* wait for all refs nodes to complete */
        wait_for_completion(&data->done);
-       io_ring_file_ref_flush(data);
 
        __io_sqe_files_unregister(ctx);
        nr_tables = DIV_ROUND_UP(ctx->nr_user_files, IORING_MAX_FILES_TABLE);
        for (i = 0; i < nr_tables; i++)
                kfree(data->table[i].files);
        kfree(data->table);
-       INIT_WORK(&data->ref_work, io_file_ref_exit_and_free);
-       queue_work(system_wq, &data->ref_work);
+       percpu_ref_exit(&data->refs);
+       kfree(data);
        ctx->file_data = NULL;
        ctx->nr_user_files = 0;
        return 0;
@@ -6204,13 +6235,6 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset)
        struct sk_buff *skb;
        int i, nr_files;
 
-       if (!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
-               unsigned long inflight = ctx->user->unix_inflight + nr;
-
-               if (inflight > task_rlimit(current, RLIMIT_NOFILE))
-                       return -EMFILE;
-       }
-
        fpl = kzalloc(sizeof(*fpl), GFP_KERNEL);
        if (!fpl)
                return -ENOMEM;
@@ -6385,46 +6409,72 @@ static void io_ring_file_put(struct io_ring_ctx *ctx, struct file *file)
 }
 
 struct io_file_put {
-       struct llist_node llist;
+       struct list_head list;
        struct file *file;
 };
 
-static void io_ring_file_ref_flush(struct fixed_file_data *data)
+static void io_file_put_work(struct work_struct *work)
 {
+       struct fixed_file_ref_node *ref_node;
+       struct fixed_file_data *file_data;
+       struct io_ring_ctx *ctx;
        struct io_file_put *pfile, *tmp;
-       struct llist_node *node;
+       unsigned long flags;
 
-       while ((node = llist_del_all(&data->put_llist)) != NULL) {
-               llist_for_each_entry_safe(pfile, tmp, node, llist) {
-                       io_ring_file_put(data->ctx, pfile->file);
-                       kfree(pfile);
-               }
+       ref_node = container_of(work, struct fixed_file_ref_node, work);
+       file_data = ref_node->file_data;
+       ctx = file_data->ctx;
+
+       list_for_each_entry_safe(pfile, tmp, &ref_node->file_list, list) {
+               list_del_init(&pfile->list);
+               io_ring_file_put(ctx, pfile->file);
+               kfree(pfile);
        }
+
+       spin_lock_irqsave(&file_data->lock, flags);
+       list_del_init(&ref_node->node);
+       spin_unlock_irqrestore(&file_data->lock, flags);
+
+       percpu_ref_exit(&ref_node->refs);
+       kfree(ref_node);
+       percpu_ref_put(&file_data->refs);
 }
 
-static void io_ring_file_ref_switch(struct work_struct *work)
+static void io_file_data_ref_zero(struct percpu_ref *ref)
 {
-       struct fixed_file_data *data;
+       struct fixed_file_ref_node *ref_node;
+
+       ref_node = container_of(ref, struct fixed_file_ref_node, refs);
 
-       data = container_of(work, struct fixed_file_data, ref_work);
-       io_ring_file_ref_flush(data);
-       percpu_ref_switch_to_percpu(&data->refs);
+       queue_work(system_wq, &ref_node->work);
 }
 
-static void io_file_data_ref_zero(struct percpu_ref *ref)
+static struct fixed_file_ref_node *alloc_fixed_file_ref_node(
+                       struct io_ring_ctx *ctx)
 {
-       struct fixed_file_data *data;
+       struct fixed_file_ref_node *ref_node;
 
-       data = container_of(ref, struct fixed_file_data, refs);
+       ref_node = kzalloc(sizeof(*ref_node), GFP_KERNEL);
+       if (!ref_node)
+               return ERR_PTR(-ENOMEM);
+
+       if (percpu_ref_init(&ref_node->refs, io_file_data_ref_zero,
+                           0, GFP_KERNEL)) {
+               kfree(ref_node);
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&ref_node->node);
+       INIT_LIST_HEAD(&ref_node->file_list);
+       INIT_WORK(&ref_node->work, io_file_put_work);
+       ref_node->file_data = ctx->file_data;
+       return ref_node;
 
-       /*
-        * We can't safely switch from inside this context, punt to wq. If
-        * the table ref is going away, the table is being unregistered.
-        * Don't queue up the async work for that case, the caller will
-        * handle it.
-        */
-       if (!percpu_ref_is_dying(&data->refs))
-               queue_work(system_wq, &data->ref_work);
+}
+
+static void destroy_fixed_file_ref_node(struct fixed_file_ref_node *ref_node)
+{
+       percpu_ref_exit(&ref_node->refs);
+       kfree(ref_node);
 }
 
 static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
@@ -6435,6 +6485,8 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
        struct file *file;
        int fd, ret = 0;
        unsigned i;
+       struct fixed_file_ref_node *ref_node;
+       unsigned long flags;
 
        if (ctx->file_data)
                return -EBUSY;
@@ -6448,6 +6500,8 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
                return -ENOMEM;
        ctx->file_data->ctx = ctx;
        init_completion(&ctx->file_data->done);
+       INIT_LIST_HEAD(&ctx->file_data->ref_list);
+       spin_lock_init(&ctx->file_data->lock);
 
        nr_tables = DIV_ROUND_UP(nr_args, IORING_MAX_FILES_TABLE);
        ctx->file_data->table = kcalloc(nr_tables,
@@ -6459,15 +6513,13 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
                return -ENOMEM;
        }
 
-       if (percpu_ref_init(&ctx->file_data->refs, io_file_data_ref_zero,
+       if (percpu_ref_init(&ctx->file_data->refs, io_file_ref_kill,
                                PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
                kfree(ctx->file_data->table);
                kfree(ctx->file_data);
                ctx->file_data = NULL;
                return -ENOMEM;
        }
-       ctx->file_data->put_llist.first = NULL;
-       INIT_WORK(&ctx->file_data->ref_work, io_ring_file_ref_switch);
 
        if (io_sqe_alloc_file_tables(ctx, nr_tables, nr_args)) {
                percpu_ref_exit(&ctx->file_data->refs);
@@ -6530,9 +6582,22 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
        }
 
        ret = io_sqe_files_scm(ctx);
-       if (ret)
+       if (ret) {
                io_sqe_files_unregister(ctx);
+               return ret;
+       }
+
+       ref_node = alloc_fixed_file_ref_node(ctx);
+       if (IS_ERR(ref_node)) {
+               io_sqe_files_unregister(ctx);
+               return PTR_ERR(ref_node);
+       }
 
+       ctx->file_data->cur_refs = &ref_node->refs;
+       spin_lock_irqsave(&ctx->file_data->lock, flags);
+       list_add(&ref_node->node, &ctx->file_data->ref_list);
+       spin_unlock_irqrestore(&ctx->file_data->lock, flags);
+       percpu_ref_get(&ctx->file_data->refs);
        return ret;
 }
 
@@ -6579,30 +6644,21 @@ static int io_sqe_file_register(struct io_ring_ctx *ctx, struct file *file,
 #endif
 }
 
-static void io_atomic_switch(struct percpu_ref *ref)
-{
-       struct fixed_file_data *data;
-
-       /*
-        * Juggle reference to ensure we hit zero, if needed, so we can
-        * switch back to percpu mode
-        */
-       data = container_of(ref, struct fixed_file_data, refs);
-       percpu_ref_put(&data->refs);
-       percpu_ref_get(&data->refs);
-}
-
 static int io_queue_file_removal(struct fixed_file_data *data,
-                                 struct file *file)
+                                struct file *file)
 {
        struct io_file_put *pfile;
+       struct percpu_ref *refs = data->cur_refs;
+       struct fixed_file_ref_node *ref_node;
 
        pfile = kzalloc(sizeof(*pfile), GFP_KERNEL);
        if (!pfile)
                return -ENOMEM;
 
+       ref_node = container_of(refs, struct fixed_file_ref_node, refs);
        pfile->file = file;
-       llist_add(&pfile->llist, &data->put_llist);
+       list_add(&pfile->list, &ref_node->file_list);
+
        return 0;
 }
 
@@ -6611,17 +6667,23 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                                 unsigned nr_args)
 {
        struct fixed_file_data *data = ctx->file_data;
-       bool ref_switch = false;
+       struct fixed_file_ref_node *ref_node;
        struct file *file;
        __s32 __user *fds;
        int fd, i, err;
        __u32 done;
+       unsigned long flags;
+       bool needs_switch = false;
 
        if (check_add_overflow(up->offset, nr_args, &done))
                return -EOVERFLOW;
        if (done > ctx->nr_user_files)
                return -EINVAL;
 
+       ref_node = alloc_fixed_file_ref_node(ctx);
+       if (IS_ERR(ref_node))
+               return PTR_ERR(ref_node);
+
        done = 0;
        fds = u64_to_user_ptr(up->fds);
        while (nr_args) {
@@ -6642,7 +6704,7 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                        if (err)
                                break;
                        table->files[index] = NULL;
-                       ref_switch = true;
+                       needs_switch = true;
                }
                if (fd != -1) {
                        file = fget(fd);
@@ -6673,11 +6735,19 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                up->offset++;
        }
 
-       if (ref_switch)
-               percpu_ref_switch_to_atomic(&data->refs, io_atomic_switch);
+       if (needs_switch) {
+               percpu_ref_kill(data->cur_refs);
+               spin_lock_irqsave(&data->lock, flags);
+               list_add(&ref_node->node, &data->ref_list);
+               data->cur_refs = &ref_node->refs;
+               spin_unlock_irqrestore(&data->lock, flags);
+               percpu_ref_get(&ctx->file_data->refs);
+       } else
+               destroy_fixed_file_ref_node(ref_node);
 
        return done ? done : err;
 }
+
 static int io_sqe_files_update(struct io_ring_ctx *ctx, void __user *arg,
                               unsigned nr_args)
 {
@@ -7203,6 +7273,18 @@ static int io_remove_personalities(int id, void *p, void *data)
        return 0;
 }
 
+static void io_ring_exit_work(struct work_struct *work)
+{
+       struct io_ring_ctx *ctx;
+
+       ctx = container_of(work, struct io_ring_ctx, exit_work);
+       if (ctx->rings)
+               io_cqring_overflow_flush(ctx, true);
+
+       wait_for_completion(&ctx->completions[0]);
+       io_ring_ctx_free(ctx);
+}
+
 static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
 {
        mutex_lock(&ctx->uring_lock);
@@ -7230,8 +7312,8 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
        if (ctx->rings)
                io_cqring_overflow_flush(ctx, true);
        idr_for_each(&ctx->personality_idr, io_remove_personalities, ctx);
-       wait_for_completion(&ctx->completions[0]);
-       io_ring_ctx_free(ctx);
+       INIT_WORK(&ctx->exit_work, io_ring_exit_work);
+       queue_work(system_wq, &ctx->exit_work);
 }
 
 static int io_uring_release(struct inode *inode, struct file *file)
index c740159..af375e0 100644 (file)
@@ -346,23 +346,8 @@ static ssize_t orangefs_file_read_iter(struct kiocb *iocb,
     struct iov_iter *iter)
 {
        int ret;
-       struct orangefs_read_options *ro;
-
        orangefs_stats.reads++;
 
-       /*
-        * Remember how they set "count" in read(2) or pread(2) or whatever -
-        * users can use count as a knob to control orangefs io size and later
-        * we can try to help them fill as many pages as possible in readpage.
-        */
-       if (!iocb->ki_filp->private_data) {
-               iocb->ki_filp->private_data = kmalloc(sizeof *ro, GFP_KERNEL);
-               if (!iocb->ki_filp->private_data)
-                       return(ENOMEM);
-               ro = iocb->ki_filp->private_data;
-               ro->blksiz = iter->count;
-       }
-
        down_read(&file_inode(iocb->ki_filp)->i_rwsem);
        ret = orangefs_revalidate_mapping(file_inode(iocb->ki_filp));
        if (ret)
@@ -650,12 +635,6 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
        return rc;
 }
 
-static int orangefs_file_open(struct inode * inode, struct file *file)
-{
-       file->private_data = NULL;
-       return generic_file_open(inode, file);
-}
-
 static int orangefs_flush(struct file *file, fl_owner_t id)
 {
        /*
@@ -666,19 +645,8 @@ static int orangefs_flush(struct file *file, fl_owner_t id)
         * on an explicit fsync call.  This duplicates historical OrangeFS
         * behavior.
         */
-       struct inode *inode = file->f_mapping->host;
        int r;
 
-       kfree(file->private_data);
-       file->private_data = NULL;
-
-       if (inode->i_state & I_DIRTY_TIME) {
-               spin_lock(&inode->i_lock);
-               inode->i_state &= ~I_DIRTY_TIME;
-               spin_unlock(&inode->i_lock);
-               mark_inode_dirty_sync(inode);
-       }
-
        r = filemap_write_and_wait_range(file->f_mapping, 0, LLONG_MAX);
        if (r > 0)
                return 0;
@@ -694,7 +662,7 @@ const struct file_operations orangefs_file_operations = {
        .lock           = orangefs_lock,
        .unlocked_ioctl = orangefs_ioctl,
        .mmap           = orangefs_file_mmap,
-       .open           = orangefs_file_open,
+       .open           = generic_file_open,
        .flush          = orangefs_flush,
        .release        = orangefs_file_release,
        .fsync          = orangefs_fsync,
index 961c0fd..12ae630 100644 (file)
@@ -259,46 +259,19 @@ static int orangefs_readpage(struct file *file, struct page *page)
        pgoff_t index; /* which page */
        struct page *next_page;
        char *kaddr;
-       struct orangefs_read_options *ro = file->private_data;
        loff_t read_size;
-       loff_t roundedup;
        int buffer_index = -1; /* orangefs shared memory slot */
        int slot_index;   /* index into slot */
        int remaining;
 
        /*
-        * If they set some miniscule size for "count" in read(2)
-        * (for example) then let's try to read a page, or the whole file
-        * if it is smaller than a page. Once "count" goes over a page
-        * then lets round up to the highest page size multiple that is
-        * less than or equal to "count" and do that much orangefs IO and
-        * try to fill as many pages as we can from it.
-        *
-        * "count" should be represented in ro->blksiz.
-        *
-        * inode->i_size = file size.
+        * Get up to this many bytes from Orangefs at a time and try
+        * to fill them into the page cache at once. Tests with dd made
+        * this seem like a reasonable static number, if there was
+        * interest perhaps this number could be made setable through
+        * sysfs...
         */
-       if (ro) {
-               if (ro->blksiz < PAGE_SIZE) {
-                       if (inode->i_size < PAGE_SIZE)
-                               read_size = inode->i_size;
-                       else
-                               read_size = PAGE_SIZE;
-               } else {
-                       roundedup = ((PAGE_SIZE - 1) & ro->blksiz) ?
-                               ((ro->blksiz + PAGE_SIZE) & ~(PAGE_SIZE -1)) :
-                               ro->blksiz;
-                       if (roundedup > inode->i_size)
-                               read_size = inode->i_size;
-                       else
-                               read_size = roundedup;
-
-               }
-       } else {
-               read_size = PAGE_SIZE;
-       }
-       if (!read_size)
-               read_size = PAGE_SIZE;
+       read_size = 524288;
 
        if (PageDirty(page))
                orangefs_launder_page(page);
index ed67f39..e12aeb9 100644 (file)
@@ -239,10 +239,6 @@ struct orangefs_write_range {
        kgid_t gid;
 };
 
-struct orangefs_read_options {
-       ssize_t blksiz;
-};
-
 extern struct orangefs_stats orangefs_stats;
 
 /*
index 74f948a..6042b64 100644 (file)
@@ -1839,9 +1839,9 @@ void proc_pid_evict_inode(struct proc_inode *ei)
        struct pid *pid = ei->pid;
 
        if (S_ISDIR(ei->vfs_inode.i_mode)) {
-               spin_lock(&pid->wait_pidfd.lock);
+               spin_lock(&pid->lock);
                hlist_del_init_rcu(&ei->sibling_inodes);
-               spin_unlock(&pid->wait_pidfd.lock);
+               spin_unlock(&pid->lock);
        }
 
        put_pid(pid);
@@ -1877,9 +1877,9 @@ struct inode *proc_pid_make_inode(struct super_block * sb,
        /* Let the pid remember us for quick removal */
        ei->pid = pid;
        if (S_ISDIR(mode)) {
-               spin_lock(&pid->wait_pidfd.lock);
+               spin_lock(&pid->lock);
                hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes);
-               spin_unlock(&pid->wait_pidfd.lock);
+               spin_unlock(&pid->lock);
        }
 
        task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
@@ -3273,7 +3273,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
 
 void proc_flush_pid(struct pid *pid)
 {
-       proc_invalidate_siblings_dcache(&pid->inodes, &pid->wait_pidfd.lock);
+       proc_invalidate_siblings_dcache(&pid->inodes, &pid->lock);
        put_pid(pid);
 }
 
index 00266de..c526c5e 100644 (file)
@@ -328,6 +328,38 @@ xfs_validate_sb_common(
                return -EFSCORRUPTED;
        }
 
+       /* Validate the realtime geometry; stolen from xfs_repair */
+       if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE ||
+           sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) {
+               xfs_notice(mp,
+                       "realtime extent sanity check failed");
+               return -EFSCORRUPTED;
+       }
+
+       if (sbp->sb_rblocks == 0) {
+               if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 ||
+                   sbp->sb_rextslog != 0 || sbp->sb_frextents != 0) {
+                       xfs_notice(mp,
+                               "realtime zeroed geometry check failed");
+                       return -EFSCORRUPTED;
+               }
+       } else {
+               uint64_t        rexts;
+               uint64_t        rbmblocks;
+
+               rexts = div_u64(sbp->sb_rblocks, sbp->sb_rextsize);
+               rbmblocks = howmany_64(sbp->sb_rextents,
+                                      NBBY * sbp->sb_blocksize);
+
+               if (sbp->sb_rextents != rexts ||
+                   sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) ||
+                   sbp->sb_rbmblocks != rbmblocks) {
+                       xfs_notice(mp,
+                               "realtime geometry sanity check failed");
+                       return -EFSCORRUPTED;
+               }
+       }
+
        if (sbp->sb_unit) {
                if (!xfs_sb_version_hasdalign(sbp) ||
                    sbp->sb_unit > sbp->sb_width ||
index f880141..9ec3eaf 100644 (file)
@@ -327,6 +327,9 @@ xfs_buf_free(
 
                        __free_page(page);
                }
+               if (current->reclaim_state)
+                       current->reclaim_state->reclaimed_slab +=
+                                                       bp->b_page_count;
        } else if (bp->b_flags & _XBF_KMEM)
                kmem_free(bp->b_addr);
        _xfs_buf_free_pages(bp);
@@ -2114,9 +2117,11 @@ xfs_buf_delwri_pushbuf(
 int __init
 xfs_buf_init(void)
 {
-       xfs_buf_zone = kmem_cache_create("xfs_buf",
-                                        sizeof(struct xfs_buf), 0,
-                                        SLAB_HWCACHE_ALIGN, NULL);
+       xfs_buf_zone = kmem_cache_create("xfs_buf", sizeof(struct xfs_buf), 0,
+                                        SLAB_HWCACHE_ALIGN |
+                                        SLAB_RECLAIM_ACCOUNT |
+                                        SLAB_MEM_SPREAD,
+                                        NULL);
        if (!xfs_buf_zone)
                goto out;
 
index 711376c..af2c8e5 100644 (file)
@@ -1105,8 +1105,8 @@ xfs_qm_dqflush(
         * Get the buffer containing the on-disk dquot
         */
        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
-                                  mp->m_quotainfo->qi_dqchunklen, 0, &bp,
-                                  &xfs_dquot_buf_ops);
+                                  mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK,
+                                  &bp, &xfs_dquot_buf_ops);
        if (error)
                goto out_unlock;
 
@@ -1177,7 +1177,7 @@ xfs_qm_dqflush(
 
 out_unlock:
        xfs_dqfunlock(dqp);
-       return -EIO;
+       return error;
 }
 
 /*
index cf65e2e..baad174 100644 (file)
@@ -189,7 +189,8 @@ xfs_qm_dquot_logitem_push(
                if (!xfs_buf_delwri_queue(bp, buffer_list))
                        rval = XFS_ITEM_FLUSHING;
                xfs_buf_relse(bp);
-       }
+       } else if (error == -EAGAIN)
+               rval = XFS_ITEM_LOCKED;
 
        spin_lock(&lip->li_ailp->ail_lock);
 out_unlock:
index f1372f9..5a4b011 100644 (file)
@@ -15,7 +15,6 @@
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
 #include "xfs_icache.h"
-#include "xfs_log.h"
 #include "xfs_pnfs.h"
 
 /*
@@ -221,18 +220,7 @@ STATIC int
 xfs_fs_nfs_commit_metadata(
        struct inode            *inode)
 {
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_lsn_t               lsn = 0;
-
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       if (xfs_ipincount(ip))
-               lsn = ip->i_itemp->ili_last_lsn;
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       if (!lsn)
-               return 0;
-       return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+       return xfs_log_force_inode(XFS_I(inode));
 }
 
 const struct export_operations xfs_export_operations = {
index b8a4a3f..4b8bdec 100644 (file)
@@ -80,19 +80,9 @@ xfs_dir_fsync(
        int                     datasync)
 {
        struct xfs_inode        *ip = XFS_I(file->f_mapping->host);
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_lsn_t               lsn = 0;
 
        trace_xfs_dir_fsync(ip);
-
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       if (xfs_ipincount(ip))
-               lsn = ip->i_itemp->ili_last_lsn;
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       if (!lsn)
-               return 0;
-       return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+       return xfs_log_force_inode(ip);
 }
 
 STATIC int
@@ -1069,7 +1059,11 @@ xfs_file_remap_range(
 
        ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize,
                        remap_flags);
+       if (ret)
+               goto out_unlock;
 
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
+               xfs_log_force_inode(dest);
 out_unlock:
        xfs_reflink_remap_unlock(file_in, file_out);
        if (ret)
index 14b922f..d177278 100644 (file)
@@ -1200,8 +1200,7 @@ xfs_create(
        unlock_dp_on_error = false;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-                                  resblks ?
-                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+                                       resblks - XFS_IALLOC_SPACE_RES(mp));
        if (error) {
                ASSERT(error != -ENOSPC);
                goto out_trans_cancel;
@@ -2504,6 +2503,88 @@ out:
 }
 
 /*
+ * Look up the inode number specified and mark it stale if it is found. If it is
+ * dirty, return the inode so it can be attached to the cluster buffer so it can
+ * be processed appropriately when the cluster free transaction completes.
+ */
+static struct xfs_inode *
+xfs_ifree_get_one_inode(
+       struct xfs_perag        *pag,
+       struct xfs_inode        *free_ip,
+       xfs_ino_t               inum)
+{
+       struct xfs_mount        *mp = pag->pag_mount;
+       struct xfs_inode        *ip;
+
+retry:
+       rcu_read_lock();
+       ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, inum));
+
+       /* Inode not in memory, nothing to do */
+       if (!ip)
+               goto out_rcu_unlock;
+
+       /*
+        * because this is an RCU protected lookup, we could find a recently
+        * freed or even reallocated inode during the lookup. We need to check
+        * under the i_flags_lock for a valid inode here. Skip it if it is not
+        * valid, the wrong inode or stale.
+        */
+       spin_lock(&ip->i_flags_lock);
+       if (ip->i_ino != inum || __xfs_iflags_test(ip, XFS_ISTALE)) {
+               spin_unlock(&ip->i_flags_lock);
+               goto out_rcu_unlock;
+       }
+       spin_unlock(&ip->i_flags_lock);
+
+       /*
+        * Don't try to lock/unlock the current inode, but we _cannot_ skip the
+        * other inodes that we did not find in the list attached to the buffer
+        * and are not already marked stale. If we can't lock it, back off and
+        * retry.
+        */
+       if (ip != free_ip) {
+               if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
+                       rcu_read_unlock();
+                       delay(1);
+                       goto retry;
+               }
+
+               /*
+                * Check the inode number again in case we're racing with
+                * freeing in xfs_reclaim_inode().  See the comments in that
+                * function for more information as to why the initial check is
+                * not sufficient.
+                */
+               if (ip->i_ino != inum) {
+                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+                       goto out_rcu_unlock;
+               }
+       }
+       rcu_read_unlock();
+
+       xfs_iflock(ip);
+       xfs_iflags_set(ip, XFS_ISTALE);
+
+       /*
+        * We don't need to attach clean inodes or those only with unlogged
+        * changes (which we throw away, anyway).
+        */
+       if (!ip->i_itemp || xfs_inode_clean(ip)) {
+               ASSERT(ip != free_ip);
+               xfs_ifunlock(ip);
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               goto out_no_inode;
+       }
+       return ip;
+
+out_rcu_unlock:
+       rcu_read_unlock();
+out_no_inode:
+       return NULL;
+}
+
+/*
  * A big issue when freeing the inode cluster is that we _cannot_ skip any
  * inodes that are in memory - they all must be marked stale and attached to
  * the cluster buffer.
@@ -2603,77 +2684,11 @@ xfs_ifree_cluster(
                 * even trying to lock them.
                 */
                for (i = 0; i < igeo->inodes_per_cluster; i++) {
-retry:
-                       rcu_read_lock();
-                       ip = radix_tree_lookup(&pag->pag_ici_root,
-                                       XFS_INO_TO_AGINO(mp, (inum + i)));
-
-                       /* Inode not in memory, nothing to do */
-                       if (!ip) {
-                               rcu_read_unlock();
+                       ip = xfs_ifree_get_one_inode(pag, free_ip, inum + i);
+                       if (!ip)
                                continue;
-                       }
-
-                       /*
-                        * because this is an RCU protected lookup, we could
-                        * find a recently freed or even reallocated inode
-                        * during the lookup. We need to check under the
-                        * i_flags_lock for a valid inode here. Skip it if it
-                        * is not valid, the wrong inode or stale.
-                        */
-                       spin_lock(&ip->i_flags_lock);
-                       if (ip->i_ino != inum + i ||
-                           __xfs_iflags_test(ip, XFS_ISTALE)) {
-                               spin_unlock(&ip->i_flags_lock);
-                               rcu_read_unlock();
-                               continue;
-                       }
-                       spin_unlock(&ip->i_flags_lock);
-
-                       /*
-                        * Don't try to lock/unlock the current inode, but we
-                        * _cannot_ skip the other inodes that we did not find
-                        * in the list attached to the buffer and are not
-                        * already marked stale. If we can't lock it, back off
-                        * and retry.
-                        */
-                       if (ip != free_ip) {
-                               if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
-                                       rcu_read_unlock();
-                                       delay(1);
-                                       goto retry;
-                               }
-
-                               /*
-                                * Check the inode number again in case we're
-                                * racing with freeing in xfs_reclaim_inode().
-                                * See the comments in that function for more
-                                * information as to why the initial check is
-                                * not sufficient.
-                                */
-                               if (ip->i_ino != inum + i) {
-                                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                                       rcu_read_unlock();
-                                       continue;
-                               }
-                       }
-                       rcu_read_unlock();
-
-                       xfs_iflock(ip);
-                       xfs_iflags_set(ip, XFS_ISTALE);
 
-                       /*
-                        * we don't need to attach clean inodes or those only
-                        * with unlogged changes (which we throw away, anyway).
-                        */
                        iip = ip->i_itemp;
-                       if (!iip || xfs_inode_clean(ip)) {
-                               ASSERT(ip != free_ip);
-                               xfs_ifunlock(ip);
-                               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                               continue;
-                       }
-
                        iip->ili_last_fields = iip->ili_fields;
                        iip->ili_fields = 0;
                        iip->ili_fsync_fields = 0;
@@ -3930,3 +3945,22 @@ xfs_irele(
        trace_xfs_irele(ip, _RET_IP_);
        iput(VFS_I(ip));
 }
+
+/*
+ * Ensure all commited transactions touching the inode are written to the log.
+ */
+int
+xfs_log_force_inode(
+       struct xfs_inode        *ip)
+{
+       xfs_lsn_t               lsn = 0;
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       if (xfs_ipincount(ip))
+               lsn = ip->i_itemp->ili_last_lsn;
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+
+       if (!lsn)
+               return 0;
+       return xfs_log_force_lsn(ip->i_mount, lsn, XFS_LOG_SYNC, NULL);
+}
index 492e539..c6a63f6 100644 (file)
@@ -426,6 +426,7 @@ int         xfs_itruncate_extents_flags(struct xfs_trans **,
                                struct xfs_inode *, int, xfs_fsize_t, int);
 void           xfs_iext_realloc(xfs_inode_t *, int, int);
 
+int            xfs_log_force_inode(struct xfs_inode *ip);
 void           xfs_iunpin_wait(xfs_inode_t *);
 #define xfs_ipincount(ip)      ((unsigned int) atomic_read(&ip->i_pincount))
 
index 4a3d13d..f779cca 100644 (file)
@@ -552,7 +552,8 @@ xfs_inode_item_push(
                if (!xfs_buf_delwri_queue(bp, buffer_list))
                        rval = XFS_ITEM_FLUSHING;
                xfs_buf_relse(bp);
-       }
+       } else if (error == -EAGAIN)
+               rval = XFS_ITEM_LOCKED;
 
        spin_lock(&lip->li_ailp->ail_lock);
 out_unlock:
@@ -730,29 +731,27 @@ xfs_iflush_done(
         * holding the lock before removing the inode from the AIL.
         */
        if (need_ail) {
-               bool                    mlip_changed = false;
+               xfs_lsn_t       tail_lsn = 0;
 
                /* this is an opencoded batch version of xfs_trans_ail_delete */
                spin_lock(&ailp->ail_lock);
                list_for_each_entry(blip, &tmp, li_bio_list) {
                        if (INODE_ITEM(blip)->ili_logged &&
-                           blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn)
-                               mlip_changed |= xfs_ail_delete_one(ailp, blip);
-                       else {
+                           blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn) {
+                               /*
+                                * xfs_ail_update_finish() only cares about the
+                                * lsn of the first tail item removed, any
+                                * others will be at the same or higher lsn so
+                                * we just ignore them.
+                                */
+                               xfs_lsn_t lsn = xfs_ail_delete_one(ailp, blip);
+                               if (!tail_lsn && lsn)
+                                       tail_lsn = lsn;
+                       } else {
                                xfs_clear_li_failed(blip);
                        }
                }
-
-               if (mlip_changed) {
-                       if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
-                               xlog_assign_tail_lsn_locked(ailp->ail_mount);
-                       if (list_empty(&ailp->ail_head))
-                               wake_up_all(&ailp->ail_empty);
-               }
-               spin_unlock(&ailp->ail_lock);
-
-               if (mlip_changed)
-                       xfs_log_space_wake(ailp->ail_mount);
+               xfs_ail_update_finish(ailp, tail_lsn);
        }
 
        /*
index 4a53768..00fda2e 100644 (file)
 kmem_zone_t    *xfs_log_ticket_zone;
 
 /* Local miscellaneous function prototypes */
-STATIC int
-xlog_commit_record(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket,
-       struct xlog_in_core     **iclog,
-       xfs_lsn_t               *commitlsnp);
-
 STATIC struct xlog *
 xlog_alloc_log(
        struct xfs_mount        *mp,
@@ -66,14 +59,6 @@ xlog_grant_push_ail(
        struct xlog             *log,
        int                     need_bytes);
 STATIC void
-xlog_regrant_reserve_log_space(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket);
-STATIC void
-xlog_ungrant_log_space(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket);
-STATIC void
 xlog_sync(
        struct xlog             *log,
        struct xlog_in_core     *iclog);
@@ -478,73 +463,6 @@ out_error:
        return error;
 }
 
-
-/*
- * NOTES:
- *
- *     1. currblock field gets updated at startup and after in-core logs
- *             marked as with WANT_SYNC.
- */
-
-/*
- * This routine is called when a user of a log manager ticket is done with
- * the reservation.  If the ticket was ever used, then a commit record for
- * the associated transaction is written out as a log operation header with
- * no data.  The flag XLOG_TIC_INITED is set when the first write occurs with
- * a given ticket.  If the ticket was one with a permanent reservation, then
- * a few operations are done differently.  Permanent reservation tickets by
- * default don't release the reservation.  They just commit the current
- * transaction with the belief that the reservation is still needed.  A flag
- * must be passed in before permanent reservations are actually released.
- * When these type of tickets are not released, they need to be set into
- * the inited state again.  By doing this, a start record will be written
- * out when the next write occurs.
- */
-xfs_lsn_t
-xfs_log_done(
-       struct xfs_mount        *mp,
-       struct xlog_ticket      *ticket,
-       struct xlog_in_core     **iclog,
-       bool                    regrant)
-{
-       struct xlog             *log = mp->m_log;
-       xfs_lsn_t               lsn = 0;
-
-       if (XLOG_FORCED_SHUTDOWN(log) ||
-           /*
-            * If nothing was ever written, don't write out commit record.
-            * If we get an error, just continue and give back the log ticket.
-            */
-           (((ticket->t_flags & XLOG_TIC_INITED) == 0) &&
-            (xlog_commit_record(log, ticket, iclog, &lsn)))) {
-               lsn = (xfs_lsn_t) -1;
-               regrant = false;
-       }
-
-
-       if (!regrant) {
-               trace_xfs_log_done_nonperm(log, ticket);
-
-               /*
-                * Release ticket if not permanent reservation or a specific
-                * request has been made to release a permanent reservation.
-                */
-               xlog_ungrant_log_space(log, ticket);
-       } else {
-               trace_xfs_log_done_perm(log, ticket);
-
-               xlog_regrant_reserve_log_space(log, ticket);
-               /* If this ticket was a permanent reservation and we aren't
-                * trying to release it, reset the inited flags; so next time
-                * we write, a start record will be written out.
-                */
-               ticket->t_flags |= XLOG_TIC_INITED;
-       }
-
-       xfs_log_ticket_put(ticket);
-       return lsn;
-}
-
 static bool
 __xlog_state_release_iclog(
        struct xlog             *log,
@@ -869,32 +787,44 @@ xlog_wait_on_iclog(
 }
 
 /*
- * Final log writes as part of unmount.
- *
- * Mark the filesystem clean as unmount happens.  Note that during relocation
- * this routine needs to be executed as part of source-bag while the
- * deallocation must not be done until source-end.
+ * Write out an unmount record using the ticket provided. We have to account for
+ * the data space used in the unmount ticket as this write is not done from a
+ * transaction context that has already done the accounting for us.
  */
-
-/* Actually write the unmount record to disk. */
-static void
-xfs_log_write_unmount_record(
-       struct xfs_mount        *mp)
+static int
+xlog_write_unmount_record(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket,
+       xfs_lsn_t               *lsn,
+       uint                    flags)
 {
-       /* the data section must be 32 bit size aligned */
-       struct xfs_unmount_log_format magic = {
+       struct xfs_unmount_log_format ulf = {
                .magic = XLOG_UNMOUNT_TYPE,
        };
        struct xfs_log_iovec reg = {
-               .i_addr = &magic,
-               .i_len = sizeof(magic),
+               .i_addr = &ulf,
+               .i_len = sizeof(ulf),
                .i_type = XLOG_REG_TYPE_UNMOUNT,
        };
        struct xfs_log_vec vec = {
                .lv_niovecs = 1,
                .lv_iovecp = &reg,
        };
-       struct xlog             *log = mp->m_log;
+
+       /* account for space used by record data */
+       ticket->t_curr_res -= sizeof(ulf);
+       return xlog_write(log, &vec, ticket, lsn, NULL, flags, false);
+}
+
+/*
+ * Mark the filesystem clean by writing an unmount record to the head of the
+ * log.
+ */
+static void
+xlog_unmount_write(
+       struct xlog             *log)
+{
+       struct xfs_mount        *mp = log->l_mp;
        struct xlog_in_core     *iclog;
        struct xlog_ticket      *tic = NULL;
        xfs_lsn_t               lsn;
@@ -905,23 +835,7 @@ xfs_log_write_unmount_record(
        if (error)
                goto out_err;
 
-       /*
-        * If we think the summary counters are bad, clear the unmount header
-        * flag in the unmount record so that the summary counters will be
-        * recalculated during log recovery at next mount.  Refer to
-        * xlog_check_unmount_rec for more details.
-        */
-       if (XFS_TEST_ERROR(xfs_fs_has_sickness(mp, XFS_SICK_FS_COUNTERS), mp,
-                       XFS_ERRTAG_FORCE_SUMMARY_RECALC)) {
-               xfs_alert(mp, "%s: will fix summary counters at next mount",
-                               __func__);
-               flags &= ~XLOG_UNMOUNT_TRANS;
-       }
-
-       /* remove inited flag, and account for space used */
-       tic->t_flags = 0;
-       tic->t_curr_res -= sizeof(magic);
-       error = xlog_write(log, &vec, tic, &lsn, NULL, flags);
+       error = xlog_write_unmount_record(log, tic, &lsn, flags);
        /*
         * At this point, we're umounting anyway, so there's no point in
         * transitioning log state to IOERROR. Just continue...
@@ -943,8 +857,7 @@ out_err:
 
        if (tic) {
                trace_xfs_log_umount_write(log, tic);
-               xlog_ungrant_log_space(log, tic);
-               xfs_log_ticket_put(tic);
+               xfs_log_ticket_ungrant(log, tic);
        }
 }
 
@@ -987,8 +900,22 @@ xfs_log_unmount_write(
 
        if (XLOG_FORCED_SHUTDOWN(log))
                return;
+
+       /*
+        * If we think the summary counters are bad, avoid writing the unmount
+        * record to force log recovery at next mount, after which the summary
+        * counters will be recalculated.  Refer to xlog_check_unmount_rec for
+        * more details.
+        */
+       if (XFS_TEST_ERROR(xfs_fs_has_sickness(mp, XFS_SICK_FS_COUNTERS), mp,
+                       XFS_ERRTAG_FORCE_SUMMARY_RECALC)) {
+               xfs_alert(mp, "%s: will fix summary counters at next mount",
+                               __func__);
+               return;
+       }
+
        xfs_log_unmount_verify_iclog(log);
-       xfs_log_write_unmount_record(mp);
+       xlog_unmount_write(log);
 }
 
 /*
@@ -1515,20 +1442,17 @@ out:
        return ERR_PTR(error);
 }      /* xlog_alloc_log */
 
-
 /*
  * Write out the commit record of a transaction associated with the given
- * ticket Return the lsn of the commit record.
+ * ticket to close off a running log write. Return the lsn of the commit record.
  */
-STATIC int
+int
 xlog_commit_record(
        struct xlog             *log,
        struct xlog_ticket      *ticket,
        struct xlog_in_core     **iclog,
-       xfs_lsn_t               *commitlsnp)
+       xfs_lsn_t               *lsn)
 {
-       struct xfs_mount *mp = log->l_mp;
-       int     error;
        struct xfs_log_iovec reg = {
                .i_addr = NULL,
                .i_len = 0,
@@ -1538,12 +1462,15 @@ xlog_commit_record(
                .lv_niovecs = 1,
                .lv_iovecp = &reg,
        };
+       int     error;
+
+       if (XLOG_FORCED_SHUTDOWN(log))
+               return -EIO;
 
-       ASSERT_ALWAYS(iclog);
-       error = xlog_write(log, &vec, ticket, commitlsnp, iclog,
-                                       XLOG_COMMIT_TRANS);
+       error = xlog_write(log, &vec, ticket, lsn, iclog, XLOG_COMMIT_TRANS,
+                          false);
        if (error)
-               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
+               xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR);
        return error;
 }
 
@@ -1761,7 +1688,15 @@ xlog_write_iclog(
        iclog->ic_bio.bi_iter.bi_sector = log->l_logBBstart + bno;
        iclog->ic_bio.bi_end_io = xlog_bio_end_io;
        iclog->ic_bio.bi_private = iclog;
-       iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC | REQ_FUA;
+
+       /*
+        * We use REQ_SYNC | REQ_IDLE here to tell the block layer the are more
+        * IOs coming immediately after this one. This prevents the block layer
+        * writeback throttle from throttling log writes behind background
+        * metadata writeback and causing priority inversions.
+        */
+       iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC |
+                               REQ_IDLE | REQ_FUA;
        if (need_flush)
                iclog->ic_bio.bi_opf |= REQ_PREFLUSH;
 
@@ -1981,7 +1916,7 @@ xlog_dealloc_log(
        log->l_mp->m_log = NULL;
        destroy_workqueue(log->l_ioend_workqueue);
        kmem_free(log);
-}      /* xlog_dealloc_log */
+}
 
 /*
  * Update counters atomically now that memcpy is done.
@@ -2118,23 +2053,21 @@ xlog_print_trans(
 }
 
 /*
- * Calculate the potential space needed by the log vector.  Each region gets
- * its own xlog_op_header_t and may need to be double word aligned.
+ * Calculate the potential space needed by the log vector.  We may need a start
+ * record, and each region gets its own struct xlog_op_header and may need to be
+ * double word aligned.
  */
 static int
 xlog_write_calc_vec_length(
        struct xlog_ticket      *ticket,
-       struct xfs_log_vec      *log_vector)
+       struct xfs_log_vec      *log_vector,
+       bool                    need_start_rec)
 {
        struct xfs_log_vec      *lv;
-       int                     headers = 0;
+       int                     headers = need_start_rec ? 1 : 0;
        int                     len = 0;
        int                     i;
 
-       /* acct for start rec of xact */
-       if (ticket->t_flags & XLOG_TIC_INITED)
-               headers++;
-
        for (lv = log_vector; lv; lv = lv->lv_next) {
                /* we don't write ordered log vectors */
                if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED)
@@ -2156,27 +2089,16 @@ xlog_write_calc_vec_length(
        return len;
 }
 
-/*
- * If first write for transaction, insert start record  We can't be trying to
- * commit if we are inited.  We can't have any "partial_copy" if we are inited.
- */
-static int
+static void
 xlog_write_start_rec(
        struct xlog_op_header   *ophdr,
        struct xlog_ticket      *ticket)
 {
-       if (!(ticket->t_flags & XLOG_TIC_INITED))
-               return 0;
-
        ophdr->oh_tid   = cpu_to_be32(ticket->t_tid);
        ophdr->oh_clientid = ticket->t_clientid;
        ophdr->oh_len = 0;
        ophdr->oh_flags = XLOG_START_TRANS;
        ophdr->oh_res2 = 0;
-
-       ticket->t_flags &= ~XLOG_TIC_INITED;
-
-       return sizeof(struct xlog_op_header);
 }
 
 static xlog_op_header_t *
@@ -2365,13 +2287,14 @@ xlog_write(
        struct xlog_ticket      *ticket,
        xfs_lsn_t               *start_lsn,
        struct xlog_in_core     **commit_iclog,
-       uint                    flags)
+       uint                    flags,
+       bool                    need_start_rec)
 {
        struct xlog_in_core     *iclog = NULL;
-       struct xfs_log_iovec    *vecp;
-       struct xfs_log_vec      *lv;
+       struct xfs_log_vec      *lv = log_vector;
+       struct xfs_log_iovec    *vecp = lv->lv_iovecp;
+       int                     index = 0;
        int                     len;
-       int                     index;
        int                     partial_copy = 0;
        int                     partial_copy_len = 0;
        int                     contwr = 0;
@@ -2379,25 +2302,13 @@ xlog_write(
        int                     data_cnt = 0;
        int                     error = 0;
 
-       *start_lsn = 0;
-
-       len = xlog_write_calc_vec_length(ticket, log_vector);
-
        /*
-        * Region headers and bytes are already accounted for.
-        * We only need to take into account start records and
-        * split regions in this function.
+        * If this is a commit or unmount transaction, we don't need a start
+        * record to be written.  We do, however, have to account for the
+        * commit or unmount header that gets written. Hence we always have
+        * to account for an extra xlog_op_header here.
         */
-       if (ticket->t_flags & XLOG_TIC_INITED)
-               ticket->t_curr_res -= sizeof(xlog_op_header_t);
-
-       /*
-        * Commit record headers need to be accounted for. These
-        * come in as separate writes so are easy to detect.
-        */
-       if (flags & (XLOG_COMMIT_TRANS | XLOG_UNMOUNT_TRANS))
-               ticket->t_curr_res -= sizeof(xlog_op_header_t);
-
+       ticket->t_curr_res -= sizeof(struct xlog_op_header);
        if (ticket->t_curr_res < 0) {
                xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES,
                     "ctx ticket reservation ran out. Need to up reservation");
@@ -2405,9 +2316,8 @@ xlog_write(
                xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR);
        }
 
-       index = 0;
-       lv = log_vector;
-       vecp = lv->lv_iovecp;
+       len = xlog_write_calc_vec_length(ticket, log_vector, need_start_rec);
+       *start_lsn = 0;
        while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) {
                void            *ptr;
                int             log_offset;
@@ -2431,7 +2341,6 @@ xlog_write(
                while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) {
                        struct xfs_log_iovec    *reg;
                        struct xlog_op_header   *ophdr;
-                       int                     start_rec_copy;
                        int                     copy_len;
                        int                     copy_off;
                        bool                    ordered = false;
@@ -2447,11 +2356,15 @@ xlog_write(
                        ASSERT(reg->i_len % sizeof(int32_t) == 0);
                        ASSERT((unsigned long)ptr % sizeof(int32_t) == 0);
 
-                       start_rec_copy = xlog_write_start_rec(ptr, ticket);
-                       if (start_rec_copy) {
-                               record_cnt++;
+                       /*
+                        * Before we start formatting log vectors, we need to
+                        * write a start record. Only do this for the first
+                        * iclog we write to.
+                        */
+                       if (need_start_rec) {
+                               xlog_write_start_rec(ptr, ticket);
                                xlog_write_adv_cnt(&ptr, &len, &log_offset,
-                                                  start_rec_copy);
+                                               sizeof(struct xlog_op_header));
                        }
 
                        ophdr = xlog_write_setup_ophdr(log, ptr, ticket, flags);
@@ -2483,8 +2396,13 @@ xlog_write(
                                xlog_write_adv_cnt(&ptr, &len, &log_offset,
                                                   copy_len);
                        }
-                       copy_len += start_rec_copy + sizeof(xlog_op_header_t);
+                       copy_len += sizeof(struct xlog_op_header);
                        record_cnt++;
+                       if (need_start_rec) {
+                               copy_len += sizeof(struct xlog_op_header);
+                               record_cnt++;
+                               need_start_rec = false;
+                       }
                        data_cnt += contwr ? copy_len : 0;
 
                        error = xlog_write_copy_finish(log, iclog, flags,
@@ -2541,14 +2459,6 @@ next_lv:
        return error;
 }
 
-
-/*****************************************************************************
- *
- *             State Machine functions
- *
- *****************************************************************************
- */
-
 static void
 xlog_state_activate_iclog(
        struct xlog_in_core     *iclog,
@@ -2909,7 +2819,7 @@ xlog_state_done_syncing(
         */
        wake_up_all(&iclog->ic_write_wait);
        spin_unlock(&log->l_icloglock);
-       xlog_state_do_callback(log);    /* also cleans log */
+       xlog_state_do_callback(log);
 }
 
 /*
@@ -3029,21 +2939,21 @@ restart:
 
        *logoffsetp = log_offset;
        return 0;
-}      /* xlog_state_get_iclog_space */
-
-/* The first cnt-1 times through here we don't need to
- * move the grant write head because the permanent
- * reservation has reserved cnt times the unit amount.
- * Release part of current permanent unit reservation and
- * reset current reservation to be one units worth.  Also
- * move grant reservation head forward.
+}
+
+/*
+ * The first cnt-1 times a ticket goes through here we don't need to move the
+ * grant write head because the permanent reservation has reserved cnt times the
+ * unit amount.  Release part of current permanent unit reservation and reset
+ * current reservation to be one units worth.  Also move grant reservation head
+ * forward.
  */
-STATIC void
-xlog_regrant_reserve_log_space(
+void
+xfs_log_ticket_regrant(
        struct xlog             *log,
        struct xlog_ticket      *ticket)
 {
-       trace_xfs_log_regrant_reserve_enter(log, ticket);
+       trace_xfs_log_ticket_regrant(log, ticket);
 
        if (ticket->t_cnt > 0)
                ticket->t_cnt--;
@@ -3055,21 +2965,20 @@ xlog_regrant_reserve_log_space(
        ticket->t_curr_res = ticket->t_unit_res;
        xlog_tic_reset_res(ticket);
 
-       trace_xfs_log_regrant_reserve_sub(log, ticket);
+       trace_xfs_log_ticket_regrant_sub(log, ticket);
 
        /* just return if we still have some of the pre-reserved space */
-       if (ticket->t_cnt > 0)
-               return;
+       if (!ticket->t_cnt) {
+               xlog_grant_add_space(log, &log->l_reserve_head.grant,
+                                    ticket->t_unit_res);
+               trace_xfs_log_ticket_regrant_exit(log, ticket);
 
-       xlog_grant_add_space(log, &log->l_reserve_head.grant,
-                                       ticket->t_unit_res);
-
-       trace_xfs_log_regrant_reserve_exit(log, ticket);
-
-       ticket->t_curr_res = ticket->t_unit_res;
-       xlog_tic_reset_res(ticket);
-}      /* xlog_regrant_reserve_log_space */
+               ticket->t_curr_res = ticket->t_unit_res;
+               xlog_tic_reset_res(ticket);
+       }
 
+       xfs_log_ticket_put(ticket);
+}
 
 /*
  * Give back the space left from a reservation.
@@ -3085,18 +2994,19 @@ xlog_regrant_reserve_log_space(
  * space, the count will stay at zero and the only space remaining will be
  * in the current reservation field.
  */
-STATIC void
-xlog_ungrant_log_space(
+void
+xfs_log_ticket_ungrant(
        struct xlog             *log,
        struct xlog_ticket      *ticket)
 {
-       int     bytes;
+       int                     bytes;
+
+       trace_xfs_log_ticket_ungrant(log, ticket);
 
        if (ticket->t_cnt > 0)
                ticket->t_cnt--;
 
-       trace_xfs_log_ungrant_enter(log, ticket);
-       trace_xfs_log_ungrant_sub(log, ticket);
+       trace_xfs_log_ticket_ungrant_sub(log, ticket);
 
        /*
         * If this is a permanent reservation ticket, we may be able to free
@@ -3111,18 +3021,15 @@ xlog_ungrant_log_space(
        xlog_grant_sub_space(log, &log->l_reserve_head.grant, bytes);
        xlog_grant_sub_space(log, &log->l_write_head.grant, bytes);
 
-       trace_xfs_log_ungrant_exit(log, ticket);
+       trace_xfs_log_ticket_ungrant_exit(log, ticket);
 
        xfs_log_space_wake(log->l_mp);
+       xfs_log_ticket_put(ticket);
 }
 
 /*
- * Mark the current iclog in the ring as WANT_SYNC and move the current iclog
- * pointer to the next iclog in the ring.
- *
- * When called from xlog_state_get_iclog_space(), the exact size of the iclog
- * has not yet been determined, all we know is that we have run out of space in
- * the current iclog.
+ * This routine will mark the current iclog in the ring as WANT_SYNC and move
+ * the current iclog pointer to the next iclog in the ring.
  */
 STATIC void
 xlog_state_switch_iclogs(
@@ -3167,7 +3074,7 @@ xlog_state_switch_iclogs(
        }
        ASSERT(iclog == log->l_iclog);
        log->l_iclog = iclog->ic_next;
-}      /* xlog_state_switch_iclogs */
+}
 
 /*
  * Write out all data in the in-core log as of this exact moment in time.
@@ -3374,13 +3281,6 @@ xfs_log_force_lsn(
        return ret;
 }
 
-/*****************************************************************************
- *
- *             TICKET functions
- *
- *****************************************************************************
- */
-
 /*
  * Free a used ticket when its refcount falls to zero.
  */
@@ -3529,7 +3429,6 @@ xlog_ticket_alloc(
        tic->t_ocnt             = cnt;
        tic->t_tid              = prandom_u32();
        tic->t_clientid         = client;
-       tic->t_flags            = XLOG_TIC_INITED;
        if (permanent)
                tic->t_flags |= XLOG_TIC_PERM_RESERV;
 
@@ -3538,13 +3437,6 @@ xlog_ticket_alloc(
        return tic;
 }
 
-
-/******************************************************************************
- *
- *             Log debug routines
- *
- ******************************************************************************
- */
 #if defined(DEBUG)
 /*
  * Make sure that the destination ptr is within the valid data region of
@@ -3630,7 +3522,7 @@ xlog_verify_tail_lsn(
        if (blocks < BTOBB(iclog->ic_offset) + 1)
                xfs_emerg(log->l_mp, "%s: ran out of log space", __func__);
     }
-}      /* xlog_verify_tail_lsn */
+}
 
 /*
  * Perform a number of checks on the iclog before writing to disk.
@@ -3733,7 +3625,7 @@ xlog_verify_iclog(
                }
                ptr += sizeof(xlog_op_header_t) + op_len;
        }
-}      /* xlog_verify_iclog */
+}
 #endif
 
 /*
index cc77cc3..1412d69 100644 (file)
@@ -105,10 +105,6 @@ struct xfs_log_item;
 struct xfs_item_ops;
 struct xfs_trans;
 
-xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
-                      struct xlog_ticket *ticket,
-                      struct xlog_in_core **iclog,
-                      bool regrant);
 int      xfs_log_force(struct xfs_mount *mp, uint flags);
 int      xfs_log_force_lsn(struct xfs_mount *mp, xfs_lsn_t lsn, uint flags,
                int *log_forced);
index 64cc0bf..b43f0e8 100644 (file)
@@ -669,6 +669,11 @@ xlog_cil_push_work(
        ASSERT(push_seq <= ctx->sequence);
 
        /*
+        * Wake up any background push waiters now this context is being pushed.
+        */
+       wake_up_all(&ctx->push_wait);
+
+       /*
         * Check if we've anything to push. If there is nothing, then we don't
         * move on to a new sequence number and so we have to be able to push
         * this sequence again later.
@@ -744,6 +749,7 @@ xlog_cil_push_work(
         */
        INIT_LIST_HEAD(&new_ctx->committing);
        INIT_LIST_HEAD(&new_ctx->busy_extents);
+       init_waitqueue_head(&new_ctx->push_wait);
        new_ctx->sequence = ctx->sequence + 1;
        new_ctx->cil = cil;
        cil->xc_ctx = new_ctx;
@@ -801,7 +807,7 @@ xlog_cil_push_work(
        lvhdr.lv_iovecp = &lhdr;
        lvhdr.lv_next = ctx->lv_chain;
 
-       error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0);
+       error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0, true);
        if (error)
                goto out_abort_free_ticket;
 
@@ -839,10 +845,11 @@ restart:
        }
        spin_unlock(&cil->xc_push_lock);
 
-       /* xfs_log_done always frees the ticket on error. */
-       commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, false);
-       if (commit_lsn == -1)
-               goto out_abort;
+       error = xlog_commit_record(log, tic, &commit_iclog, &commit_lsn);
+       if (error)
+               goto out_abort_free_ticket;
+
+       xfs_log_ticket_ungrant(log, tic);
 
        spin_lock(&commit_iclog->ic_callback_lock);
        if (commit_iclog->ic_state == XLOG_STATE_IOERROR) {
@@ -875,7 +882,7 @@ out_skip:
        return;
 
 out_abort_free_ticket:
-       xfs_log_ticket_put(tic);
+       xfs_log_ticket_ungrant(log, tic);
 out_abort:
        ASSERT(XLOG_FORCED_SHUTDOWN(log));
        xlog_cil_committed(ctx);
@@ -890,7 +897,7 @@ out_abort:
  */
 static void
 xlog_cil_push_background(
-       struct xlog     *log)
+       struct xlog     *log) __releases(cil->xc_ctx_lock)
 {
        struct xfs_cil  *cil = log->l_cilp;
 
@@ -904,14 +911,36 @@ xlog_cil_push_background(
         * don't do a background push if we haven't used up all the
         * space available yet.
         */
-       if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+       if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log)) {
+               up_read(&cil->xc_ctx_lock);
                return;
+       }
 
        spin_lock(&cil->xc_push_lock);
        if (cil->xc_push_seq < cil->xc_current_sequence) {
                cil->xc_push_seq = cil->xc_current_sequence;
                queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work);
        }
+
+       /*
+        * Drop the context lock now, we can't hold that if we need to sleep
+        * because we are over the blocking threshold. The push_lock is still
+        * held, so blocking threshold sleep/wakeup is still correctly
+        * serialised here.
+        */
+       up_read(&cil->xc_ctx_lock);
+
+       /*
+        * If we are well over the space limit, throttle the work that is being
+        * done until the push work on this context has begun.
+        */
+       if (cil->xc_ctx->space_used >= XLOG_CIL_BLOCKING_SPACE_LIMIT(log)) {
+               trace_xfs_log_cil_wait(log, cil->xc_ctx->ticket);
+               ASSERT(cil->xc_ctx->space_used < log->l_logsize);
+               xlog_wait(&cil->xc_ctx->push_wait, &cil->xc_push_lock);
+               return;
+       }
+
        spin_unlock(&cil->xc_push_lock);
 
 }
@@ -1007,7 +1036,10 @@ xfs_log_commit_cil(
        if (commit_lsn)
                *commit_lsn = xc_commit_lsn;
 
-       xfs_log_done(mp, tp->t_ticket, NULL, regrant);
+       if (regrant && !XLOG_FORCED_SHUTDOWN(log))
+               xfs_log_ticket_regrant(log, tp->t_ticket);
+       else
+               xfs_log_ticket_ungrant(log, tp->t_ticket);
        tp->t_ticket = NULL;
        xfs_trans_unreserve_and_mod_sb(tp);
 
@@ -1028,9 +1060,9 @@ xfs_log_commit_cil(
                if (lip->li_ops->iop_committing)
                        lip->li_ops->iop_committing(lip, xc_commit_lsn);
        }
-       xlog_cil_push_background(log);
 
-       up_read(&cil->xc_ctx_lock);
+       /* xlog_cil_push_background() releases cil->xc_ctx_lock */
+       xlog_cil_push_background(log);
 }
 
 /*
@@ -1189,6 +1221,7 @@ xlog_cil_init(
 
        INIT_LIST_HEAD(&ctx->committing);
        INIT_LIST_HEAD(&ctx->busy_extents);
+       init_waitqueue_head(&ctx->push_wait);
        ctx->sequence = 1;
        ctx->cil = cil;
        cil->xc_ctx = ctx;
index 2b0aec3..ec22c7a 100644 (file)
@@ -51,13 +51,11 @@ enum xlog_iclog_state {
 };
 
 /*
- * Flags to log ticket
+ * Log ticket flags
  */
-#define XLOG_TIC_INITED                0x1     /* has been initialized */
-#define XLOG_TIC_PERM_RESERV   0x2     /* permanent reservation */
+#define XLOG_TIC_PERM_RESERV   0x1     /* permanent reservation */
 
 #define XLOG_TIC_FLAGS \
-       { XLOG_TIC_INITED,      "XLOG_TIC_INITED" }, \
        { XLOG_TIC_PERM_RESERV, "XLOG_TIC_PERM_RESERV" }
 
 /*
@@ -242,6 +240,7 @@ struct xfs_cil_ctx {
        struct xfs_log_vec      *lv_chain;      /* logvecs being pushed */
        struct list_head        iclog_entry;
        struct list_head        committing;     /* ctx committing list */
+       wait_queue_head_t       push_wait;      /* background push throttle */
        struct work_struct      discard_endio_work;
 };
 
@@ -318,13 +317,53 @@ struct xfs_cil {
  * tries to keep 25% of the log free, so we need to keep below that limit or we
  * risk running out of free log space to start any new transactions.
  *
- * In order to keep background CIL push efficient, we will set a lower
- * threshold at which background pushing is attempted without blocking current
- * transaction commits.  A separate, higher bound defines when CIL pushes are
- * enforced to ensure we stay within our maximum checkpoint size bounds.
- * threshold, yet give us plenty of space for aggregation on large logs.
+ * In order to keep background CIL push efficient, we only need to ensure the
+ * CIL is large enough to maintain sufficient in-memory relogging to avoid
+ * repeated physical writes of frequently modified metadata. If we allow the CIL
+ * to grow to a substantial fraction of the log, then we may be pinning hundreds
+ * of megabytes of metadata in memory until the CIL flushes. This can cause
+ * issues when we are running low on memory - pinned memory cannot be reclaimed,
+ * and the CIL consumes a lot of memory. Hence we need to set an upper physical
+ * size limit for the CIL that limits the maximum amount of memory pinned by the
+ * CIL but does not limit performance by reducing relogging efficiency
+ * significantly.
+ *
+ * As such, the CIL push threshold ends up being the smaller of two thresholds:
+ * - a threshold large enough that it allows CIL to be pushed and progress to be
+ *   made without excessive blocking of incoming transaction commits. This is
+ *   defined to be 12.5% of the log space - half the 25% push threshold of the
+ *   AIL.
+ * - small enough that it doesn't pin excessive amounts of memory but maintains
+ *   close to peak relogging efficiency. This is defined to be 16x the iclog
+ *   buffer window (32MB) as measurements have shown this to be roughly the
+ *   point of diminishing performance increases under highly concurrent
+ *   modification workloads.
+ *
+ * To prevent the CIL from overflowing upper commit size bounds, we introduce a
+ * new threshold at which we block committing transactions until the background
+ * CIL commit commences and switches to a new context. While this is not a hard
+ * limit, it forces the process committing a transaction to the CIL to block and
+ * yeild the CPU, giving the CIL push work a chance to be scheduled and start
+ * work. This prevents a process running lots of transactions from overfilling
+ * the CIL because it is not yielding the CPU. We set the blocking limit at
+ * twice the background push space threshold so we keep in line with the AIL
+ * push thresholds.
+ *
+ * Note: this is not a -hard- limit as blocking is applied after the transaction
+ * is inserted into the CIL and the push has been triggered. It is largely a
+ * throttling mechanism that allows the CIL push to be scheduled and run. A hard
+ * limit will be difficult to implement without introducing global serialisation
+ * in the CIL commit fast path, and it's not at all clear that we actually need
+ * such hard limits given the ~7 years we've run without a hard limit before
+ * finding the first situation where a checkpoint size overflow actually
+ * occurred. Hence the simple throttle, and an ASSERT check to tell us that
+ * we've overrun the max size.
  */
-#define XLOG_CIL_SPACE_LIMIT(log)      (log->l_logsize >> 3)
+#define XLOG_CIL_SPACE_LIMIT(log)      \
+       min_t(int, (log)->l_logsize >> 3, BBTOB(XLOG_TOTAL_REC_SHIFT(log)) << 4)
+
+#define XLOG_CIL_BLOCKING_SPACE_LIMIT(log)     \
+       (XLOG_CIL_SPACE_LIMIT(log) * 2)
 
 /*
  * ticket grant locks, queues and accounting have their own cachlines
@@ -439,14 +478,14 @@ xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes)
 
 void   xlog_print_tic_res(struct xfs_mount *mp, struct xlog_ticket *ticket);
 void   xlog_print_trans(struct xfs_trans *);
-int
-xlog_write(
-       struct xlog             *log,
-       struct xfs_log_vec      *log_vector,
-       struct xlog_ticket      *tic,
-       xfs_lsn_t               *start_lsn,
-       struct xlog_in_core     **commit_iclog,
-       uint                    flags);
+int    xlog_write(struct xlog *log, struct xfs_log_vec *log_vector,
+               struct xlog_ticket *tic, xfs_lsn_t *start_lsn,
+               struct xlog_in_core **commit_iclog, uint flags,
+               bool need_start_rec);
+int    xlog_commit_record(struct xlog *log, struct xlog_ticket *ticket,
+               struct xlog_in_core **iclog, xfs_lsn_t *lsn);
+void   xfs_log_ticket_ungrant(struct xlog *log, struct xlog_ticket *ticket);
+void   xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket);
 
 /*
  * When we crack an atomic LSN, we sample it first so that the value will not
index 88ab09e..50c4342 100644 (file)
@@ -167,6 +167,7 @@ typedef struct xfs_mount {
        struct xfs_kobj         m_error_meta_kobj;
        struct xfs_error_cfg    m_error_cfg[XFS_ERR_CLASS_MAX][XFS_ERR_ERRNO_MAX];
        struct xstats           m_stats;        /* per-fs stats */
+       struct ratelimit_state  m_flush_inodes_ratelimit;
 
        struct workqueue_struct *m_buf_workqueue;
        struct workqueue_struct *m_unwritten_workqueue;
index cabdb75..c225691 100644 (file)
@@ -121,12 +121,11 @@ xfs_qm_dqpurge(
 {
        struct xfs_mount        *mp = dqp->q_mount;
        struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       int                     error = -EAGAIN;
 
        xfs_dqlock(dqp);
-       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
-               xfs_dqunlock(dqp);
-               return -EAGAIN;
-       }
+       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0)
+               goto out_unlock;
 
        dqp->dq_flags |= XFS_DQ_FREEING;
 
@@ -139,7 +138,6 @@ xfs_qm_dqpurge(
         */
        if (XFS_DQ_IS_DIRTY(dqp)) {
                struct xfs_buf  *bp = NULL;
-               int             error;
 
                /*
                 * We don't care about getting disk errors here. We need
@@ -149,6 +147,8 @@ xfs_qm_dqpurge(
                if (!error) {
                        error = xfs_bwrite(bp);
                        xfs_buf_relse(bp);
+               } else if (error == -EAGAIN) {
+                       goto out_unlock;
                }
                xfs_dqflock(dqp);
        }
@@ -174,6 +174,10 @@ xfs_qm_dqpurge(
 
        xfs_qm_dqdestroy(dqp);
        return 0;
+
+out_unlock:
+       xfs_dqunlock(dqp);
+       return error;
 }
 
 /*
index 2094386..abf06bf 100644 (file)
@@ -528,6 +528,9 @@ xfs_flush_inodes(
 {
        struct super_block      *sb = mp->m_super;
 
+       if (!__ratelimit(&mp->m_flush_inodes_ratelimit))
+               return;
+
        if (down_read_trylock(&sb->s_umount)) {
                sync_inodes_sb(sb);
                up_read(&sb->s_umount);
@@ -1366,6 +1369,17 @@ xfs_fc_fill_super(
        if (error)
                goto out_free_names;
 
+       /*
+        * Cap the number of invocations of xfs_flush_inodes to 16 for every
+        * quarter of a second.  The magic numbers here were determined by
+        * observation neither to cause stalls in writeback when there are a
+        * lot of IO threads and the fs is near ENOSPC, nor cause any fstest
+        * regressions.  YMMV.
+        */
+       ratelimit_state_init(&mp->m_flush_inodes_ratelimit, HZ / 4, 16);
+       ratelimit_set_flags(&mp->m_flush_inodes_ratelimit,
+                       RATELIMIT_MSG_ON_RELEASE);
+
        error = xfs_init_mount_workqueues(mp);
        if (error)
                goto out_close_devices;
@@ -1861,7 +1875,8 @@ xfs_init_zones(void)
 
        xfs_ili_zone = kmem_cache_create("xfs_ili",
                                         sizeof(struct xfs_inode_log_item), 0,
-                                        SLAB_MEM_SPREAD, NULL);
+                                        SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                        NULL);
        if (!xfs_ili_zone)
                goto out_destroy_inode_zone;
 
index fa0fa3c..13fb4b9 100644 (file)
@@ -176,7 +176,6 @@ xfs_symlink(
                return -ENAMETOOLONG;
        ASSERT(pathlen > 0);
 
-       udqp = gdqp = NULL;
        prid = xfs_get_initial_prid(dp);
 
        /*
index efc7751..a4323a6 100644 (file)
@@ -1001,8 +1001,6 @@ DECLARE_EVENT_CLASS(xfs_loggrant_class,
 DEFINE_EVENT(xfs_loggrant_class, name, \
        TP_PROTO(struct xlog *log, struct xlog_ticket *tic), \
        TP_ARGS(log, tic))
-DEFINE_LOGGRANT_EVENT(xfs_log_done_nonperm);
-DEFINE_LOGGRANT_EVENT(xfs_log_done_perm);
 DEFINE_LOGGRANT_EVENT(xfs_log_umount_write);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_sleep);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake);
@@ -1011,12 +1009,13 @@ DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
 DEFINE_LOGGRANT_EVENT(xfs_log_reserve_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_sub);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_cil_wait);
 
 DECLARE_EVENT_CLASS(xfs_log_item_class,
        TP_PROTO(struct xfs_log_item *lip),
index 1adc6bc..28b983f 100644 (file)
@@ -9,6 +9,7 @@
 #include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
+#include "xfs_log_priv.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_extent_busy.h"
@@ -150,8 +151,9 @@ xfs_trans_reserve(
        uint                    blocks,
        uint                    rtextents)
 {
-       int             error = 0;
-       bool            rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
+       struct xfs_mount        *mp = tp->t_mountp;
+       int                     error = 0;
+       bool                    rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
        /* Mark this thread as being in a transaction */
        current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
@@ -162,7 +164,7 @@ xfs_trans_reserve(
         * fail if the count would go below zero.
         */
        if (blocks > 0) {
-               error = xfs_mod_fdblocks(tp->t_mountp, -((int64_t)blocks), rsvd);
+               error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd);
                if (error != 0) {
                        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
                        return -ENOSPC;
@@ -191,9 +193,9 @@ xfs_trans_reserve(
 
                if (tp->t_ticket != NULL) {
                        ASSERT(resp->tr_logflags & XFS_TRANS_PERM_LOG_RES);
-                       error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
+                       error = xfs_log_regrant(mp, tp->t_ticket);
                } else {
-                       error = xfs_log_reserve(tp->t_mountp,
+                       error = xfs_log_reserve(mp,
                                                resp->tr_logres,
                                                resp->tr_logcount,
                                                &tp->t_ticket, XFS_TRANSACTION,
@@ -213,7 +215,7 @@ xfs_trans_reserve(
         * fail if the count would go below zero.
         */
        if (rtextents > 0) {
-               error = xfs_mod_frextents(tp->t_mountp, -((int64_t)rtextents));
+               error = xfs_mod_frextents(mp, -((int64_t)rtextents));
                if (error) {
                        error = -ENOSPC;
                        goto undo_log;
@@ -229,7 +231,7 @@ xfs_trans_reserve(
         */
 undo_log:
        if (resp->tr_logres > 0) {
-               xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, false);
+               xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
                tp->t_log_res = 0;
                tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;
@@ -237,7 +239,7 @@ undo_log:
 
 undo_blocks:
        if (blocks > 0) {
-               xfs_mod_fdblocks(tp->t_mountp, (int64_t)blocks, rsvd);
+               xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd);
                tp->t_blk_res = 0;
        }
 
@@ -1004,9 +1006,10 @@ out_unreserve:
         */
        xfs_trans_unreserve_and_mod_dquots(tp);
        if (tp->t_ticket) {
-               commit_lsn = xfs_log_done(mp, tp->t_ticket, NULL, regrant);
-               if (commit_lsn == -1 && !error)
-                       error = -EIO;
+               if (regrant && !XLOG_FORCED_SHUTDOWN(mp->m_log))
+                       xfs_log_ticket_regrant(mp->m_log, tp->t_ticket);
+               else
+                       xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
        }
        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
@@ -1065,7 +1068,7 @@ xfs_trans_cancel(
        xfs_trans_unreserve_and_mod_dquots(tp);
 
        if (tp->t_ticket) {
-               xfs_log_done(mp, tp->t_ticket, NULL, false);
+               xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
        }
 
index 2ef0dfb..5642535 100644 (file)
@@ -109,17 +109,25 @@ xfs_ail_next(
  * We need the AIL lock in order to get a coherent read of the lsn of the last
  * item in the AIL.
  */
+static xfs_lsn_t
+__xfs_ail_min_lsn(
+       struct xfs_ail          *ailp)
+{
+       struct xfs_log_item     *lip = xfs_ail_min(ailp);
+
+       if (lip)
+               return lip->li_lsn;
+       return 0;
+}
+
 xfs_lsn_t
 xfs_ail_min_lsn(
        struct xfs_ail          *ailp)
 {
-       xfs_lsn_t               lsn = 0;
-       struct xfs_log_item     *lip;
+       xfs_lsn_t               lsn;
 
        spin_lock(&ailp->ail_lock);
-       lip = xfs_ail_min(ailp);
-       if (lip)
-               lsn = lip->li_lsn;
+       lsn = __xfs_ail_min_lsn(ailp);
        spin_unlock(&ailp->ail_lock);
 
        return lsn;
@@ -681,6 +689,28 @@ xfs_ail_push_all_sync(
        finish_wait(&ailp->ail_empty, &wait);
 }
 
+void
+xfs_ail_update_finish(
+       struct xfs_ail          *ailp,
+       xfs_lsn_t               old_lsn) __releases(ailp->ail_lock)
+{
+       struct xfs_mount        *mp = ailp->ail_mount;
+
+       /* if the tail lsn hasn't changed, don't do updates or wakeups. */
+       if (!old_lsn || old_lsn == __xfs_ail_min_lsn(ailp)) {
+               spin_unlock(&ailp->ail_lock);
+               return;
+       }
+
+       if (!XFS_FORCED_SHUTDOWN(mp))
+               xlog_assign_tail_lsn_locked(mp);
+
+       if (list_empty(&ailp->ail_head))
+               wake_up_all(&ailp->ail_empty);
+       spin_unlock(&ailp->ail_lock);
+       xfs_log_space_wake(mp);
+}
+
 /*
  * xfs_trans_ail_update - bulk AIL insertion operation.
  *
@@ -712,7 +742,7 @@ xfs_trans_ail_update_bulk(
        xfs_lsn_t               lsn) __releases(ailp->ail_lock)
 {
        struct xfs_log_item     *mlip;
-       int                     mlip_changed = 0;
+       xfs_lsn_t               tail_lsn = 0;
        int                     i;
        LIST_HEAD(tmp);
 
@@ -727,9 +757,10 @@ xfs_trans_ail_update_bulk(
                                continue;
 
                        trace_xfs_ail_move(lip, lip->li_lsn, lsn);
+                       if (mlip == lip && !tail_lsn)
+                               tail_lsn = lip->li_lsn;
+
                        xfs_ail_delete(ailp, lip);
-                       if (mlip == lip)
-                               mlip_changed = 1;
                } else {
                        trace_xfs_ail_insert(lip, 0, lsn);
                }
@@ -740,23 +771,23 @@ xfs_trans_ail_update_bulk(
        if (!list_empty(&tmp))
                xfs_ail_splice(ailp, cur, &tmp, lsn);
 
-       if (mlip_changed) {
-               if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
-                       xlog_assign_tail_lsn_locked(ailp->ail_mount);
-               spin_unlock(&ailp->ail_lock);
-
-               xfs_log_space_wake(ailp->ail_mount);
-       } else {
-               spin_unlock(&ailp->ail_lock);
-       }
+       xfs_ail_update_finish(ailp, tail_lsn);
 }
 
-bool
+/*
+ * Delete one log item from the AIL.
+ *
+ * If this item was at the tail of the AIL, return the LSN of the log item so
+ * that we can use it to check if the LSN of the tail of the log has moved
+ * when finishing up the AIL delete process in xfs_ail_update_finish().
+ */
+xfs_lsn_t
 xfs_ail_delete_one(
        struct xfs_ail          *ailp,
        struct xfs_log_item     *lip)
 {
        struct xfs_log_item     *mlip = xfs_ail_min(ailp);
+       xfs_lsn_t               lsn = lip->li_lsn;
 
        trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
        xfs_ail_delete(ailp, lip);
@@ -764,7 +795,9 @@ xfs_ail_delete_one(
        clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
        lip->li_lsn = 0;
 
-       return mlip == lip;
+       if (mlip == lip)
+               return lsn;
+       return 0;
 }
 
 /**
@@ -792,10 +825,10 @@ void
 xfs_trans_ail_delete(
        struct xfs_ail          *ailp,
        struct xfs_log_item     *lip,
-       int                     shutdown_type) __releases(ailp->ail_lock)
+       int                     shutdown_type)
 {
        struct xfs_mount        *mp = ailp->ail_mount;
-       bool                    mlip_changed;
+       xfs_lsn_t               tail_lsn;
 
        if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
                spin_unlock(&ailp->ail_lock);
@@ -808,17 +841,8 @@ xfs_trans_ail_delete(
                return;
        }
 
-       mlip_changed = xfs_ail_delete_one(ailp, lip);
-       if (mlip_changed) {
-               if (!XFS_FORCED_SHUTDOWN(mp))
-                       xlog_assign_tail_lsn_locked(mp);
-               if (list_empty(&ailp->ail_head))
-                       wake_up_all(&ailp->ail_empty);
-       }
-
-       spin_unlock(&ailp->ail_lock);
-       if (mlip_changed)
-               xfs_log_space_wake(ailp->ail_mount);
+       tail_lsn = xfs_ail_delete_one(ailp, lip);
+       xfs_ail_update_finish(ailp, tail_lsn);
 }
 
 int
index 2e073c1..35655ea 100644 (file)
@@ -91,9 +91,11 @@ xfs_trans_ail_update(
        xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
 }
 
-bool xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
+xfs_lsn_t xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
+void xfs_ail_update_finish(struct xfs_ail *ailp, xfs_lsn_t old_lsn)
+                       __releases(ailp->ail_lock);
 void xfs_trans_ail_delete(struct xfs_ail *ailp, struct xfs_log_item *lip,
-               int shutdown_type) __releases(ailp->ail_lock);
+               int shutdown_type);
 
 static inline void
 xfs_trans_ail_remove(
index 25f0523..531ca87 100644 (file)
@@ -248,8 +248,7 @@ int omap_dm_timers_active(void);
 
 /*
  * The below are inlined to optimize code size for system timers. Other code
- * should not need these at all, see
- * include/linux/platform_data/pwm_omap_dmtimer.h
+ * should not need these at all.
  */
 #if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS)
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
index 7aa2f93..b0dcc07 100644 (file)
@@ -42,9 +42,10 @@ int analogix_dp_resume(struct analogix_dp_device *dp);
 int analogix_dp_suspend(struct analogix_dp_device *dp);
 
 struct analogix_dp_device *
-analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-                struct analogix_dp_plat_data *plat_data);
+analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data);
+int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev);
 void analogix_dp_unbind(struct analogix_dp_device *dp);
+void analogix_dp_remove(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
index dcef359..aed382c 100644 (file)
@@ -136,7 +136,7 @@ struct drm_sg_mem {
  * Kernel side of a mapping
  */
 struct drm_local_map {
-       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
+       dma_addr_t offset;       /**< Requested physical address (0 for SAREA)*/
        unsigned long size;      /**< Requested physical size (bytes) */
        enum drm_map_type type;  /**< Type of memory to map */
        enum drm_map_flags flags;        /**< Flags */
index e4a6949..35f8ffe 100644 (file)
@@ -46,6 +46,7 @@ struct blkcg_gq;
 struct blkcg {
        struct cgroup_subsys_state      css;
        spinlock_t                      lock;
+       refcount_t                      online_pin;
 
        struct radix_tree_root          blkg_tree;
        struct blkcg_gq __rcu           *blkg_hint;
@@ -56,7 +57,6 @@ struct blkcg {
        struct list_head                all_blkcgs_node;
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct list_head                cgwb_list;
-       refcount_t                      cgwb_refcnt;
 #endif
 };
 
@@ -412,47 +412,38 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd)
 
 extern void blkcg_destroy_blkgs(struct blkcg *blkcg);
 
-#ifdef CONFIG_CGROUP_WRITEBACK
-
 /**
- * blkcg_cgwb_get - get a reference for blkcg->cgwb_list
+ * blkcg_pin_online - pin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
+ * While pinned, a blkcg is kept online.  This is primarily used to
+ * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline
+ * while an associated cgwb is still active.
  */
-static inline void blkcg_cgwb_get(struct blkcg *blkcg)
+static inline void blkcg_pin_online(struct blkcg *blkcg)
 {
-       refcount_inc(&blkcg->cgwb_refcnt);
+       refcount_inc(&blkcg->online_pin);
 }
 
 /**
- * blkcg_cgwb_put - put a reference for @blkcg->cgwb_list
+ * blkcg_unpin_online - unpin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
- * When this count goes to zero, all active wb has finished so the
+ * This is primarily used to impedance-match blkg and cgwb lifetimes so
+ * that blkg doesn't go offline while an associated cgwb is still active.
+ * When this count goes to zero, all active cgwbs have finished so the
  * blkcg can continue destruction by calling blkcg_destroy_blkgs().
- * This work may occur in cgwb_release_workfn() on the cgwb_release
- * workqueue.
  */
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
+static inline void blkcg_unpin_online(struct blkcg *blkcg)
 {
-       if (refcount_dec_and_test(&blkcg->cgwb_refcnt))
+       do {
+               if (!refcount_dec_and_test(&blkcg->online_pin))
+                       break;
                blkcg_destroy_blkgs(blkcg);
+               blkcg = blkcg_parent(blkcg);
+       } while (blkcg);
 }
 
-#else
-
-static inline void blkcg_cgwb_get(struct blkcg *blkcg) { }
-
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
-{
-       /* wb isn't being accounted, so trigger destruction right away */
-       blkcg_destroy_blkgs(blkcg);
-}
-
-#endif
-
 /**
  * blkg_path - format cgroup path of blkg
  * @blkg: blkg of interest
index 6d0d70f..10f8162 100644 (file)
@@ -270,8 +270,6 @@ struct nvme_fc_remote_port {
  *
  * Host/Initiator Transport Entrypoints/Parameters:
  *
- * @module:  The LLDD module using the interface
- *
  * @localport_delete:  The LLDD initiates deletion of a localport via
  *       nvme_fc_deregister_localport(). However, the teardown is
  *       asynchronous. This routine is called upon the completion of the
@@ -385,8 +383,6 @@ struct nvme_fc_remote_port {
  *       Value is Mandatory. Allowed to be zero.
  */
 struct nvme_fc_port_template {
-       struct module   *module;
-
        /* initiator-based functions */
        void    (*localport_delete)(struct nvme_fc_local_port *);
        void    (*remoteport_delete)(struct nvme_fc_remote_port *);
index 01a0d4e..cc896f0 100644 (file)
@@ -60,6 +60,7 @@ struct pid
 {
        refcount_t count;
        unsigned int level;
+       spinlock_t lock;
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
        struct hlist_head inodes;
diff --git a/include/linux/platform_data/pwm_omap_dmtimer.h b/include/linux/platform_data/pwm_omap_dmtimer.h
deleted file mode 100644 (file)
index e7d521e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * include/linux/platform_data/pwm_omap_dmtimer.h
- *
- * OMAP Dual-Mode Timer PWM platform data
- *
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
- * Tarun Kanti DebBarma <tarun.kanti@ti.com>
- * Thara Gopinath <thara@ti.com>
- *
- * Platform device conversion and hwmod support.
- *
- * Copyright (C) 2005 Nokia Corporation
- * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
- * PWM and clock framework support by Timo Teras.
- *
- * 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 SOFTWARE IS PROVIDED ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * 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.
- *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __PWM_OMAP_DMTIMER_PDATA_H
-#define __PWM_OMAP_DMTIMER_PDATA_H
-
-/* clock sources */
-#define PWM_OMAP_DMTIMER_SRC_SYS_CLK                   0x00
-#define PWM_OMAP_DMTIMER_SRC_32_KHZ                    0x01
-#define PWM_OMAP_DMTIMER_SRC_EXT_CLK                   0x02
-
-/* timer interrupt enable bits */
-#define PWM_OMAP_DMTIMER_INT_CAPTURE                   (1 << 2)
-#define PWM_OMAP_DMTIMER_INT_OVERFLOW                  (1 << 1)
-#define PWM_OMAP_DMTIMER_INT_MATCH                     (1 << 0)
-
-/* trigger types */
-#define PWM_OMAP_DMTIMER_TRIGGER_NONE                  0x00
-#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW              0x01
-#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE  0x02
-
-struct omap_dm_timer;
-typedef struct omap_dm_timer pwm_omap_dmtimer;
-
-struct pwm_omap_dmtimer_pdata {
-       pwm_omap_dmtimer *(*request_by_node)(struct device_node *np);
-       pwm_omap_dmtimer *(*request_specific)(int timer_id);
-       pwm_omap_dmtimer *(*request)(void);
-
-       int     (*free)(pwm_omap_dmtimer *timer);
-
-       void    (*enable)(pwm_omap_dmtimer *timer);
-       void    (*disable)(pwm_omap_dmtimer *timer);
-
-       int     (*get_irq)(pwm_omap_dmtimer *timer);
-       int     (*set_int_enable)(pwm_omap_dmtimer *timer, unsigned int value);
-       int     (*set_int_disable)(pwm_omap_dmtimer *timer, u32 mask);
-
-       struct clk *(*get_fclk)(pwm_omap_dmtimer *timer);
-
-       int     (*start)(pwm_omap_dmtimer *timer);
-       int     (*stop)(pwm_omap_dmtimer *timer);
-       int     (*set_source)(pwm_omap_dmtimer *timer, int source);
-
-       int     (*set_load)(pwm_omap_dmtimer *timer, int autoreload,
-                       unsigned int value);
-       int     (*set_match)(pwm_omap_dmtimer *timer, int enable,
-                       unsigned int match);
-       int     (*set_pwm)(pwm_omap_dmtimer *timer, int def_on,
-                       int toggle, int trigger);
-       int     (*set_prescaler)(pwm_omap_dmtimer *timer, int prescaler);
-
-       unsigned int (*read_counter)(pwm_omap_dmtimer *timer);
-       int     (*write_counter)(pwm_omap_dmtimer *timer, unsigned int value);
-       unsigned int (*read_status)(pwm_omap_dmtimer *timer);
-       int     (*write_status)(pwm_omap_dmtimer *timer, unsigned int value);
-};
-
-#endif /* __PWM_OMAP_DMTIMER_PDATA_H */
index 1e6108b..e061635 100644 (file)
@@ -202,7 +202,6 @@ __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
 void dump_stack_print_info(const char *log_lvl);
 void show_regs_print_info(const char *log_lvl);
 extern asmlinkage void dump_stack(void) __cold;
-extern void printk_safe_init(void);
 extern void printk_safe_flush(void);
 extern void printk_safe_flush_on_panic(void);
 #else
@@ -269,10 +268,6 @@ static inline void dump_stack(void)
 {
 }
 
-static inline void printk_safe_init(void)
-{
-}
-
 static inline void printk_safe_flush(void)
 {
 }
index 0ef808d..2635b2a 100644 (file)
@@ -71,7 +71,8 @@ struct pwm_state {
  * @chip: PWM chip providing this PWM device
  * @chip_data: chip-private data associated with the PWM device
  * @args: PWM arguments
- * @state: curent PWM channel state
+ * @state: last applied state
+ * @last: last implemented state (for PWM_DEBUG)
  */
 struct pwm_device {
        const char *label;
@@ -83,6 +84,7 @@ struct pwm_device {
 
        struct pwm_args args;
        struct pwm_state state;
+       struct pwm_state last;
 };
 
 /**
index 78bac99..d4825b8 100644 (file)
@@ -351,7 +351,7 @@ struct snd_soc_dai {
 
        /* bit field */
        unsigned int probed:1;
-       unsigned int started:1;
+       unsigned int started[SNDRV_PCM_STREAM_LAST + 1];
 };
 
 static inline struct snd_soc_pcm_stream *
index c0e6a05..12b0dcb 100644 (file)
@@ -14,8 +14,8 @@
 
 unsigned xen_evtchn_nr_channels(void);
 
-int bind_evtchn_to_irq(unsigned int evtchn);
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irq(evtchn_port_t evtchn);
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags, const char *devname,
                              void *dev_id);
@@ -31,9 +31,9 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
                           const char *devname,
                           void *dev_id);
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port);
+                                  evtchn_port_t remote_port);
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
+                                         evtchn_port_t remote_port,
                                          irq_handler_t handler,
                                          unsigned long irqflags,
                                          const char *devname,
@@ -54,15 +54,15 @@ int xen_set_irq_priority(unsigned irq, unsigned priority);
 /*
  * Allow extra references to event channels exposed to userspace by evtchn
  */
-int evtchn_make_refcounted(unsigned int evtchn);
-int evtchn_get(unsigned int evtchn);
-void evtchn_put(unsigned int evtchn);
+int evtchn_make_refcounted(evtchn_port_t evtchn);
+int evtchn_get(evtchn_port_t evtchn);
+void evtchn_put(evtchn_port_t evtchn);
 
 void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
-void rebind_evtchn_irq(int evtchn, int irq);
+void rebind_evtchn_irq(evtchn_port_t evtchn, int irq);
 int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu);
 
-static inline void notify_remote_via_evtchn(int port)
+static inline void notify_remote_via_evtchn(evtchn_port_t port)
 {
        struct evtchn_send send = { .port = port };
        (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
@@ -86,9 +86,9 @@ void xen_poll_irq(int irq);
 void xen_poll_irq_timeout(int irq, u64 timeout);
 
 /* Determine the IRQ which is bound to an event channel */
-unsigned irq_from_evtchn(unsigned int evtchn);
+unsigned int irq_from_evtchn(evtchn_port_t evtchn);
 int irq_from_virq(unsigned int cpu, unsigned int virq);
-unsigned int evtchn_from_irq(unsigned irq);
+evtchn_port_t evtchn_from_irq(unsigned irq);
 
 #ifdef CONFIG_XEN_PVHVM
 /* Xen HVM evtchn vector callback */
index 45650c9..cf80e33 100644 (file)
@@ -220,7 +220,7 @@ struct evtchn_expand_array {
 #define EVTCHNOP_set_priority    13
 struct evtchn_set_priority {
        /* IN parameters. */
-       uint32_t port;
+       evtchn_port_t port;
        uint32_t priority;
 };
 
index 8c0d1ed..5a8315e 100644 (file)
@@ -47,6 +47,7 @@
 #include <xen/interface/grant_table.h>
 #include <xen/interface/io/xenbus.h>
 #include <xen/interface/io/xs_wire.h>
+#include <xen/interface/event_channel.h>
 
 #define XENBUS_MAX_RING_GRANT_ORDER 4
 #define XENBUS_MAX_RING_GRANTS      (1U << XENBUS_MAX_RING_GRANT_ORDER)
@@ -212,8 +213,8 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
 
 int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
 
-int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
-int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port);
 
 enum xenbus_state xenbus_read_driver_state(const char *path);
 
index e488213..a48617f 100644 (file)
@@ -913,7 +913,6 @@ asmlinkage __visible void __init start_kernel(void)
        boot_init_stack_canary();
 
        time_init();
-       printk_safe_init();
        perf_event_init();
        profile_init();
        call_function_init();
index bc21c0f..c835b84 100644 (file)
@@ -256,6 +256,7 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid,
 
        get_pid_ns(ns);
        refcount_set(&pid->count, 1);
+       spin_lock_init(&pid->lock);
        for (type = 0; type < PIDTYPE_MAX; ++type)
                INIT_HLIST_HEAD(&pid->tasks[type]);
 
index ef90eb1..7959449 100644 (file)
@@ -196,6 +196,50 @@ unlock:
        return res;
 }
 
+struct compat_resume_swap_area {
+       compat_loff_t offset;
+       u32 dev;
+} __packed;
+
+static int snapshot_set_swap_area(struct snapshot_data *data,
+               void __user *argp)
+{
+       sector_t offset;
+       dev_t swdev;
+
+       if (swsusp_swap_in_use())
+               return -EPERM;
+
+       if (in_compat_syscall()) {
+               struct compat_resume_swap_area swap_area;
+
+               if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
+                       return -EFAULT;
+               swdev = new_decode_dev(swap_area.dev);
+               offset = swap_area.offset;
+       } else {
+               struct resume_swap_area swap_area;
+
+               if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
+                       return -EFAULT;
+               swdev = new_decode_dev(swap_area.dev);
+               offset = swap_area.offset;
+       }
+
+       /*
+        * User space encodes device types as two-byte values,
+        * so we need to recode them
+        */
+       if (!swdev) {
+               data->swap = -1;
+               return -EINVAL;
+       }
+       data->swap = swap_type_of(swdev, offset, NULL);
+       if (data->swap < 0)
+               return -ENODEV;
+       return 0;
+}
+
 static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                                                        unsigned long arg)
 {
@@ -351,34 +395,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                break;
 
        case SNAPSHOT_SET_SWAP_AREA:
-               if (swsusp_swap_in_use()) {
-                       error = -EPERM;
-               } else {
-                       struct resume_swap_area swap_area;
-                       dev_t swdev;
-
-                       error = copy_from_user(&swap_area, (void __user *)arg,
-                                       sizeof(struct resume_swap_area));
-                       if (error) {
-                               error = -EFAULT;
-                               break;
-                       }
-
-                       /*
-                        * User space encodes device types as two-byte values,
-                        * so we need to recode them
-                        */
-                       swdev = new_decode_dev(swap_area.dev);
-                       if (swdev) {
-                               offset = swap_area.offset;
-                               data->swap = swap_type_of(swdev, offset, NULL);
-                               if (data->swap < 0)
-                                       error = -ENODEV;
-                       } else {
-                               data->swap = -1;
-                               error = -EINVAL;
-                       }
-               }
+               error = snapshot_set_swap_area(data, (void __user *)arg);
                break;
 
        default:
@@ -393,12 +410,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 }
 
 #ifdef CONFIG_COMPAT
-
-struct compat_resume_swap_area {
-       compat_loff_t offset;
-       u32 dev;
-} __packed;
-
 static long
 snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -409,33 +420,13 @@ snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case SNAPSHOT_AVAIL_SWAP_SIZE:
        case SNAPSHOT_ALLOC_SWAP_PAGE:
        case SNAPSHOT_CREATE_IMAGE:
+       case SNAPSHOT_SET_SWAP_AREA:
                return snapshot_ioctl(file, cmd,
                                      (unsigned long) compat_ptr(arg));
-
-       case SNAPSHOT_SET_SWAP_AREA: {
-               struct compat_resume_swap_area __user *u_swap_area =
-                       compat_ptr(arg);
-               struct resume_swap_area swap_area;
-               mm_segment_t old_fs;
-               int err;
-
-               err = get_user(swap_area.offset, &u_swap_area->offset);
-               err |= get_user(swap_area.dev, &u_swap_area->dev);
-               if (err)
-                       return -EFAULT;
-               old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
-                                    (unsigned long) &swap_area);
-               set_fs(old_fs);
-               return err;
-       }
-
        default:
                return snapshot_ioctl(file, cmd, arg);
        }
 }
-
 #endif /* CONFIG_COMPAT */
 
 static const struct file_operations snapshot_fops = {
index c8e6ab6..b2b0f52 100644 (file)
@@ -23,6 +23,9 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args);
 void __printk_safe_enter(void);
 void __printk_safe_exit(void);
 
+void printk_safe_init(void);
+bool printk_percpu_data_ready(void);
+
 #define printk_safe_enter_irqsave(flags)       \
        do {                                    \
                local_irq_save(flags);          \
@@ -64,4 +67,6 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; }
 #define printk_safe_enter_irq() local_irq_disable()
 #define printk_safe_exit_irq() local_irq_enable()
 
+static inline void printk_safe_init(void) { }
+static inline bool printk_percpu_data_ready(void) { return false; }
 #endif /* CONFIG_PRINTK */
index 633f41a..9a9b615 100644 (file)
@@ -460,6 +460,18 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
 
+/*
+ * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before
+ * per_cpu_areas are initialised. This variable is set to true when
+ * it's safe to access per-CPU data.
+ */
+static bool __printk_percpu_data_ready __read_mostly;
+
+bool printk_percpu_data_ready(void)
+{
+       return __printk_percpu_data_ready;
+}
+
 /* Return log buffer address */
 char *log_buf_addr_get(void)
 {
@@ -1146,12 +1158,28 @@ static void __init log_buf_add_cpu(void)
 static inline void log_buf_add_cpu(void) {}
 #endif /* CONFIG_SMP */
 
+static void __init set_percpu_data_ready(void)
+{
+       printk_safe_init();
+       /* Make sure we set this flag only after printk_safe() init is done */
+       barrier();
+       __printk_percpu_data_ready = true;
+}
+
 void __init setup_log_buf(int early)
 {
        unsigned long flags;
        char *new_log_buf;
        unsigned int free;
 
+       /*
+        * Some archs call setup_log_buf() multiple times - first is very
+        * early, e.g. from setup_arch(), and second - when percpu_areas
+        * are initialised.
+        */
+       if (!early)
+               set_percpu_data_ready();
+
        if (log_buf != __log_buf)
                return;
 
@@ -2975,6 +3003,9 @@ static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
 
 void wake_up_klogd(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        if (waitqueue_active(&log_wait)) {
                this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
@@ -2985,6 +3016,9 @@ void wake_up_klogd(void)
 
 void defer_console_output(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
        irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
index b4045e7..d9a659a 100644 (file)
@@ -27,7 +27,6 @@
  * There are situations when we want to make sure that all buffers
  * were handled or when IRQs are blocked.
  */
-static int printk_safe_irq_ready __read_mostly;
 
 #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -    \
                                sizeof(atomic_t) -                      \
@@ -51,7 +50,7 @@ static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
 /* Get flushed in a more safe context. */
 static void queue_flush_work(struct printk_safe_seq_buf *s)
 {
-       if (printk_safe_irq_ready)
+       if (printk_percpu_data_ready())
                irq_work_queue(&s->work);
 }
 
@@ -402,14 +401,6 @@ void __init printk_safe_init(void)
 #endif
        }
 
-       /*
-        * In the highly unlikely event that a NMI were to trigger at
-        * this moment. Make sure IRQ work is set up before this
-        * variable is set.
-        */
-       barrier();
-       printk_safe_irq_ready = 1;
-
        /* Flush pending messages that did not have scheduled IRQ works. */
        printk_safe_flush();
 }
index 62f05f6..c81b4f3 100644 (file)
@@ -491,8 +491,8 @@ static void cgwb_release_workfn(struct work_struct *work)
        css_put(wb->blkcg_css);
        mutex_unlock(&wb->bdi->cgwb_release_mutex);
 
-       /* triggers blkg destruction if cgwb_refcnt becomes zero */
-       blkcg_cgwb_put(blkcg);
+       /* triggers blkg destruction if no online users left */
+       blkcg_unpin_online(blkcg);
 
        fprop_local_destroy_percpu(&wb->memcg_completions);
        percpu_ref_exit(&wb->refcnt);
@@ -592,7 +592,7 @@ static int cgwb_create(struct backing_dev_info *bdi,
                        list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
                        list_add(&wb->memcg_node, memcg_cgwb_list);
                        list_add(&wb->blkcg_node, blkcg_cgwb_list);
-                       blkcg_cgwb_get(blkcg);
+                       blkcg_pin_online(blkcg);
                        css_get(memcg_css);
                        css_get(blkcg_css);
                }
index fbda4eb..59d62f0 100644 (file)
@@ -197,7 +197,8 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
 }
 
 static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
-                                        snd_pcm_sframes_t frames)
+                                        snd_pcm_sframes_t frames,
+                                        bool check_size)
 {
        struct snd_pcm_plugin *plugin, *plugin_next;
 
@@ -209,7 +210,7 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
                        if (frames < 0)
                                return frames;
                }
-               if (frames > plugin->buf_frames)
+               if (check_size && frames > plugin->buf_frames)
                        frames = plugin->buf_frames;
                plugin = plugin_next;
        }
@@ -217,13 +218,14 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
 }
 
 static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
-                                        snd_pcm_sframes_t frames)
+                                        snd_pcm_sframes_t frames,
+                                        bool check_size)
 {
        struct snd_pcm_plugin *plugin, *plugin_prev;
 
        plugin = snd_pcm_plug_last(plug);
        while (plugin && frames > 0) {
-               if (frames > plugin->buf_frames)
+               if (check_size && frames > plugin->buf_frames)
                        frames = plugin->buf_frames;
                plugin_prev = plugin->prev;
                if (plugin->src_frames) {
@@ -242,9 +244,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
                return -ENXIO;
        switch (snd_pcm_plug_stream(plug)) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               return calc_src_frames(plug, drv_frames);
+               return calc_src_frames(plug, drv_frames, false);
        case SNDRV_PCM_STREAM_CAPTURE:
-               return calc_dst_frames(plug, drv_frames);
+               return calc_dst_frames(plug, drv_frames, false);
        default:
                snd_BUG();
                return -EINVAL;
@@ -257,9 +259,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
                return -ENXIO;
        switch (snd_pcm_plug_stream(plug)) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               return calc_dst_frames(plug, clt_frames);
+               return calc_dst_frames(plug, clt_frames, false);
        case SNDRV_PCM_STREAM_CAPTURE:
-               return calc_src_frames(plug, clt_frames);
+               return calc_src_frames(plug, clt_frames, false);
        default:
                snd_BUG();
                return -EINVAL;
@@ -622,7 +624,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
                src_channels = dst_channels;
                plugin = next;
        }
-       return snd_pcm_plug_client_size(plug, frames);
+       return calc_src_frames(plug, frames, true);
 }
 
 snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size)
@@ -632,7 +634,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
        snd_pcm_sframes_t frames = size;
        int err;
 
-       frames = snd_pcm_plug_slave_size(plug, frames);
+       frames = calc_src_frames(plug, frames, true);
        if (frames < 0)
                return frames;
 
index f5fd62e..841523f 100644 (file)
@@ -290,8 +290,12 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
+       int chs = get_amp_channels(kcontrol);
+
        if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) {
-               ucontrol->value.integer.value[0] =
+               if (chs & 1)
+                       ucontrol->value.integer.value[0] = beep->enabled;
+               if (chs & 2)
                        ucontrol->value.integer.value[1] = beep->enabled;
                return 0;
        }
index 92a042e..bd09359 100644 (file)
@@ -2076,6 +2076,17 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
 #endif
 }
 
+/* Blacklist for skipping the whole probe:
+ * some HD-audio PCI entries are exposed without any codecs, and such devices
+ * should be ignored from the beginning.
+ */
+static const struct snd_pci_quirk driver_blacklist[] = {
+       SND_PCI_QUIRK(0x1043, 0x874f, "ASUS ROG Zenith II / Strix", 0),
+       SND_PCI_QUIRK(0x1462, 0xcb59, "MSI TRX40 Creator", 0),
+       SND_PCI_QUIRK(0x1462, 0xcb60, "MSI TRX40", 0),
+       {}
+};
+
 static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
        .pcm_mmap_prepare = pcm_mmap_prepare,
@@ -2092,6 +2103,11 @@ static int azx_probe(struct pci_dev *pci,
        bool schedule_probe;
        int err;
 
+       if (snd_pci_quirk_lookup(pci, driver_blacklist)) {
+               dev_info(&pci->dev, "Skipping the blacklisted device\n");
+               return -ENODEV;
+       }
+
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
index f66a481..de2826f 100644 (file)
@@ -86,6 +86,14 @@ struct alc_spec {
 
        unsigned int gpio_mute_led_mask;
        unsigned int gpio_mic_led_mask;
+       unsigned int mute_led_coef_idx;
+       unsigned int mute_led_coefbit_mask;
+       unsigned int mute_led_coefbit_on;
+       unsigned int mute_led_coefbit_off;
+       unsigned int mic_led_coef_idx;
+       unsigned int mic_led_coefbit_mask;
+       unsigned int mic_led_coefbit_on;
+       unsigned int mic_led_coefbit_off;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -2447,6 +2455,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
@@ -4178,6 +4187,111 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
        }
 }
 
+/* update mute-LED according to the speaker mute state via COEF bit */
+static void alc_fixup_mute_led_coefbit_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->mute_led_polarity)
+               enabled = !enabled;
+
+       /* temporarily power up/down for setting COEF bit */
+       enabled ? alc_update_coef_idx(codec, spec->mute_led_coef_idx,
+               spec->mute_led_coefbit_mask, spec->mute_led_coefbit_off) :
+                 alc_update_coef_idx(codec, spec->mute_led_coef_idx,
+               spec->mute_led_coefbit_mask, spec->mute_led_coefbit_on);
+}
+
+static void alc285_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef_idx = 0x0b;
+               spec->mute_led_coefbit_mask = 1<<3;
+               spec->mute_led_coefbit_on = 1<<3;
+               spec->mute_led_coefbit_off = 0;
+               spec->gen.vmaster_mute.hook = alc_fixup_mute_led_coefbit_hook;
+               spec->gen.vmaster_mute_enum = 1;
+       }
+}
+
+static void alc236_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef_idx = 0x34;
+               spec->mute_led_coefbit_mask = 1<<5;
+               spec->mute_led_coefbit_on = 0;
+               spec->mute_led_coefbit_off = 1<<5;
+               spec->gen.vmaster_mute.hook = alc_fixup_mute_led_coefbit_hook;
+               spec->gen.vmaster_mute_enum = 1;
+       }
+}
+
+/* turn on/off mic-mute LED per capture hook by coef bit */
+static void alc_hp_cap_micmute_update(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->gen.micmute_led.led_value)
+               alc_update_coef_idx(codec, spec->mic_led_coef_idx,
+                       spec->mic_led_coefbit_mask, spec->mic_led_coefbit_on);
+       else
+               alc_update_coef_idx(codec, spec->mic_led_coef_idx,
+                       spec->mic_led_coefbit_mask, spec->mic_led_coefbit_off);
+}
+
+static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef_idx = 0x19;
+               spec->mic_led_coefbit_mask = 1<<13;
+               spec->mic_led_coefbit_on = 1<<13;
+               spec->mic_led_coefbit_off = 0;
+               snd_hda_gen_add_micmute_led(codec, alc_hp_cap_micmute_update);
+       }
+}
+
+static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef_idx = 0x35;
+               spec->mic_led_coefbit_mask = 3<<2;
+               spec->mic_led_coefbit_on = 2<<2;
+               spec->mic_led_coefbit_off = 1<<2;
+               snd_hda_gen_add_micmute_led(codec, alc_hp_cap_micmute_update);
+       }
+}
+
+static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc236_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
 #if IS_REACHABLE(CONFIG_INPUT)
 static void gpio2_mic_hotkey_event(struct hda_codec *codec,
                                   struct hda_jack_callback *event)
@@ -5964,6 +6078,8 @@ enum {
        ALC285_FIXUP_THINKPAD_HEADSET_JACK,
        ALC294_FIXUP_ASUS_HPE,
        ALC285_FIXUP_HP_GPIO_LED,
+       ALC285_FIXUP_HP_MUTE_LED,
+       ALC236_FIXUP_HP_MUTE_LED,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -7089,6 +7205,14 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_hp_gpio_led,
        },
+       [ALC285_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_mute_led,
+       },
+       [ALC236_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_mute_led,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7234,6 +7358,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -7325,6 +7451,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
index 91f83ce..9aa12a6 100644 (file)
@@ -536,7 +536,7 @@ static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        mutex_lock(&ice->gpio_mutex);
-       ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
+       ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
        mutex_unlock(&ice->gpio_mutex);
        return 0;
 }
@@ -550,7 +550,7 @@ static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&ice->gpio_mutex);
        oval = wm_get(ice, WM_ADC_MUX);
-       nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
+       nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0];
        if (nval != oval) {
                wm_put(ice, WM_ADC_MUX, nval);
                change = 1;
index 3a3c47e..f160d35 100644 (file)
@@ -139,6 +139,7 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
                rv_writel(adata->tdm_fmt, rtd->acp3x_base + frmt_reg);
        }
        val = rv_readl(rtd->acp3x_base + reg_val);
+       val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
        val = val | (rtd->xfer_resolution  << 3);
        rv_writel(val, rtd->acp3x_base + reg_val);
        return 0;
index 21e7ac0..03fe939 100644 (file)
@@ -76,6 +76,8 @@
 #define ACP_POWERED_OFF                        0x02
 #define ACP_POWER_OFF_IN_PROGRESS      0x03
 
+#define ACP3x_ITER_IRER_SAMP_LEN_MASK  0x38
+
 struct acp3x_platform_info {
        u16 play_i2s_instance;
        u16 cap_i2s_instance;
index e46c390..b7a1efc 100644 (file)
@@ -181,7 +181,7 @@ bcm63xx_pcm_pointer(struct snd_soc_component *component,
        snd_pcm_uframes_t x;
        struct bcm63xx_runtime_data *prtd = substream->runtime->private_data;
 
-       if ((void *)prtd->dma_addr_next == NULL)
+       if (!prtd->dma_addr_next)
                prtd->dma_addr_next = substream->runtime->dma_addr;
 
        x = bytes_to_frames(substream->runtime,
index 5f25b9f..8a02791 100644 (file)
@@ -137,6 +137,9 @@ struct cs4270_private {
 
        /* power domain regulators */
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+
+       /* reset gpio */
+       struct gpio_desc *reset_gpio;
 };
 
 static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
@@ -649,6 +652,22 @@ static const struct regmap_config cs4270_regmap = {
 };
 
 /**
+ * cs4270_i2c_remove - deinitialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ *
+ * This function puts the chip into low power mode when the i2c device
+ * is removed.
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+       struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+
+       gpiod_set_value_cansleep(cs4270->reset_gpio, 0);
+
+       return 0;
+}
+
+/**
  * cs4270_i2c_probe - initialize the I2C interface of the CS4270
  * @i2c_client: the I2C client object
  * @id: the I2C device ID (ignored)
@@ -660,7 +679,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
        struct cs4270_private *cs4270;
-       struct gpio_desc *reset_gpiod;
        unsigned int val;
        int ret, i;
 
@@ -679,10 +697,21 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        if (ret < 0)
                return ret;
 
-       reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
-                                             GPIOD_OUT_HIGH);
-       if (PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       /* reset the device */
+       cs4270->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(cs4270->reset_gpio)) {
+               dev_dbg(&i2c_client->dev, "Error getting CS4270 reset GPIO\n");
+               return PTR_ERR(cs4270->reset_gpio);
+       }
+
+       if (cs4270->reset_gpio) {
+               dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+               gpiod_set_value_cansleep(cs4270->reset_gpio, 1);
+       }
+
+       /* Sleep 500ns before i2c communications */
+       ndelay(500);
 
        cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
        if (IS_ERR(cs4270->regmap))
@@ -735,6 +764,7 @@ static struct i2c_driver cs4270_i2c_driver = {
        },
        .id_table = cs4270_id,
        .probe = cs4270_i2c_probe,
+       .remove = cs4270_i2c_remove,
 };
 
 module_i2c_driver(cs4270_i2c_driver);
index 92d6701..6ba1849 100644 (file)
@@ -3758,6 +3758,14 @@ static const struct dmi_system_id dmi_platform_data[] = {
                },
                .driver_data = (void *)&kahlee_platform_data,
        },
+       {
+               .ident = "Medion E1239T",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "E1239T MD60568"),
+               },
+               .driver_data = (void *)&intel_braswell_platform_data,
+       },
        { }
 };
 
index c9268a2..d36f560 100644 (file)
@@ -3703,7 +3703,7 @@ static const struct acpi_device_id rt5682_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
 #endif
 
-static struct i2c_driver rt5682_i2c_driver = {
+static struct i2c_driver __maybe_unused rt5682_i2c_driver = {
        .driver = {
                .name = "rt5682",
                .of_match_table = of_match_ptr(rt5682_of_match),
@@ -3713,7 +3713,10 @@ static struct i2c_driver rt5682_i2c_driver = {
        .shutdown = rt5682_i2c_shutdown,
        .id_table = rt5682_i2c_id,
 };
+
+#ifdef CONFIG_I2C
 module_i2c_driver(rt5682_i2c_driver);
+#endif
 
 MODULE_DESCRIPTION("ASoC RT5682 driver");
 MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
index f883c93..69f3af4 100644 (file)
@@ -50,6 +50,8 @@ static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
 {
        int ret = 0;
 
+       WARN_ON(!mutex_is_locked(&drv->lock));
+
        ret = sst_fill_byte_control(drv, ipc_msg,
                                block, task_id, pipe_id, len, cmd_data);
        if (ret < 0)
@@ -966,7 +968,9 @@ static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
        dev_dbg(c->dev, "Enter: widget=%s\n", w->name);
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
+               mutex_lock(&drv->lock);
                ret = sst_send_slot_map(drv);
+               mutex_unlock(&drv->lock);
                if (ret)
                        return ret;
                ret = sst_send_pipe_module_params(w, k);
index 13db285..053c277 100644 (file)
@@ -223,9 +223,9 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
                size_t mbox_data_len, const void *mbox_data, void **data,
                bool large, bool fill_dsp, bool sync, bool response)
 {
+       struct sst_block *block = NULL;
        struct ipc_post *msg = NULL;
        struct ipc_dsp_hdr dsp_hdr;
-       struct sst_block *block;
        int ret = 0, pvt_id;
 
        pvt_id = sst_assign_pvt_id(sst);
index 6c2fdb5..af2f502 100644 (file)
@@ -254,7 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &bdw_rt5650_ops,
index 6b4b640..cc41a34 100644 (file)
@@ -340,7 +340,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &bdw_rt5677_ops,
index acb4e36..f9a8336 100644 (file)
@@ -217,7 +217,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
                .init = broadwell_rt286_codec_init,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &broadwell_rt286_ops,
index 33fb8ea..08f4ae9 100644 (file)
@@ -591,6 +591,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {
+               /* MPMAN MPWIN895CL */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MPMAN"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MPWIN8900CL"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* MSI S100 tablet */
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
index 3ed53d7..74af090 100644 (file)
@@ -162,7 +162,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = haswell_ssp0_fixup,
                .ops = &haswell_rt5640_ops,
index f6c7cdd..125af00 100644 (file)
@@ -78,7 +78,7 @@ struct q6asm_dai_data {
 };
 
 static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                SNDRV_PCM_INFO_MMAP_VALID |
                                SNDRV_PCM_INFO_INTERLEAVED |
@@ -100,7 +100,7 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
 };
 
 static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                SNDRV_PCM_INFO_MMAP_VALID |
                                SNDRV_PCM_INFO_INTERLEAVED |
index 19142f6..8f3cad8 100644 (file)
@@ -295,12 +295,12 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
 {
        int ret = 0;
 
-       if (!dai->started &&
+       if (!dai->started[substream->stream] &&
            dai->driver->ops->startup)
                ret = dai->driver->ops->startup(substream, dai);
 
        if (ret == 0)
-               dai->started = 1;
+               dai->started[substream->stream] = 1;
 
        return ret;
 }
@@ -308,11 +308,11 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
                         struct snd_pcm_substream *substream)
 {
-       if (dai->started &&
+       if (dai->started[substream->stream] &&
            dai->driver->ops->shutdown)
                dai->driver->ops->shutdown(substream, dai);
 
-       dai->started = 0;
+       dai->started[substream->stream] = 0;
 }
 
 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
index 04da792..679ed60 100644 (file)
@@ -802,7 +802,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
                        val = max - val;
                p->connect = !!val;
        } else {
-               p->connect = 0;
+               /* since a virtual mixer has no backing registers to
+                * decide which path to connect, it will try to match
+                * with initial state.  This is to ensure
+                * that the default mixer choice will be
+                * correctly powered up during initialization.
+                */
+               p->connect = invert;
        }
 }
 
index 652657d..55ffb34 100644 (file)
@@ -825,7 +825,7 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
        unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
-       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int regwmask = (1UL<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
        long min = mc->min;
@@ -874,7 +874,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
        unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
-       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int regwmask = (1UL<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
        long max = mc->max;
index e256d43..289aebc 100644 (file)
@@ -2324,7 +2324,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                switch (cmd) {
                case SNDRV_PCM_TRIGGER_START:
                        if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
-                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
                        ret = dpcm_do_trigger(dpcm, be_substream, cmd);
@@ -2354,7 +2355,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
-                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+                       if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
                        if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
index 1f81cd2..87f75ed 100644 (file)
@@ -362,7 +362,7 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
        struct snd_soc_component *comp = tplg->comp;
 
        return soc_tplg_add_dcontrol(comp->card->snd_card,
-                               comp->dev, k, NULL, comp, kcontrol);
+                               comp->dev, k, comp->name_prefix, comp, kcontrol);
 }
 
 /* remove a mixer kcontrol */
index 1f2e0be..64af082 100644 (file)
@@ -597,7 +597,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
        }
 
        if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
-               dev_info(sdev->dev, "firmware boot complete\n");
+               dev_dbg(sdev->dev, "firmware boot complete\n");
        else
                return -EIO; /* FW boots but fw_ready op failed */
 
index 2bd280c..0d0c9af 100644 (file)
@@ -1556,8 +1556,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_component(&pdev->dev, &stm32_component,
                                         &sai->cpu_dai_drv, 1);
-       if (ret)
+       if (ret) {
+               snd_dmaengine_pcm_unregister(&pdev->dev);
                return ret;
+       }
 
        if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
                conf = &stm32_sai_pcm_config_spdif;
index 5ebca80..72b575c 100644 (file)
@@ -359,6 +359,14 @@ static const struct usbmix_name_map corsair_virtuoso_map[] = {
        { 0 }
 };
 
+/* Some mobos shipped with a dummy HD-audio show the invalid GET_MIN/GET_MAX
+ * response for Input Gain Pad (id=19, control=12).  Skip it.
+ */
+static const struct usbmix_name_map asus_rog_map[] = {
+       { 19, NULL, 12 }, /* FU, Input Gain Pad */
+       {}
+};
+
 /*
  * Control map entries
  */
@@ -488,6 +496,26 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x1b1c, 0x0a42),
                .map = corsair_virtuoso_map,
        },
+       {       /* Gigabyte TRX40 Aorus Pro WiFi */
+               .id = USB_ID(0x0414, 0xa002),
+               .map = asus_rog_map,
+       },
+       {       /* ASUS ROG Zenith II */
+               .id = USB_ID(0x0b05, 0x1916),
+               .map = asus_rog_map,
+       },
+       {       /* ASUS ROG Strix */
+               .id = USB_ID(0x0b05, 0x1917),
+               .map = asus_rog_map,
+       },
+       {       /* MSI TRX40 Creator */
+               .id = USB_ID(0x0db0, 0x0d64),
+               .map = asus_rog_map,
+       },
+       {       /* MSI TRX40 */
+               .id = USB_ID(0x0db0, 0x543d),
+               .map = asus_rog_map,
+       },
        { 0 } /* terminator */
 };
 
index 1c87192..e009d58 100644 (file)
@@ -3592,5 +3592,47 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
                }
        }
 },
+{
+       /*
+        * Pioneer DJ DJM-250MK2
+        * PCM is 8 channels out @ 48 fixed (endpoints 0x01).
+        * The output from computer to the mixer is usable.
+        *
+        * The input (phono or line to computer) is not working.
+        * It should be at endpoint 0x82 and probably also 8 channels,
+        * but it seems that it works only with Pioneer proprietary software.
+        * Even on officially supported OS, the Audacity was unable to record
+        * and Mixxx to recognize the control vinyls.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // outputs
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC|
+                                               USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 }
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
index 86f192a..a8ece17 100644 (file)
@@ -1827,6 +1827,7 @@ struct registration_quirk {
 
 static const struct registration_quirk registration_quirks[] = {
        REG_QUIRK_ENTRY(0x0951, 0x16d8, 2),     /* Kingston HyperX AMP */
+       REG_QUIRK_ENTRY(0x0951, 0x16ed, 2),     /* Kingston HyperX Cloud Alpha S */
        { 0 }                                   /* terminator */
 };