]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Mar 2017 10:49:24 +0000 (11:49 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Mar 2017 10:49:24 +0000 (11:49 +0100)
added patches:
acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch
acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch
block-allow-write_same-commands-with-the-sg_io-ioctl.patch
drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch
drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch
drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch
drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch
ibmveth-calculate-gso_segs-for-large-packets.patch
igb-add-i211-to-i210-phy-workaround.patch
igb-workaround-for-igb-i210-firmware-issue.patch
pci-add-comments-about-rom-bar-updating.patch
pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch
pci-do-any-vf-bar-updates-before-enabling-the-bars.patch
pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch
pci-ignore-bar-updates-on-virtual-functions.patch
pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch
pci-separate-vf-bar-updates-from-standard-bar-updates.patch
pci-update-bars-using-property-bits-appropriate-for-type.patch
powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch
powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch
powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch
powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch
s390-zcrypt-introduce-cex6-toleration.patch
scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch
scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch
scsi-ibmvscsis-rearrange-functions-for-future-patches.patch
scsi-ibmvscsis-return-correct-partition-name-to-client.patch
scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch
scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch
serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch
slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch
usb-gadget-udc-atmel-remove-memory-leak.patch
uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch
vfio-spapr-add-a-helper-to-create-default-dma-window.patch
vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch
vfio-spapr-postpone-default-window-creation.patch
vfio-spapr-reference-mm-in-tce_container.patch
x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch
xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch

40 files changed:
queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch [new file with mode: 0644]
queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch [new file with mode: 0644]
queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch [new file with mode: 0644]
queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch [new file with mode: 0644]
queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch [new file with mode: 0644]
queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch [new file with mode: 0644]
queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch [new file with mode: 0644]
queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch [new file with mode: 0644]
queue-4.9/igb-add-i211-to-i210-phy-workaround.patch [new file with mode: 0644]
queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch [new file with mode: 0644]
queue-4.9/pci-add-comments-about-rom-bar-updating.patch [new file with mode: 0644]
queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch [new file with mode: 0644]
queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch [new file with mode: 0644]
queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch [new file with mode: 0644]
queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch [new file with mode: 0644]
queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch [new file with mode: 0644]
queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch [new file with mode: 0644]
queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch [new file with mode: 0644]
queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch [new file with mode: 0644]
queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch [new file with mode: 0644]
queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch [new file with mode: 0644]
queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch [new file with mode: 0644]
queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch [new file with mode: 0644]
queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch [new file with mode: 0644]
queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch [new file with mode: 0644]
queue-4.9/series
queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch [new file with mode: 0644]
queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch [new file with mode: 0644]
queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch [new file with mode: 0644]
queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch [new file with mode: 0644]
queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch [new file with mode: 0644]
queue-4.9/vfio-spapr-postpone-default-window-creation.patch [new file with mode: 0644]
queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch [new file with mode: 0644]
queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch [new file with mode: 0644]
queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch [new file with mode: 0644]

diff --git a/queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch b/queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch
new file mode 100644 (file)
index 0000000..6878851
--- /dev/null
@@ -0,0 +1,52 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:32 +0000
+Subject: [PATCH v2 for-4.9 35/40] ACPI / blacklist: add _REV quirks for Dell Precision 5520 and 3520
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-35-alexander.levin@verizon.com>
+
+From: Alex Hung <alex.hung@canonical.com>
+
+[ Upstream commit 9523b9bf6dceef6b0215e90b2348cd646597f796 ]
+
+Precision 5520 and 3520 either hang at login and during suspend or reboot.
+
+It turns out that that adding them to acpi_rev_dmi_table[] helps to work
+around those issues.
+
+Signed-off-by: Alex Hung <alex.hung@canonical.com>
+[ rjw: Changelog ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/blacklist.c |   16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/acpi/blacklist.c
++++ b/drivers/acpi/blacklist.c
+@@ -160,6 +160,22 @@ static struct dmi_system_id acpi_rev_dmi
+                     DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"),
+               },
+       },
++      {
++       .callback = dmi_enable_rev_override,
++       .ident = "DELL Precision 5520",
++       .matches = {
++                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                    DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"),
++              },
++      },
++      {
++       .callback = dmi_enable_rev_override,
++       .ident = "DELL Precision 3520",
++       .matches = {
++                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                    DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"),
++              },
++      },
+ #endif
+       {}
+ };
diff --git a/queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch b/queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch
new file mode 100644 (file)
index 0000000..75a74ff
--- /dev/null
@@ -0,0 +1,48 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:32 +0000
+Subject: [PATCH v2 for-4.9 36/40] ACPI / blacklist: Make Dell Latitude 3350 ethernet work
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-36-alexander.levin@verizon.com>
+
+From: Michael Pobega <mpobega@neverware.com>
+
+[ Upstream commit 708f5dcc21ae9b35f395865fc154b0105baf4de4 ]
+
+The Dell Latitude 3350's ethernet card attempts to use a reserved
+IRQ (18), resulting in ACPI being unable to enable the ethernet.
+
+Adding it to acpi_rev_dmi_table[] helps to work around this problem.
+
+Signed-off-by: Michael Pobega <mpobega@neverware.com>
+[ rjw: Changelog ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/blacklist.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/acpi/blacklist.c
++++ b/drivers/acpi/blacklist.c
+@@ -176,6 +176,18 @@ static struct dmi_system_id acpi_rev_dmi
+                     DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"),
+               },
+       },
++      /*
++       * Resolves a quirk with the Dell Latitude 3350 that
++       * causes the ethernet adapter to not function.
++       */
++      {
++       .callback = dmi_enable_rev_override,
++       .ident = "DELL Latitude 3350",
++       .matches = {
++                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++                    DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"),
++              },
++      },
+ #endif
+       {}
+ };
diff --git a/queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch b/queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch
new file mode 100644 (file)
index 0000000..30ef704
--- /dev/null
@@ -0,0 +1,82 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:30 +0000
+Subject: [PATCH v2 for-4.9 31/40] block: allow WRITE_SAME commands with the SG_IO ioctl
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-31-alexander.levin@verizon.com>
+
+From: Mauricio Faria de Oliveira <mauricfo@linux.vnet.ibm.com>
+
+[ Upstream commit 25cdb64510644f3e854d502d69c73f21c6df88a9 ]
+
+The WRITE_SAME commands are not present in the blk_default_cmd_filter
+write_ok list, and thus are failed with -EPERM when the SG_IO ioctl()
+is executed without CAP_SYS_RAWIO capability (e.g., unprivileged users).
+[ sg_io() -> blk_fill_sghdr_rq() > blk_verify_command() -> -EPERM ]
+
+The problem can be reproduced with the sg_write_same command
+
+  # sg_write_same --num 1 --xferlen 512 /dev/sda
+  #
+
+  # capsh --drop=cap_sys_rawio -- -c \
+    'sg_write_same --num 1 --xferlen 512 /dev/sda'
+    Write same: pass through os error: Operation not permitted
+  #
+
+For comparison, the WRITE_VERIFY command does not observe this problem,
+since it is in that list:
+
+  # capsh --drop=cap_sys_rawio -- -c \
+    'sg_write_verify --num 1 --ilen 512 --lba 0 /dev/sda'
+  #
+
+So, this patch adds the WRITE_SAME commands to the list, in order
+for the SG_IO ioctl to finish successfully:
+
+  # capsh --drop=cap_sys_rawio -- -c \
+    'sg_write_same --num 1 --xferlen 512 /dev/sda'
+  #
+
+That case happens to be exercised by QEMU KVM guests with 'scsi-block' devices
+(qemu "-device scsi-block" [1], libvirt "<disk type='block' device='lun'>" [2]),
+which employs the SG_IO ioctl() and runs as an unprivileged user (libvirt-qemu).
+
+In that scenario, when a filesystem (e.g., ext4) performs its zero-out calls,
+which are translated to write-same calls in the guest kernel, and then into
+SG_IO ioctls to the host kernel, SCSI I/O errors may be observed in the guest:
+
+  [...] sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
+  [...] sd 0:0:0:0: [sda] tag#0 Sense Key : Aborted Command [current]
+  [...] sd 0:0:0:0: [sda] tag#0 Add. Sense: I/O process terminated
+  [...] sd 0:0:0:0: [sda] tag#0 CDB: Write Same(10) 41 00 01 04 e0 78 00 00 08 00
+  [...] blk_update_request: I/O error, dev sda, sector 17096824
+
+Links:
+[1] http://git.qemu.org/?p=qemu.git;a=commit;h=336a6915bc7089fb20fea4ba99972ad9a97c5f52
+[2] https://libvirt.org/formatdomain.html#elementsDisks (see 'disk' -> 'device')
+
+Signed-off-by: Mauricio Faria de Oliveira <mauricfo@linux.vnet.ibm.com>
+Signed-off-by: Brahadambal Srinivasan <latha@linux.vnet.ibm.com>
+Reported-by: Manjunatha H R <manjuhr1@in.ibm.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jens Axboe <axboe@fb.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/scsi_ioctl.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/block/scsi_ioctl.c
++++ b/block/scsi_ioctl.c
+@@ -182,6 +182,9 @@ static void blk_set_cmd_filter_defaults(
+       __set_bit(WRITE_16, filter->write_ok);
+       __set_bit(WRITE_LONG, filter->write_ok);
+       __set_bit(WRITE_LONG_2, filter->write_ok);
++      __set_bit(WRITE_SAME, filter->write_ok);
++      __set_bit(WRITE_SAME_16, filter->write_ok);
++      __set_bit(WRITE_SAME_32, filter->write_ok);
+       __set_bit(ERASE, filter->write_ok);
+       __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok);
+       __set_bit(MODE_SELECT, filter->write_ok);
diff --git a/queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch b/queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch
new file mode 100644 (file)
index 0000000..a9e1403
--- /dev/null
@@ -0,0 +1,91 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:26 +0000
+Subject: [PATCH v2 for-4.9 20/40] Drivers: hv: ring_buffer: count on wrap around mappings in get_next_pkt_raw() (v2)
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-20-alexander.levin@verizon.com>
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+[ Upstream commit fa32ff6576623616c1751562edaed8c164ca5199 ]
+
+With wrap around mappings in place we can always provide drivers with
+direct links to packets on the ring buffer, even when they wrap around.
+Do the required updates to get_next_pkt_raw()/put_pkt_raw()
+
+The first version of this commit was reverted (65a532f3d50a) to deal with
+cross-tree merge issues which are (hopefully) resolved now.
+
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Tested-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/hyperv.h |   32 +++++++++++---------------------
+ 1 file changed, 11 insertions(+), 21 deletions(-)
+
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -1548,31 +1548,23 @@ static inline struct vmpacket_descriptor
+ get_next_pkt_raw(struct vmbus_channel *channel)
+ {
+       struct hv_ring_buffer_info *ring_info = &channel->inbound;
+-      u32 read_loc = ring_info->priv_read_index;
++      u32 priv_read_loc = ring_info->priv_read_index;
+       void *ring_buffer = hv_get_ring_buffer(ring_info);
+-      struct vmpacket_descriptor *cur_desc;
+-      u32 packetlen;
+       u32 dsize = ring_info->ring_datasize;
+-      u32 delta = read_loc - ring_info->ring_buffer->read_index;
++      /*
++       * delta is the difference between what is available to read and
++       * what was already consumed in place. We commit read index after
++       * the whole batch is processed.
++       */
++      u32 delta = priv_read_loc >= ring_info->ring_buffer->read_index ?
++              priv_read_loc - ring_info->ring_buffer->read_index :
++              (dsize - ring_info->ring_buffer->read_index) + priv_read_loc;
+       u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
+       if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
+               return NULL;
+-      if ((read_loc + sizeof(*cur_desc)) > dsize)
+-              return NULL;
+-
+-      cur_desc = ring_buffer + read_loc;
+-      packetlen = cur_desc->len8 << 3;
+-
+-      /*
+-       * If the packet under consideration is wrapping around,
+-       * return failure.
+-       */
+-      if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1))
+-              return NULL;
+-
+-      return cur_desc;
++      return ring_buffer + priv_read_loc;
+ }
+ /*
+@@ -1584,16 +1576,14 @@ static inline void put_pkt_raw(struct vm
+                               struct vmpacket_descriptor *desc)
+ {
+       struct hv_ring_buffer_info *ring_info = &channel->inbound;
+-      u32 read_loc = ring_info->priv_read_index;
+       u32 packetlen = desc->len8 << 3;
+       u32 dsize = ring_info->ring_datasize;
+-      if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize)
+-              BUG();
+       /*
+        * Include the packet trailer.
+        */
+       ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
++      ring_info->priv_read_index %= dsize;
+ }
+ /*
diff --git a/queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch b/queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch
new file mode 100644 (file)
index 0000000..d5479da
--- /dev/null
@@ -0,0 +1,143 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:29 +0000
+Subject: [PATCH v2 for-4.9 28/40] drm/nouveau/disp/gp102: fix cursor/overlay immediate channel indices
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-28-alexander.levin@verizon.com>
+
+From: Ben Skeggs <bskeggs@redhat.com>
+
+[ Upstream commit e50fcff15fe120ef2103a9e18af6644235c2b14d ]
+
+Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild      |    2 +
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h  |    2 +
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgp102.c |   37 +++++++++++++++++++
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgp102.c |   37 +++++++++++++++++++
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c |    4 +-
+ 5 files changed, 80 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgp102.c
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgp102.c
+
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+@@ -95,9 +95,11 @@ nvkm-y += nvkm/engine/disp/cursg84.o
+ nvkm-y += nvkm/engine/disp/cursgt215.o
+ nvkm-y += nvkm/engine/disp/cursgf119.o
+ nvkm-y += nvkm/engine/disp/cursgk104.o
++nvkm-y += nvkm/engine/disp/cursgp102.o
+ nvkm-y += nvkm/engine/disp/oimmnv50.o
+ nvkm-y += nvkm/engine/disp/oimmg84.o
+ nvkm-y += nvkm/engine/disp/oimmgt215.o
+ nvkm-y += nvkm/engine/disp/oimmgf119.o
+ nvkm-y += nvkm/engine/disp/oimmgk104.o
++nvkm-y += nvkm/engine/disp/oimmgp102.o
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
+@@ -114,6 +114,8 @@ extern const struct nv50_disp_pioc_oclas
+ extern const struct nv50_disp_pioc_oclass gk104_disp_oimm_oclass;
+ extern const struct nv50_disp_pioc_oclass gk104_disp_curs_oclass;
++extern const struct nv50_disp_pioc_oclass gp102_disp_oimm_oclass;
++extern const struct nv50_disp_pioc_oclass gp102_disp_curs_oclass;
+ int nv50_disp_curs_new(const struct nv50_disp_chan_func *,
+                      const struct nv50_disp_chan_mthd *,
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgp102.c
+@@ -0,0 +1,37 @@
++/*
++ * Copyright 2016 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs <bskeggs@redhat.com>
++ */
++#include "channv50.h"
++#include "rootnv50.h"
++
++#include <nvif/class.h>
++
++const struct nv50_disp_pioc_oclass
++gp102_disp_curs_oclass = {
++      .base.oclass = GK104_DISP_CURSOR,
++      .base.minver = 0,
++      .base.maxver = 0,
++      .ctor = nv50_disp_curs_new,
++      .func = &gf119_disp_pioc_func,
++      .chid = { 13, 17 },
++};
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgp102.c
+@@ -0,0 +1,37 @@
++/*
++ * Copyright 2016 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Ben Skeggs <bskeggs@redhat.com>
++ */
++#include "channv50.h"
++#include "rootnv50.h"
++
++#include <nvif/class.h>
++
++const struct nv50_disp_pioc_oclass
++gp102_disp_oimm_oclass = {
++      .base.oclass = GK104_DISP_OVERLAY,
++      .base.minver = 0,
++      .base.maxver = 0,
++      .ctor = nv50_disp_oimm_new,
++      .func = &gf119_disp_pioc_func,
++      .chid = { 9, 13 },
++};
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c
+@@ -36,8 +36,8 @@ gp104_disp_root = {
+               &gp104_disp_ovly_oclass,
+       },
+       .pioc = {
+-              &gk104_disp_oimm_oclass,
+-              &gk104_disp_curs_oclass,
++              &gp102_disp_oimm_oclass,
++              &gp102_disp_curs_oclass,
+       },
+ };
diff --git a/queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch b/queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch
new file mode 100644 (file)
index 0000000..ab32fa6
--- /dev/null
@@ -0,0 +1,271 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:30 +0000
+Subject: [PATCH v2 for-4.9 30/40] drm/nouveau/disp/nv50-: specify ctrl/user separately when constructing classes
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-30-alexander.levin@verizon.com>
+
+From: Ben Skeggs <bskeggs@redhat.com>
+
+[ Upstream commit 2a32b9b1866a2ee9f01fbf2a48d99012f0120739 ]
+
+Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c  |   11 ++++++-----
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h  |   15 +++++++++------
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c   |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c  |    6 +++---
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c  |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c   |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c |    2 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c  |    6 +++---
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c  |    4 ++--
+ 14 files changed, 32 insertions(+), 28 deletions(-)
+
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+@@ -263,7 +263,7 @@ nv50_disp_chan = {
+ int
+ nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func,
+                   const struct nv50_disp_chan_mthd *mthd,
+-                  struct nv50_disp_root *root, int chid, int head,
++                  struct nv50_disp_root *root, int ctrl, int user, int head,
+                   const struct nvkm_oclass *oclass,
+                   struct nv50_disp_chan *chan)
+ {
+@@ -273,8 +273,8 @@ nv50_disp_chan_ctor(const struct nv50_di
+       chan->func = func;
+       chan->mthd = mthd;
+       chan->root = root;
+-      chan->chid.ctrl = chid;
+-      chan->chid.user = chid;
++      chan->chid.ctrl = ctrl;
++      chan->chid.user = user;
+       chan->head = head;
+       if (disp->chan[chan->chid.user]) {
+@@ -288,7 +288,7 @@ nv50_disp_chan_ctor(const struct nv50_di
+ int
+ nv50_disp_chan_new_(const struct nv50_disp_chan_func *func,
+                   const struct nv50_disp_chan_mthd *mthd,
+-                  struct nv50_disp_root *root, int chid, int head,
++                  struct nv50_disp_root *root, int ctrl, int user, int head,
+                   const struct nvkm_oclass *oclass,
+                   struct nvkm_object **pobject)
+ {
+@@ -298,5 +298,6 @@ nv50_disp_chan_new_(const struct nv50_di
+               return -ENOMEM;
+       *pobject = &chan->object;
+-      return nv50_disp_chan_ctor(func, mthd, root, chid, head, oclass, chan);
++      return nv50_disp_chan_ctor(func, mthd, root, ctrl, user,
++                                 head, oclass, chan);
+ }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
+@@ -29,11 +29,11 @@ struct nv50_disp_chan_func {
+ int nv50_disp_chan_ctor(const struct nv50_disp_chan_func *,
+                       const struct nv50_disp_chan_mthd *,
+-                      struct nv50_disp_root *, int chid, int head,
++                      struct nv50_disp_root *, int ctrl, int user, int head,
+                       const struct nvkm_oclass *, struct nv50_disp_chan *);
+ int nv50_disp_chan_new_(const struct nv50_disp_chan_func *,
+                       const struct nv50_disp_chan_mthd *,
+-                      struct nv50_disp_root *, int chid, int head,
++                      struct nv50_disp_root *, int ctrl, int user, int head,
+                       const struct nvkm_oclass *, struct nvkm_object **);
+ extern const struct nv50_disp_chan_func nv50_disp_pioc_func;
+@@ -94,13 +94,16 @@ extern const struct nv50_disp_chan_mthd
+ struct nv50_disp_pioc_oclass {
+       int (*ctor)(const struct nv50_disp_chan_func *,
+                   const struct nv50_disp_chan_mthd *,
+-                  struct nv50_disp_root *, int chid,
++                  struct nv50_disp_root *, int ctrl, int user,
+                   const struct nvkm_oclass *, void *data, u32 size,
+                   struct nvkm_object **);
+       struct nvkm_sclass base;
+       const struct nv50_disp_chan_func *func;
+       const struct nv50_disp_chan_mthd *mthd;
+-      int chid;
++      struct {
++              int ctrl;
++              int user;
++      } chid;
+ };
+ extern const struct nv50_disp_pioc_oclass nv50_disp_oimm_oclass;
+@@ -123,12 +126,12 @@ extern const struct nv50_disp_pioc_oclas
+ int nv50_disp_curs_new(const struct nv50_disp_chan_func *,
+                      const struct nv50_disp_chan_mthd *,
+-                     struct nv50_disp_root *, int chid,
++                     struct nv50_disp_root *, int ctrl, int user,
+                      const struct nvkm_oclass *, void *data, u32 size,
+                      struct nvkm_object **);
+ int nv50_disp_oimm_new(const struct nv50_disp_chan_func *,
+                      const struct nv50_disp_chan_mthd *,
+-                     struct nv50_disp_root *, int chid,
++                     struct nv50_disp_root *, int ctrl, int user,
+                      const struct nvkm_oclass *, void *data, u32 size,
+                      struct nvkm_object **);
+ #endif
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c
+@@ -33,5 +33,5 @@ g84_disp_curs_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_curs_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 7,
++      .chid = { 7, 7 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c
+@@ -33,5 +33,5 @@ gf119_disp_curs_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_curs_new,
+       .func = &gf119_disp_pioc_func,
+-      .chid = 13,
++      .chid = { 13, 13 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c
+@@ -33,5 +33,5 @@ gk104_disp_curs_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_curs_new,
+       .func = &gf119_disp_pioc_func,
+-      .chid = 13,
++      .chid = { 13, 13 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c
+@@ -33,5 +33,5 @@ gt215_disp_curs_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_curs_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 7,
++      .chid = { 7, 7 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
+@@ -33,7 +33,7 @@
+ int
+ nv50_disp_curs_new(const struct nv50_disp_chan_func *func,
+                  const struct nv50_disp_chan_mthd *mthd,
+-                 struct nv50_disp_root *root, int chid,
++                 struct nv50_disp_root *root, int ctrl, int user,
+                  const struct nvkm_oclass *oclass, void *data, u32 size,
+                  struct nvkm_object **pobject)
+ {
+@@ -54,7 +54,7 @@ nv50_disp_curs_new(const struct nv50_dis
+       } else
+               return ret;
+-      return nv50_disp_chan_new_(func, mthd, root, chid + head,
++      return nv50_disp_chan_new_(func, mthd, root, ctrl + head, user + head,
+                                  head, oclass, pobject);
+ }
+@@ -65,5 +65,5 @@ nv50_disp_curs_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_curs_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 7,
++      .chid = { 7, 7 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c
+@@ -149,7 +149,7 @@ nv50_disp_dmac_new_(const struct nv50_di
+       chan->func = func;
+       ret = nv50_disp_chan_ctor(&nv50_disp_dmac_func_, mthd, root,
+-                                chid, head, oclass, &chan->base);
++                                chid, chid, head, oclass, &chan->base);
+       if (ret)
+               return ret;
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c
+@@ -33,5 +33,5 @@ g84_disp_oimm_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_oimm_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 5,
++      .chid = { 5, 5 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c
+@@ -33,5 +33,5 @@ gf119_disp_oimm_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_oimm_new,
+       .func = &gf119_disp_pioc_func,
+-      .chid = 9,
++      .chid = { 9, 9 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c
+@@ -33,5 +33,5 @@ gk104_disp_oimm_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_oimm_new,
+       .func = &gf119_disp_pioc_func,
+-      .chid = 9,
++      .chid = { 9, 9 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c
+@@ -33,5 +33,5 @@ gt215_disp_oimm_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_oimm_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 5,
++      .chid = { 5, 5 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
+@@ -33,7 +33,7 @@
+ int
+ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func,
+                  const struct nv50_disp_chan_mthd *mthd,
+-                 struct nv50_disp_root *root, int chid,
++                 struct nv50_disp_root *root, int ctrl, int user,
+                  const struct nvkm_oclass *oclass, void *data, u32 size,
+                  struct nvkm_object **pobject)
+ {
+@@ -54,7 +54,7 @@ nv50_disp_oimm_new(const struct nv50_dis
+       } else
+               return ret;
+-      return nv50_disp_chan_new_(func, mthd, root, chid + head,
++      return nv50_disp_chan_new_(func, mthd, root, ctrl + head, user + head,
+                                  head, oclass, pobject);
+ }
+@@ -65,5 +65,5 @@ nv50_disp_oimm_oclass = {
+       .base.maxver = 0,
+       .ctor = nv50_disp_oimm_new,
+       .func = &nv50_disp_pioc_func,
+-      .chid = 5,
++      .chid = { 5, 5 },
+ };
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+@@ -207,8 +207,8 @@ nv50_disp_root_pioc_new_(const struct nv
+ {
+       const struct nv50_disp_pioc_oclass *sclass = oclass->priv;
+       struct nv50_disp_root *root = nv50_disp_root(oclass->parent);
+-      return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid,
+-                          oclass, data, size, pobject);
++      return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid.ctrl,
++                          sclass->chid.user, oclass, data, size, pobject);
+ }
+ static int
diff --git a/queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch b/queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch
new file mode 100644 (file)
index 0000000..9ebee8e
--- /dev/null
@@ -0,0 +1,450 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:29 +0000
+Subject: [PATCH v2 for-4.9 29/40] drm/nouveau/disp/nv50-: split chid into chid.ctrl and chid.user
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-29-alexander.levin@verizon.com>
+
+From: Ben Skeggs <bskeggs@redhat.com>
+
+[ Upstream commit 4391d7f5c79a9fe6fa11cf6c160ca7f7bdb49d2a ]
+
+GP102/GP104 make life difficult by redefining the channel indices for
+some registers, but not others.
+
+Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c  |   23 +++++----
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h  |    6 ++
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c |   44 +++++++++----------
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c |   23 +++++----
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c  |   44 +++++++++----------
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c |   28 ++++++------
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c  |   30 ++++++------
+ 7 files changed, 106 insertions(+), 92 deletions(-)
+
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+@@ -82,7 +82,7 @@ nv50_disp_chan_mthd(struct nv50_disp_cha
+                       if (mthd->addr) {
+                               snprintf(cname_, sizeof(cname_), "%s %d",
+-                                       mthd->name, chan->chid);
++                                       mthd->name, chan->chid.user);
+                               cname = cname_;
+                       }
+@@ -139,7 +139,7 @@ nv50_disp_chan_uevent_ctor(struct nvkm_o
+       if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
+               notify->size  = sizeof(struct nvif_notify_uevent_rep);
+               notify->types = 1;
+-              notify->index = chan->chid;
++              notify->index = chan->chid.user;
+               return 0;
+       }
+@@ -159,7 +159,7 @@ nv50_disp_chan_rd32(struct nvkm_object *
+       struct nv50_disp_chan *chan = nv50_disp_chan(object);
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_device *device = disp->base.engine.subdev.device;
+-      *data = nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr);
++      *data = nvkm_rd32(device, 0x640000 + (chan->chid.user * 0x1000) + addr);
+       return 0;
+ }
+@@ -169,7 +169,7 @@ nv50_disp_chan_wr32(struct nvkm_object *
+       struct nv50_disp_chan *chan = nv50_disp_chan(object);
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_device *device = disp->base.engine.subdev.device;
+-      nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data);
++      nvkm_wr32(device, 0x640000 + (chan->chid.user * 0x1000) + addr, data);
+       return 0;
+ }
+@@ -196,7 +196,7 @@ nv50_disp_chan_map(struct nvkm_object *o
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_device *device = disp->base.engine.subdev.device;
+       *addr = device->func->resource_addr(device, 0) +
+-              0x640000 + (chan->chid * 0x1000);
++              0x640000 + (chan->chid.user * 0x1000);
+       *size = 0x001000;
+       return 0;
+ }
+@@ -243,8 +243,8 @@ nv50_disp_chan_dtor(struct nvkm_object *
+ {
+       struct nv50_disp_chan *chan = nv50_disp_chan(object);
+       struct nv50_disp *disp = chan->root->disp;
+-      if (chan->chid >= 0)
+-              disp->chan[chan->chid] = NULL;
++      if (chan->chid.user >= 0)
++              disp->chan[chan->chid.user] = NULL;
+       return chan->func->dtor ? chan->func->dtor(chan) : chan;
+ }
+@@ -273,14 +273,15 @@ nv50_disp_chan_ctor(const struct nv50_di
+       chan->func = func;
+       chan->mthd = mthd;
+       chan->root = root;
+-      chan->chid = chid;
++      chan->chid.ctrl = chid;
++      chan->chid.user = chid;
+       chan->head = head;
+-      if (disp->chan[chan->chid]) {
+-              chan->chid = -1;
++      if (disp->chan[chan->chid.user]) {
++              chan->chid.user = -1;
+               return -EBUSY;
+       }
+-      disp->chan[chan->chid] = chan;
++      disp->chan[chan->chid.user] = chan;
+       return 0;
+ }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h
+@@ -7,7 +7,11 @@ struct nv50_disp_chan {
+       const struct nv50_disp_chan_func *func;
+       const struct nv50_disp_chan_mthd *mthd;
+       struct nv50_disp_root *root;
+-      int chid;
++
++      struct {
++              int ctrl;
++              int user;
++      } chid;
+       int head;
+       struct nvkm_object object;
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c
+@@ -32,8 +32,8 @@ gf119_disp_dmac_bind(struct nv50_disp_dm
+                    struct nvkm_object *object, u32 handle)
+ {
+       return nvkm_ramht_insert(chan->base.root->ramht, object,
+-                               chan->base.chid, -9, handle,
+-                               chan->base.chid << 27 | 0x00000001);
++                               chan->base.chid.user, -9, handle,
++                               chan->base.chid.user << 27 | 0x00000001);
+ }
+ void
+@@ -42,22 +42,23 @@ gf119_disp_dmac_fini(struct nv50_disp_dm
+       struct nv50_disp *disp = chan->base.root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->base.chid;
++      int ctrl = chan->base.chid.ctrl;
++      int user = chan->base.chid.user;
+       /* deactivate channel */
+-      nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
+-      nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
++      nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00001010, 0x00001000);
++      nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000003, 0x00000000);
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000))
++              if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x001e0000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d fini: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610490 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d fini: %08x\n", user,
++                         nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
+       }
+       /* disable error reporting and completion notification */
+-      nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000);
+-      nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000);
++      nvkm_mask(device, 0x610090, 0x00000001 << user, 0x00000000);
++      nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000000);
+ }
+ static int
+@@ -66,26 +67,27 @@ gf119_disp_dmac_init(struct nv50_disp_dm
+       struct nv50_disp *disp = chan->base.root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->base.chid;
++      int ctrl = chan->base.chid.ctrl;
++      int user = chan->base.chid.user;
+       /* enable error reporting */
+-      nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
++      nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user);
+       /* initialise channel for dma command submission */
+-      nvkm_wr32(device, 0x610494 + (chid * 0x0010), chan->push);
+-      nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000);
+-      nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001);
+-      nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
+-      nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000);
+-      nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013);
++      nvkm_wr32(device, 0x610494 + (ctrl * 0x0010), chan->push);
++      nvkm_wr32(device, 0x610498 + (ctrl * 0x0010), 0x00010000);
++      nvkm_wr32(device, 0x61049c + (ctrl * 0x0010), 0x00000001);
++      nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010);
++      nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000);
++      nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013);
+       /* wait for it to go inactive */
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000))
++              if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d init: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610490 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d init: %08x\n", user,
++                         nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c
+@@ -32,26 +32,27 @@ gp104_disp_dmac_init(struct nv50_disp_dm
+       struct nv50_disp *disp = chan->base.root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->base.chid;
++      int ctrl = chan->base.chid.ctrl;
++      int user = chan->base.chid.user;
+       /* enable error reporting */
+-      nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
++      nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user);
+       /* initialise channel for dma command submission */
+-      nvkm_wr32(device, 0x611494 + (chid * 0x0010), chan->push);
+-      nvkm_wr32(device, 0x611498 + (chid * 0x0010), 0x00010000);
+-      nvkm_wr32(device, 0x61149c + (chid * 0x0010), 0x00000001);
+-      nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
+-      nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000);
+-      nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013);
++      nvkm_wr32(device, 0x611494 + (ctrl * 0x0010), chan->push);
++      nvkm_wr32(device, 0x611498 + (ctrl * 0x0010), 0x00010000);
++      nvkm_wr32(device, 0x61149c + (ctrl * 0x0010), 0x00000001);
++      nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010);
++      nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000);
++      nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013);
+       /* wait for it to go inactive */
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000))
++              if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d init: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610490 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d init: %08x\n", user,
++                         nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c
+@@ -179,9 +179,9 @@ nv50_disp_dmac_bind(struct nv50_disp_dma
+                   struct nvkm_object *object, u32 handle)
+ {
+       return nvkm_ramht_insert(chan->base.root->ramht, object,
+-                               chan->base.chid, -10, handle,
+-                               chan->base.chid << 28 |
+-                               chan->base.chid);
++                               chan->base.chid.user, -10, handle,
++                               chan->base.chid.user << 28 |
++                               chan->base.chid.user);
+ }
+ static void
+@@ -190,21 +190,22 @@ nv50_disp_dmac_fini(struct nv50_disp_dma
+       struct nv50_disp *disp = chan->base.root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->base.chid;
++      int ctrl = chan->base.chid.ctrl;
++      int user = chan->base.chid.user;
+       /* deactivate channel */
+-      nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
+-      nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
++      nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00001010, 0x00001000);
++      nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000003, 0x00000000);
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000))
++              if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x001e0000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid,
+-                         nvkm_rd32(device, 0x610200 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d fini timeout, %08x\n", user,
++                         nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
+       }
+       /* disable error reporting and completion notifications */
+-      nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
++      nvkm_mask(device, 0x610028, 0x00010001 << user, 0x00000000 << user);
+ }
+ static int
+@@ -213,26 +214,27 @@ nv50_disp_dmac_init(struct nv50_disp_dma
+       struct nv50_disp *disp = chan->base.root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->base.chid;
++      int ctrl = chan->base.chid.ctrl;
++      int user = chan->base.chid.user;
+       /* enable error reporting */
+-      nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
++      nvkm_mask(device, 0x610028, 0x00010000 << user, 0x00010000 << user);
+       /* initialise channel for dma command submission */
+-      nvkm_wr32(device, 0x610204 + (chid * 0x0010), chan->push);
+-      nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000);
+-      nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid);
+-      nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
+-      nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000);
+-      nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013);
++      nvkm_wr32(device, 0x610204 + (ctrl * 0x0010), chan->push);
++      nvkm_wr32(device, 0x610208 + (ctrl * 0x0010), 0x00010000);
++      nvkm_wr32(device, 0x61020c + (ctrl * 0x0010), ctrl);
++      nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000010, 0x00000010);
++      nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000);
++      nvkm_wr32(device, 0x610200 + (ctrl * 0x0010), 0x00000013);
+       /* wait for it to go inactive */
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000))
++              if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x80000000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d init timeout, %08x\n", chid,
+-                         nvkm_rd32(device, 0x610200 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d init timeout, %08x\n", user,
++                         nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c
+@@ -32,20 +32,21 @@ gf119_disp_pioc_fini(struct nv50_disp_ch
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->chid;
++      int ctrl = chan->chid.ctrl;
++      int user = chan->chid.user;
+-      nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
++      nvkm_mask(device, 0x610490 + (ctrl * 0x10), 0x00000001, 0x00000000);
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000))
++              if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x00030000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d fini: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610490 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d fini: %08x\n", user,
++                         nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
+       }
+       /* disable error reporting and completion notification */
+-      nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000);
+-      nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000);
++      nvkm_mask(device, 0x610090, 0x00000001 << user, 0x00000000);
++      nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000000);
+ }
+ static int
+@@ -54,20 +55,21 @@ gf119_disp_pioc_init(struct nv50_disp_ch
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->chid;
++      int ctrl = chan->chid.ctrl;
++      int user = chan->chid.user;
+       /* enable error reporting */
+-      nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
++      nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user);
+       /* activate channel */
+-      nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001);
++      nvkm_wr32(device, 0x610490 + (ctrl * 0x10), 0x00000001);
+       if (nvkm_msec(device, 2000,
+-              u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10));
++              u32 tmp = nvkm_rd32(device, 0x610490 + (ctrl * 0x10));
+               if ((tmp & 0x00030000) == 0x00010000)
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d init: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610490 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d init: %08x\n", user,
++                         nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
+--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c
++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c
+@@ -32,15 +32,16 @@ nv50_disp_pioc_fini(struct nv50_disp_cha
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->chid;
++      int ctrl = chan->chid.ctrl;
++      int user = chan->chid.user;
+-      nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
++      nvkm_mask(device, 0x610200 + (ctrl * 0x10), 0x00000001, 0x00000000);
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000))
++              if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x00030000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d timeout: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610200 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d timeout: %08x\n", user,
++                         nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
+       }
+ }
+@@ -50,26 +51,27 @@ nv50_disp_pioc_init(struct nv50_disp_cha
+       struct nv50_disp *disp = chan->root->disp;
+       struct nvkm_subdev *subdev = &disp->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
+-      int chid = chan->chid;
++      int ctrl = chan->chid.ctrl;
++      int user = chan->chid.user;
+-      nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000);
++      nvkm_wr32(device, 0x610200 + (ctrl * 0x10), 0x00002000);
+       if (nvkm_msec(device, 2000,
+-              if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000))
++              if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x00030000))
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d timeout0: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610200 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d timeout0: %08x\n", user,
++                         nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
+-      nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001);
++      nvkm_wr32(device, 0x610200 + (ctrl * 0x10), 0x00000001);
+       if (nvkm_msec(device, 2000,
+-              u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10));
++              u32 tmp = nvkm_rd32(device, 0x610200 + (ctrl * 0x10));
+               if ((tmp & 0x00030000) == 0x00010000)
+                       break;
+       ) < 0) {
+-              nvkm_error(subdev, "ch %d timeout1: %08x\n", chid,
+-                         nvkm_rd32(device, 0x610200 + (chid * 0x10)));
++              nvkm_error(subdev, "ch %d timeout1: %08x\n", user,
++                         nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
+               return -EBUSY;
+       }
diff --git a/queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch b/queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch
new file mode 100644 (file)
index 0000000..5d90801
--- /dev/null
@@ -0,0 +1,60 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:25 +0000
+Subject: [PATCH v2 for-4.9 19/40] ibmveth: calculate gso_segs for large packets
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-19-alexander.levin@verizon.com>
+
+From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
+
+[ Upstream commit 94acf164dc8f1184e8d0737be7125134c2701dbe ]
+
+Include calculations to compute the number of segments
+that comprise an aggregated large packet.
+
+Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
+Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Reviewed-by: Jonathan Maxwell <jmaxwell37@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/ibm/ibmveth.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/ibm/ibmveth.c
++++ b/drivers/net/ethernet/ibm/ibmveth.c
+@@ -1181,7 +1181,9 @@ map_failed:
+ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
+ {
++      struct tcphdr *tcph;
+       int offset = 0;
++      int hdr_len;
+       /* only TCP packets will be aggregated */
+       if (skb->protocol == htons(ETH_P_IP)) {
+@@ -1208,14 +1210,20 @@ static void ibmveth_rx_mss_helper(struct
+       /* if mss is not set through Large Packet bit/mss in rx buffer,
+        * expect that the mss will be written to the tcp header checksum.
+        */
++      tcph = (struct tcphdr *)(skb->data + offset);
+       if (lrg_pkt) {
+               skb_shinfo(skb)->gso_size = mss;
+       } else if (offset) {
+-              struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset);
+-
+               skb_shinfo(skb)->gso_size = ntohs(tcph->check);
+               tcph->check = 0;
+       }
++
++      if (skb_shinfo(skb)->gso_size) {
++              hdr_len = offset + tcph->doff * 4;
++              skb_shinfo(skb)->gso_segs =
++                              DIV_ROUND_UP(skb->len - hdr_len,
++                                           skb_shinfo(skb)->gso_size);
++      }
+ }
+ static int ibmveth_poll(struct napi_struct *napi, int budget)
diff --git a/queue-4.9/igb-add-i211-to-i210-phy-workaround.patch b/queue-4.9/igb-add-i211-to-i210-phy-workaround.patch
new file mode 100644 (file)
index 0000000..c0c5676
--- /dev/null
@@ -0,0 +1,35 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:19 +0000
+Subject: [PATCH v2 for-4.9 03/40] igb: add i211 to i210 PHY workaround
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-3-alexander.levin@verizon.com>
+
+From: Todd Fujinaka <todd.fujinaka@intel.com>
+
+[ Upstream commit 5bc8c230e2a993b49244f9457499f17283da9ec7 ]
+
+i210 and i211 share the same PHY but have different PCI IDs. Don't
+forget i211 for any i210 workarounds.
+
+Signed-off-by: Todd Fujinaka <todd.fujinaka@intel.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/intel/igb/e1000_phy.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
++++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
+@@ -78,7 +78,7 @@ s32 igb_get_phy_id(struct e1000_hw *hw)
+       u16 phy_id;
+       /* ensure PHY page selection to fix misconfigured i210 */
+-      if (hw->mac.type == e1000_i210)
++      if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
+               phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0);
+       ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
diff --git a/queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch b/queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch
new file mode 100644 (file)
index 0000000..0ff3142
--- /dev/null
@@ -0,0 +1,40 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:19 +0000
+Subject: [PATCH v2 for-4.9 02/40] igb: Workaround for igb i210 firmware issue
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-2-alexander.levin@verizon.com>
+
+From: Chris J Arges <christopherarges@gmail.com>
+
+[ Upstream commit 4e684f59d760a2c7c716bb60190783546e2d08a1 ]
+
+Sometimes firmware may not properly initialize I347AT4_PAGE_SELECT causing
+the probe of an igb i210 NIC to fail. This patch adds an addition zeroing
+of this register during igb_get_phy_id to workaround this issue.
+
+Thanks for Jochen Henneberg for the idea and original patch.
+
+Signed-off-by: Chris J Arges <christopherarges@gmail.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/intel/igb/e1000_phy.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
++++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
+@@ -77,6 +77,10 @@ s32 igb_get_phy_id(struct e1000_hw *hw)
+       s32 ret_val = 0;
+       u16 phy_id;
++      /* ensure PHY page selection to fix misconfigured i210 */
++      if (hw->mac.type == e1000_i210)
++              phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0);
++
+       ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+       if (ret_val)
+               goto out;
diff --git a/queue-4.9/pci-add-comments-about-rom-bar-updating.patch b/queue-4.9/pci-add-comments-about-rom-bar-updating.patch
new file mode 100644 (file)
index 0000000..db04916
--- /dev/null
@@ -0,0 +1,67 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:23 +0000
+Subject: [PATCH v2 for-4.9 13/40] PCI: Add comments about ROM BAR updating
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-13-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 0b457dde3cf8b7c76a60f8e960f21bbd4abdc416 ]
+
+pci_update_resource() updates a hardware BAR so its address matches the
+kernel's struct resource UNLESS it's a disabled ROM BAR.  We only update
+those when we enable the ROM.
+
+It's not obvious from the code why ROM BARs should be handled specially.
+Apparently there are Matrox devices with defective ROM BARs that read as
+zero when disabled.  That means that if pci_enable_rom() reads the disabled
+BAR, sets PCI_ROM_ADDRESS_ENABLE (without re-inserting the address), and
+writes it back, it would enable the ROM at address zero.
+
+Add comments and references to explain why we can't make the code look more
+rational.
+
+The code changes are from 755528c860b0 ("Ignore disabled ROM resources at
+setup") and 8085ce084c0f ("[PATCH] Fix PCI ROM mapping").
+
+Link: https://lkml.org/lkml/2005/8/30/138
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/rom.c       |    5 +++++
+ drivers/pci/setup-res.c |    6 ++++++
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/pci/rom.c
++++ b/drivers/pci/rom.c
+@@ -35,6 +35,11 @@ int pci_enable_rom(struct pci_dev *pdev)
+       if (res->flags & IORESOURCE_ROM_SHADOW)
+               return 0;
++      /*
++       * Ideally pci_update_resource() would update the ROM BAR address,
++       * and we would only set the enable bit here.  But apparently some
++       * devices have buggy ROM BARs that read as zero when disabled.
++       */
+       pcibios_resource_to_bus(pdev->bus, &region, res);
+       pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
+       rom_addr &= ~PCI_ROM_ADDRESS_MASK;
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -68,6 +68,12 @@ static void pci_std_update_resource(stru
+       if (resno < PCI_ROM_RESOURCE) {
+               reg = PCI_BASE_ADDRESS_0 + 4 * resno;
+       } else if (resno == PCI_ROM_RESOURCE) {
++
++              /*
++               * Apparently some Matrox devices have ROM BARs that read
++               * as zero when disabled, so don't update ROM BARs unless
++               * they're enabled.  See https://lkml.org/lkml/2005/8/30/138.
++               */
+               if (!(res->flags & IORESOURCE_ROM_ENABLE))
+                       return;
diff --git a/queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch b/queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch
new file mode 100644 (file)
index 0000000..2daa5b5
--- /dev/null
@@ -0,0 +1,37 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:23 +0000
+Subject: [PATCH v2 for-4.9 14/40] PCI: Decouple IORESOURCE_ROM_ENABLE and PCI_ROM_ADDRESS_ENABLE
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-14-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 7a6d312b50e63f598f5b5914c4fd21878ac2b595 ]
+
+Remove the assumption that IORESOURCE_ROM_ENABLE == PCI_ROM_ADDRESS_ENABLE.
+PCI_ROM_ADDRESS_ENABLE is the ROM enable bit defined by the PCI spec, so if
+we're reading or writing a BAR register value, that's what we should use.
+IORESOURCE_ROM_ENABLE is a corresponding bit in struct resource flags.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/probe.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -227,7 +227,8 @@ int __pci_read_base(struct pci_dev *dev,
+                       mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+               }
+       } else {
+-              res->flags |= (l & IORESOURCE_ROM_ENABLE);
++              if (l & PCI_ROM_ADDRESS_ENABLE)
++                      res->flags |= IORESOURCE_ROM_ENABLE;
+               l64 = l & PCI_ROM_ADDRESS_MASK;
+               sz64 = sz & PCI_ROM_ADDRESS_MASK;
+               mask64 = (u32)PCI_ROM_ADDRESS_MASK;
diff --git a/queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch b/queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch
new file mode 100644 (file)
index 0000000..55f23da
--- /dev/null
@@ -0,0 +1,65 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:25 +0000
+Subject: [PATCH v2 for-4.9 18/40] PCI: Do any VF BAR updates before enabling the BARs
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-18-alexander.levin@verizon.com>
+
+From: Gavin Shan <gwshan@linux.vnet.ibm.com>
+
+[ Upstream commit f40ec3c748c6912f6266c56a7f7992de61b255ed ]
+
+Previously we enabled VFs and enable their memory space before calling
+pcibios_sriov_enable().  But pcibios_sriov_enable() may update the VF BARs:
+for example, on PPC PowerNV we may change them to manage the association of
+VFs to PEs.
+
+Because 64-bit BARs cannot be updated atomically, it's unsafe to update
+them while they're enabled.  The half-updated state may conflict with other
+devices in the system.
+
+Call pcibios_sriov_enable() before enabling the VFs so any BAR updates
+happen while the VF BARs are disabled.
+
+[bhelgaas: changelog]
+Tested-by: Carol Soto <clsoto@us.ibm.com>
+Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/iov.c |   14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/pci/iov.c
++++ b/drivers/pci/iov.c
+@@ -306,13 +306,6 @@ static int sriov_enable(struct pci_dev *
+                       return rc;
+       }
+-      pci_iov_set_numvfs(dev, nr_virtfn);
+-      iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+-      pci_cfg_access_lock(dev);
+-      pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+-      msleep(100);
+-      pci_cfg_access_unlock(dev);
+-
+       iov->initial_VFs = initial;
+       if (nr_virtfn < initial)
+               initial = nr_virtfn;
+@@ -323,6 +316,13 @@ static int sriov_enable(struct pci_dev *
+               goto err_pcibios;
+       }
++      pci_iov_set_numvfs(dev, nr_virtfn);
++      iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
++      pci_cfg_access_lock(dev);
++      pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
++      msleep(100);
++      pci_cfg_access_unlock(dev);
++
+       for (i = 0; i < initial; i++) {
+               rc = pci_iov_add_virtfn(dev, i, 0);
+               if (rc)
diff --git a/queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch b/queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch
new file mode 100644 (file)
index 0000000..5a1be4f
--- /dev/null
@@ -0,0 +1,57 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:24 +0000
+Subject: [PATCH v2 for-4.9 15/40] PCI: Don't update VF BARs while VF memory space is enabled
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-15-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 546ba9f8f22f71b0202b6ba8967be5cc6dae4e21 ]
+
+If we update a VF BAR while it's enabled, there are two potential problems:
+
+  1) Any driver that's using the VF has a cached BAR value that is stale
+     after the update, and
+
+  2) We can't update 64-bit BARs atomically, so the intermediate state
+     (new lower dword with old upper dword) may conflict with another
+     device, and an access by a driver unrelated to the VF may cause a bus
+     error.
+
+Warn about attempts to update VF BARs while they are enabled.  This is a
+programming error, so use dev_WARN() to get a backtrace.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/iov.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/pci/iov.c
++++ b/drivers/pci/iov.c
+@@ -566,6 +566,7 @@ void pci_iov_update_resource(struct pci_
+       struct resource *res = dev->resource + resno;
+       int vf_bar = resno - PCI_IOV_RESOURCES;
+       struct pci_bus_region region;
++      u16 cmd;
+       u32 new;
+       int reg;
+@@ -577,6 +578,13 @@ void pci_iov_update_resource(struct pci_
+       if (!iov)
+               return;
++      pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd);
++      if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) {
++              dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n",
++                       vf_bar, res);
++              return;
++      }
++
+       /*
+        * Ignore unimplemented BARs, unused resource slots for 64-bit
+        * BARs, and non-movable resources, e.g., those described via
diff --git a/queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch b/queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch
new file mode 100644 (file)
index 0000000..f9bcb5b
--- /dev/null
@@ -0,0 +1,56 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:24 +0000
+Subject: [PATCH v2 for-4.9 17/40] PCI: Ignore BAR updates on virtual functions
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-17-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 63880b230a4af502c56dde3d4588634c70c66006 ]
+
+VF BARs are read-only zero, so updating VF BARs will not have any effect.
+See the SR-IOV spec r1.1, sec 3.4.1.11.
+
+We already ignore these updates because of 70675e0b6a1a ("PCI: Don't try to
+restore VF BARs"); this merely restructures it slightly to make it easier
+to split updates for standard and SR-IOV BARs.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/pci.c       |    4 ----
+ drivers/pci/setup-res.c |    5 ++---
+ 2 files changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -564,10 +564,6 @@ static void pci_restore_bars(struct pci_
+ {
+       int i;
+-      /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
+-      if (dev->is_virtfn)
+-              return;
+-
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
+               pci_update_resource(dev, i);
+ }
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -34,10 +34,9 @@ static void pci_std_update_resource(stru
+       int reg;
+       struct resource *res = dev->resource + resno;
+-      if (dev->is_virtfn) {
+-              dev_warn(&dev->dev, "can't update VF BAR%d\n", resno);
++      /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
++      if (dev->is_virtfn)
+               return;
+-      }
+       /*
+        * Ignore resources for unimplemented BARs and unused resource slots
diff --git a/queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch b/queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch
new file mode 100644 (file)
index 0000000..e53ec67
--- /dev/null
@@ -0,0 +1,156 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:23 +0000
+Subject: [PATCH v2 for-4.9 12/40] PCI: Remove pci_resource_bar() and pci_iov_resource_bar()
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-12-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 286c2378aaccc7343ebf17ec6cd86567659caf70 ]
+
+pci_std_update_resource() only deals with standard BARs, so we don't have
+to worry about the complications of VF BARs in an SR-IOV capability.
+
+Compute the BAR address inline and remove pci_resource_bar().  That makes
+pci_iov_resource_bar() unused, so remove that as well.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/iov.c       |   18 ------------------
+ drivers/pci/pci.c       |   30 ------------------------------
+ drivers/pci/pci.h       |    6 ------
+ drivers/pci/setup-res.c |   13 +++++++------
+ 4 files changed, 7 insertions(+), 60 deletions(-)
+
+--- a/drivers/pci/iov.c
++++ b/drivers/pci/iov.c
+@@ -554,24 +554,6 @@ void pci_iov_release(struct pci_dev *dev
+ }
+ /**
+- * pci_iov_resource_bar - get position of the SR-IOV BAR
+- * @dev: the PCI device
+- * @resno: the resource number
+- *
+- * Returns position of the BAR encapsulated in the SR-IOV capability.
+- */
+-int pci_iov_resource_bar(struct pci_dev *dev, int resno)
+-{
+-      if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
+-              return 0;
+-
+-      BUG_ON(!dev->is_physfn);
+-
+-      return dev->sriov->pos + PCI_SRIOV_BAR +
+-              4 * (resno - PCI_IOV_RESOURCES);
+-}
+-
+-/**
+  * pci_iov_update_resource - update a VF BAR
+  * @dev: the PCI device
+  * @resno: the resource number
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -4835,36 +4835,6 @@ int pci_select_bars(struct pci_dev *dev,
+ }
+ EXPORT_SYMBOL(pci_select_bars);
+-/**
+- * pci_resource_bar - get position of the BAR associated with a resource
+- * @dev: the PCI device
+- * @resno: the resource number
+- * @type: the BAR type to be filled in
+- *
+- * Returns BAR position in config space, or 0 if the BAR is invalid.
+- */
+-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
+-{
+-      int reg;
+-
+-      if (resno < PCI_ROM_RESOURCE) {
+-              *type = pci_bar_unknown;
+-              return PCI_BASE_ADDRESS_0 + 4 * resno;
+-      } else if (resno == PCI_ROM_RESOURCE) {
+-              *type = pci_bar_mem32;
+-              return dev->rom_base_reg;
+-      } else if (resno < PCI_BRIDGE_RESOURCES) {
+-              /* device specific resource */
+-              *type = pci_bar_unknown;
+-              reg = pci_iov_resource_bar(dev, resno);
+-              if (reg)
+-                      return reg;
+-      }
+-
+-      dev_err(&dev->dev, "BAR %d: invalid resource\n", resno);
+-      return 0;
+-}
+-
+ /* Some architectures require additional programming to enable VGA */
+ static arch_set_vga_state_t arch_set_vga_state;
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -245,7 +245,6 @@ bool pci_bus_read_dev_vendor_id(struct p
+ int pci_setup_device(struct pci_dev *dev);
+ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+                   struct resource *res, unsigned int reg);
+-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
+ void pci_configure_ari(struct pci_dev *dev);
+ void __pci_bus_size_bridges(struct pci_bus *bus,
+                       struct list_head *realloc_head);
+@@ -289,7 +288,6 @@ static inline void pci_restore_ats_state
+ #ifdef CONFIG_PCI_IOV
+ int pci_iov_init(struct pci_dev *dev);
+ void pci_iov_release(struct pci_dev *dev);
+-int pci_iov_resource_bar(struct pci_dev *dev, int resno);
+ void pci_iov_update_resource(struct pci_dev *dev, int resno);
+ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
+ void pci_restore_iov_state(struct pci_dev *dev);
+@@ -304,10 +302,6 @@ static inline void pci_iov_release(struc
+ {
+ }
+-static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno)
+-{
+-      return 0;
+-}
+ static inline void pci_restore_iov_state(struct pci_dev *dev)
+ {
+ }
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -32,7 +32,6 @@ static void pci_std_update_resource(stru
+       u16 cmd;
+       u32 new, check, mask;
+       int reg;
+-      enum pci_bar_type type;
+       struct resource *res = dev->resource + resno;
+       if (dev->is_virtfn) {
+@@ -66,14 +65,16 @@ static void pci_std_update_resource(stru
+       else
+               mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+-      reg = pci_resource_bar(dev, resno, &type);
+-      if (!reg)
+-              return;
+-      if (type != pci_bar_unknown) {
++      if (resno < PCI_ROM_RESOURCE) {
++              reg = PCI_BASE_ADDRESS_0 + 4 * resno;
++      } else if (resno == PCI_ROM_RESOURCE) {
+               if (!(res->flags & IORESOURCE_ROM_ENABLE))
+                       return;
++
++              reg = dev->rom_base_reg;
+               new |= PCI_ROM_ADDRESS_ENABLE;
+-      }
++      } else
++              return;
+       /*
+        * We can't update a 64-bit BAR atomically, so when possible,
diff --git a/queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch b/queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch
new file mode 100644 (file)
index 0000000..8762d00
--- /dev/null
@@ -0,0 +1,135 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:22 +0000
+Subject: [PATCH v2 for-4.9 11/40] PCI: Separate VF BAR updates from standard BAR updates
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-11-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 6ffa2489c51da77564a0881a73765ea2169f955d ]
+
+Previously pci_update_resource() used the same code path for updating
+standard BARs and VF BARs in SR-IOV capabilities.
+
+Split the VF BAR update into a new pci_iov_update_resource() internal
+interface, which makes it simpler to compute the BAR address (we can get
+rid of pci_resource_bar() and pci_iov_resource_bar()).
+
+This patch:
+
+  - Renames pci_update_resource() to pci_std_update_resource(),
+  - Adds pci_iov_update_resource(),
+  - Makes pci_update_resource() a wrapper that calls the appropriate one,
+
+No functional change intended.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/iov.c       |   50 ++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/pci/pci.h       |    1 
+ drivers/pci/setup-res.c |   13 ++++++++++--
+ 3 files changed, 62 insertions(+), 2 deletions(-)
+
+--- a/drivers/pci/iov.c
++++ b/drivers/pci/iov.c
+@@ -571,6 +571,56 @@ int pci_iov_resource_bar(struct pci_dev
+               4 * (resno - PCI_IOV_RESOURCES);
+ }
++/**
++ * pci_iov_update_resource - update a VF BAR
++ * @dev: the PCI device
++ * @resno: the resource number
++ *
++ * Update a VF BAR in the SR-IOV capability of a PF.
++ */
++void pci_iov_update_resource(struct pci_dev *dev, int resno)
++{
++      struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
++      struct resource *res = dev->resource + resno;
++      int vf_bar = resno - PCI_IOV_RESOURCES;
++      struct pci_bus_region region;
++      u32 new;
++      int reg;
++
++      /*
++       * The generic pci_restore_bars() path calls this for all devices,
++       * including VFs and non-SR-IOV devices.  If this is not a PF, we
++       * have nothing to do.
++       */
++      if (!iov)
++              return;
++
++      /*
++       * Ignore unimplemented BARs, unused resource slots for 64-bit
++       * BARs, and non-movable resources, e.g., those described via
++       * Enhanced Allocation.
++       */
++      if (!res->flags)
++              return;
++
++      if (res->flags & IORESOURCE_UNSET)
++              return;
++
++      if (res->flags & IORESOURCE_PCI_FIXED)
++              return;
++
++      pcibios_resource_to_bus(dev->bus, &region, res);
++      new = region.start;
++      new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
++
++      reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar;
++      pci_write_config_dword(dev, reg, new);
++      if (res->flags & IORESOURCE_MEM_64) {
++              new = region.start >> 16 >> 16;
++              pci_write_config_dword(dev, reg + 4, new);
++      }
++}
++
+ resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev,
+                                                     int resno)
+ {
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -290,6 +290,7 @@ static inline void pci_restore_ats_state
+ int pci_iov_init(struct pci_dev *dev);
+ void pci_iov_release(struct pci_dev *dev);
+ int pci_iov_resource_bar(struct pci_dev *dev, int resno);
++void pci_iov_update_resource(struct pci_dev *dev, int resno);
+ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
+ void pci_restore_iov_state(struct pci_dev *dev);
+ int pci_iov_bus_range(struct pci_bus *bus);
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -25,8 +25,7 @@
+ #include <linux/slab.h>
+ #include "pci.h"
+-
+-void pci_update_resource(struct pci_dev *dev, int resno)
++static void pci_std_update_resource(struct pci_dev *dev, int resno)
+ {
+       struct pci_bus_region region;
+       bool disable;
+@@ -110,6 +109,16 @@ void pci_update_resource(struct pci_dev
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
++void pci_update_resource(struct pci_dev *dev, int resno)
++{
++      if (resno <= PCI_ROM_RESOURCE)
++              pci_std_update_resource(dev, resno);
++#ifdef CONFIG_PCI_IOV
++      else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
++              pci_iov_update_resource(dev, resno);
++#endif
++}
++
+ int pci_claim_resource(struct pci_dev *dev, int resource)
+ {
+       struct resource *res = &dev->resource[resource];
diff --git a/queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch b/queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch
new file mode 100644 (file)
index 0000000..c05e78f
--- /dev/null
@@ -0,0 +1,54 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:24 +0000
+Subject: [PATCH v2 for-4.9 16/40] PCI: Update BARs using property bits appropriate for type
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-16-alexander.levin@verizon.com>
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit 45d004f4afefdd8d79916ee6d97a9ecd94bb1ffe ]
+
+The BAR property bits (0-3 for memory BARs, 0-1 for I/O BARs) are supposed
+to be read-only, but we do save them in res->flags and include them when
+updating the BAR.
+
+Mask the I/O property bits with ~PCI_BASE_ADDRESS_IO_MASK (0x3) instead of
+PCI_REGION_FLAG_MASK (0xf) to make it obvious that we can't corrupt bits
+2-3 of I/O addresses.
+
+Use PCI_ROM_ADDRESS_MASK for ROM BARs.  This means we'll only check the top
+21 bits (instead of the 28 bits we used to check) of a ROM BAR to see if
+the update was successful.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/setup-res.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -58,12 +58,17 @@ static void pci_std_update_resource(stru
+               return;
+       pcibios_resource_to_bus(dev->bus, &region, res);
++      new = region.start;
+-      new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
+-      if (res->flags & IORESOURCE_IO)
++      if (res->flags & IORESOURCE_IO) {
+               mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
+-      else
++              new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK;
++      } else if (resno == PCI_ROM_RESOURCE) {
++              mask = (u32)PCI_ROM_ADDRESS_MASK;
++      } else {
+               mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
++              new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
++      }
+       if (resno < PCI_ROM_RESOURCE) {
+               reg = PCI_BASE_ADDRESS_0 + 4 * resno;
diff --git a/queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch b/queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch
new file mode 100644 (file)
index 0000000..6d7cb8c
--- /dev/null
@@ -0,0 +1,102 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:26 +0000
+Subject: [PATCH v2 for-4.9 22/40] powerpc/iommu: Pass mm_struct to init/cleanup helpers
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-22-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit 88f54a3581eb9deaa3bd1aade40aef266d782385 ]
+
+We are going to get rid of @current references in mmu_context_boos3s64.c
+and cache mm_struct in the VFIO container. Since mm_context_t does not
+have reference counting, we will be using mm_struct which does have
+the reference counter.
+
+This changes mm_iommu_init/mm_iommu_cleanup to receive mm_struct rather
+than mm_context_t (which is embedded into mm).
+
+This should not cause any behavioral change.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/include/asm/mmu_context.h |    4 ++--
+ arch/powerpc/kernel/setup-common.c     |    2 +-
+ arch/powerpc/mm/mmu_context_book3s64.c |    4 ++--
+ arch/powerpc/mm/mmu_context_iommu.c    |    9 +++++----
+ 4 files changed, 10 insertions(+), 9 deletions(-)
+
+--- a/arch/powerpc/include/asm/mmu_context.h
++++ b/arch/powerpc/include/asm/mmu_context.h
+@@ -23,8 +23,8 @@ extern bool mm_iommu_preregistered(void)
+ extern long mm_iommu_get(unsigned long ua, unsigned long entries,
+               struct mm_iommu_table_group_mem_t **pmem);
+ extern long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem);
+-extern void mm_iommu_init(mm_context_t *ctx);
+-extern void mm_iommu_cleanup(mm_context_t *ctx);
++extern void mm_iommu_init(struct mm_struct *mm);
++extern void mm_iommu_cleanup(struct mm_struct *mm);
+ extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua,
+               unsigned long size);
+ extern struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua,
+--- a/arch/powerpc/kernel/setup-common.c
++++ b/arch/powerpc/kernel/setup-common.c
+@@ -915,7 +915,7 @@ void __init setup_arch(char **cmdline_p)
+       init_mm.context.pte_frag = NULL;
+ #endif
+ #ifdef CONFIG_SPAPR_TCE_IOMMU
+-      mm_iommu_init(&init_mm.context);
++      mm_iommu_init(&init_mm);
+ #endif
+       irqstack_early_init();
+       exc_lvl_early_init();
+--- a/arch/powerpc/mm/mmu_context_book3s64.c
++++ b/arch/powerpc/mm/mmu_context_book3s64.c
+@@ -115,7 +115,7 @@ int init_new_context(struct task_struct
+       mm->context.pte_frag = NULL;
+ #endif
+ #ifdef CONFIG_SPAPR_TCE_IOMMU
+-      mm_iommu_init(&mm->context);
++      mm_iommu_init(mm);
+ #endif
+       return 0;
+ }
+@@ -160,7 +160,7 @@ static inline void destroy_pagetable_pag
+ void destroy_context(struct mm_struct *mm)
+ {
+ #ifdef CONFIG_SPAPR_TCE_IOMMU
+-      mm_iommu_cleanup(&mm->context);
++      mm_iommu_cleanup(mm);
+ #endif
+ #ifdef CONFIG_PPC_ICSWX
+--- a/arch/powerpc/mm/mmu_context_iommu.c
++++ b/arch/powerpc/mm/mmu_context_iommu.c
+@@ -373,16 +373,17 @@ void mm_iommu_mapped_dec(struct mm_iommu
+ }
+ EXPORT_SYMBOL_GPL(mm_iommu_mapped_dec);
+-void mm_iommu_init(mm_context_t *ctx)
++void mm_iommu_init(struct mm_struct *mm)
+ {
+-      INIT_LIST_HEAD_RCU(&ctx->iommu_group_mem_list);
++      INIT_LIST_HEAD_RCU(&mm->context.iommu_group_mem_list);
+ }
+-void mm_iommu_cleanup(mm_context_t *ctx)
++void mm_iommu_cleanup(struct mm_struct *mm)
+ {
+       struct mm_iommu_table_group_mem_t *mem, *tmp;
+-      list_for_each_entry_safe(mem, tmp, &ctx->iommu_group_mem_list, next) {
++      list_for_each_entry_safe(mem, tmp, &mm->context.iommu_group_mem_list,
++                      next) {
+               list_del_rcu(&mem->next);
+               mm_iommu_do_free(mem);
+       }
diff --git a/queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch b/queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch
new file mode 100644 (file)
index 0000000..a50434a
--- /dev/null
@@ -0,0 +1,248 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:27 +0000
+Subject: [PATCH v2 for-4.9 23/40] powerpc/iommu: Stop using @current in mm_iommu_xxx
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-23-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit d7baee6901b34c4895eb78efdbf13a49079d7404 ]
+
+This changes mm_iommu_xxx helpers to take mm_struct as a parameter
+instead of getting it from @current which in some situations may
+not have a valid reference to mm.
+
+This changes helpers to receive @mm and moves all references to @current
+to the caller, including checks for !current and !current->mm;
+checks in mm_iommu_preregistered() are removed as there is no caller
+yet.
+
+This moves the mm_iommu_adjust_locked_vm() call to the caller as
+it receives mm_iommu_table_group_mem_t but it needs mm.
+
+This should cause no behavioral change.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/include/asm/mmu_context.h |   16 ++++++-----
+ arch/powerpc/mm/mmu_context_iommu.c    |   46 ++++++++++++---------------------
+ drivers/vfio/vfio_iommu_spapr_tce.c    |   14 +++++++---
+ 3 files changed, 36 insertions(+), 40 deletions(-)
+
+--- a/arch/powerpc/include/asm/mmu_context.h
++++ b/arch/powerpc/include/asm/mmu_context.h
+@@ -19,16 +19,18 @@ extern void destroy_context(struct mm_st
+ struct mm_iommu_table_group_mem_t;
+ extern int isolate_lru_page(struct page *page);       /* from internal.h */
+-extern bool mm_iommu_preregistered(void);
+-extern long mm_iommu_get(unsigned long ua, unsigned long entries,
++extern bool mm_iommu_preregistered(struct mm_struct *mm);
++extern long mm_iommu_get(struct mm_struct *mm,
++              unsigned long ua, unsigned long entries,
+               struct mm_iommu_table_group_mem_t **pmem);
+-extern long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem);
++extern long mm_iommu_put(struct mm_struct *mm,
++              struct mm_iommu_table_group_mem_t *mem);
+ extern void mm_iommu_init(struct mm_struct *mm);
+ extern void mm_iommu_cleanup(struct mm_struct *mm);
+-extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua,
+-              unsigned long size);
+-extern struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua,
+-              unsigned long entries);
++extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(struct mm_struct *mm,
++              unsigned long ua, unsigned long size);
++extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
++              unsigned long ua, unsigned long entries);
+ extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
+               unsigned long ua, unsigned long *hpa);
+ extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem);
+--- a/arch/powerpc/mm/mmu_context_iommu.c
++++ b/arch/powerpc/mm/mmu_context_iommu.c
+@@ -56,7 +56,7 @@ static long mm_iommu_adjust_locked_vm(st
+       }
+       pr_debug("[%d] RLIMIT_MEMLOCK HASH64 %c%ld %ld/%ld\n",
+-                      current->pid,
++                      current ? current->pid : 0,
+                       incr ? '+' : '-',
+                       npages << PAGE_SHIFT,
+                       mm->locked_vm << PAGE_SHIFT,
+@@ -66,12 +66,9 @@ static long mm_iommu_adjust_locked_vm(st
+       return ret;
+ }
+-bool mm_iommu_preregistered(void)
++bool mm_iommu_preregistered(struct mm_struct *mm)
+ {
+-      if (!current || !current->mm)
+-              return false;
+-
+-      return !list_empty(&current->mm->context.iommu_group_mem_list);
++      return !list_empty(&mm->context.iommu_group_mem_list);
+ }
+ EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
+@@ -124,19 +121,16 @@ static int mm_iommu_move_page_from_cma(s
+       return 0;
+ }
+-long mm_iommu_get(unsigned long ua, unsigned long entries,
++long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,
+               struct mm_iommu_table_group_mem_t **pmem)
+ {
+       struct mm_iommu_table_group_mem_t *mem;
+       long i, j, ret = 0, locked_entries = 0;
+       struct page *page = NULL;
+-      if (!current || !current->mm)
+-              return -ESRCH; /* process exited */
+-
+       mutex_lock(&mem_list_mutex);
+-      list_for_each_entry_rcu(mem, &current->mm->context.iommu_group_mem_list,
++      list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list,
+                       next) {
+               if ((mem->ua == ua) && (mem->entries == entries)) {
+                       ++mem->used;
+@@ -154,7 +148,7 @@ long mm_iommu_get(unsigned long ua, unsi
+       }
+-      ret = mm_iommu_adjust_locked_vm(current->mm, entries, true);
++      ret = mm_iommu_adjust_locked_vm(mm, entries, true);
+       if (ret)
+               goto unlock_exit;
+@@ -215,11 +209,11 @@ populate:
+       mem->entries = entries;
+       *pmem = mem;
+-      list_add_rcu(&mem->next, &current->mm->context.iommu_group_mem_list);
++      list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list);
+ unlock_exit:
+       if (locked_entries && ret)
+-              mm_iommu_adjust_locked_vm(current->mm, locked_entries, false);
++              mm_iommu_adjust_locked_vm(mm, locked_entries, false);
+       mutex_unlock(&mem_list_mutex);
+@@ -264,17 +258,13 @@ static void mm_iommu_free(struct rcu_hea
+ static void mm_iommu_release(struct mm_iommu_table_group_mem_t *mem)
+ {
+       list_del_rcu(&mem->next);
+-      mm_iommu_adjust_locked_vm(current->mm, mem->entries, false);
+       call_rcu(&mem->rcu, mm_iommu_free);
+ }
+-long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem)
++long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem)
+ {
+       long ret = 0;
+-      if (!current || !current->mm)
+-              return -ESRCH; /* process exited */
+-
+       mutex_lock(&mem_list_mutex);
+       if (mem->used == 0) {
+@@ -297,6 +287,8 @@ long mm_iommu_put(struct mm_iommu_table_
+       /* @mapped became 0 so now mappings are disabled, release the region */
+       mm_iommu_release(mem);
++      mm_iommu_adjust_locked_vm(mm, mem->entries, false);
++
+ unlock_exit:
+       mutex_unlock(&mem_list_mutex);
+@@ -304,14 +296,12 @@ unlock_exit:
+ }
+ EXPORT_SYMBOL_GPL(mm_iommu_put);
+-struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua,
+-              unsigned long size)
++struct mm_iommu_table_group_mem_t *mm_iommu_lookup(struct mm_struct *mm,
++              unsigned long ua, unsigned long size)
+ {
+       struct mm_iommu_table_group_mem_t *mem, *ret = NULL;
+-      list_for_each_entry_rcu(mem,
+-                      &current->mm->context.iommu_group_mem_list,
+-                      next) {
++      list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, next) {
+               if ((mem->ua <= ua) &&
+                               (ua + size <= mem->ua +
+                                (mem->entries << PAGE_SHIFT))) {
+@@ -324,14 +314,12 @@ struct mm_iommu_table_group_mem_t *mm_io
+ }
+ EXPORT_SYMBOL_GPL(mm_iommu_lookup);
+-struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua,
+-              unsigned long entries)
++struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm,
++              unsigned long ua, unsigned long entries)
+ {
+       struct mm_iommu_table_group_mem_t *mem, *ret = NULL;
+-      list_for_each_entry_rcu(mem,
+-                      &current->mm->context.iommu_group_mem_list,
+-                      next) {
++      list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, next) {
+               if ((mem->ua == ua) && (mem->entries == entries)) {
+                       ret = mem;
+                       break;
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -107,14 +107,17 @@ static long tce_iommu_unregister_pages(s
+ {
+       struct mm_iommu_table_group_mem_t *mem;
++      if (!current || !current->mm)
++              return -ESRCH; /* process exited */
++
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK))
+               return -EINVAL;
+-      mem = mm_iommu_find(vaddr, size >> PAGE_SHIFT);
++      mem = mm_iommu_find(current->mm, vaddr, size >> PAGE_SHIFT);
+       if (!mem)
+               return -ENOENT;
+-      return mm_iommu_put(mem);
++      return mm_iommu_put(current->mm, mem);
+ }
+ static long tce_iommu_register_pages(struct tce_container *container,
+@@ -124,11 +127,14 @@ static long tce_iommu_register_pages(str
+       struct mm_iommu_table_group_mem_t *mem = NULL;
+       unsigned long entries = size >> PAGE_SHIFT;
++      if (!current || !current->mm)
++              return -ESRCH; /* process exited */
++
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) ||
+                       ((vaddr + size) < vaddr))
+               return -EINVAL;
+-      ret = mm_iommu_get(vaddr, entries, &mem);
++      ret = mm_iommu_get(current->mm, vaddr, entries, &mem);
+       if (ret)
+               return ret;
+@@ -375,7 +381,7 @@ static int tce_iommu_prereg_ua_to_hpa(un
+       long ret = 0;
+       struct mm_iommu_table_group_mem_t *mem;
+-      mem = mm_iommu_lookup(tce, size);
++      mem = mm_iommu_lookup(current->mm, tce, size);
+       if (!mem)
+               return -EINVAL;
diff --git a/queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch b/queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch
new file mode 100644 (file)
index 0000000..88895c3
--- /dev/null
@@ -0,0 +1,41 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:33 +0000
+Subject: [PATCH v2 for-4.9 40/40] powerpc/mm: Fix build break when CMA=n && SPAPR_TCE_IOMMU=y
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-40-alexander.levin@verizon.com>
+
+From: Michael Ellerman <mpe@ellerman.id.au>
+
+[ Upstream commit a05ef161cdd22faccffe06f21fc8f1e249565385 ]
+
+Currently the build breaks if CMA=n and SPAPR_TCE_IOMMU=y:
+
+  arch/powerpc/mm/mmu_context_iommu.c: In function â€˜mm_iommu_get’:
+  arch/powerpc/mm/mmu_context_iommu.c:193:42: error: â€˜MIGRATE_CMA’ undeclared (first use in this function)
+  if (get_pageblock_migratetype(page) == MIGRATE_CMA) {
+  ^~~~~~~~~~~
+
+Fix it by using the existing is_migrate_cma_page(), which evaulates to
+false when CMA=n.
+
+Fixes: 2e5bbb5461f1 ("KVM: PPC: Book3S HV: Migrate pinned pages out of CMA")
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/mm/mmu_context_iommu.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/powerpc/mm/mmu_context_iommu.c
++++ b/arch/powerpc/mm/mmu_context_iommu.c
+@@ -184,7 +184,7 @@ long mm_iommu_get(struct mm_struct *mm,
+                * of the CMA zone if possible. NOTE: faulting in + migration
+                * can be expensive. Batching can be considered later
+                */
+-              if (get_pageblock_migratetype(page) == MIGRATE_CMA) {
++              if (is_migrate_cma_page(page)) {
+                       if (mm_iommu_move_page_from_cma(page))
+                               goto populate;
+                       if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
diff --git a/queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch b/queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch
new file mode 100644 (file)
index 0000000..e8b50b8
--- /dev/null
@@ -0,0 +1,211 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:27 +0000
+Subject: [PATCH v2 for-4.9 25/40] powerpc/mm/iommu, vfio/spapr: Put pages on VFIO container shutdown
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-25-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit 4b6fad7097f883335b6d9627c883cb7f276d94c9 ]
+
+At the moment the userspace tool is expected to request pinning of
+the entire guest RAM when VFIO IOMMU SPAPR v2 driver is present.
+When the userspace process finishes, all the pinned pages need to
+be put; this is done as a part of the userspace memory context (MM)
+destruction which happens on the very last mmdrop().
+
+This approach has a problem that a MM of the userspace process
+may live longer than the userspace process itself as kernel threads
+use userspace process MMs which was runnning on a CPU where
+the kernel thread was scheduled to. If this happened, the MM remains
+referenced until this exact kernel thread wakes up again
+and releases the very last reference to the MM, on an idle system this
+can take even hours.
+
+This moves preregistered regions tracking from MM to VFIO; insteads of
+using mm_iommu_table_group_mem_t::used, tce_container::prereg_list is
+added so each container releases regions which it has pre-registered.
+
+This changes the userspace interface to return EBUSY if a memory
+region is already registered in a container. However it should not
+have any practical effect as the only userspace tool available now
+does register memory region once per container anyway.
+
+As tce_iommu_register_pages/tce_iommu_unregister_pages are called
+under container->lock, this does not need additional locking.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/mm/mmu_context_book3s64.c |    4 --
+ arch/powerpc/mm/mmu_context_iommu.c    |   11 -----
+ drivers/vfio/vfio_iommu_spapr_tce.c    |   61 ++++++++++++++++++++++++++++++++-
+ 3 files changed, 61 insertions(+), 15 deletions(-)
+
+--- a/arch/powerpc/mm/mmu_context_book3s64.c
++++ b/arch/powerpc/mm/mmu_context_book3s64.c
+@@ -156,13 +156,11 @@ static inline void destroy_pagetable_pag
+ }
+ #endif
+-
+ void destroy_context(struct mm_struct *mm)
+ {
+ #ifdef CONFIG_SPAPR_TCE_IOMMU
+-      mm_iommu_cleanup(mm);
++      WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list));
+ #endif
+-
+ #ifdef CONFIG_PPC_ICSWX
+       drop_cop(mm->context.acop, mm);
+       kfree(mm->context.cop_lockp);
+--- a/arch/powerpc/mm/mmu_context_iommu.c
++++ b/arch/powerpc/mm/mmu_context_iommu.c
+@@ -365,14 +365,3 @@ void mm_iommu_init(struct mm_struct *mm)
+ {
+       INIT_LIST_HEAD_RCU(&mm->context.iommu_group_mem_list);
+ }
+-
+-void mm_iommu_cleanup(struct mm_struct *mm)
+-{
+-      struct mm_iommu_table_group_mem_t *mem, *tmp;
+-
+-      list_for_each_entry_safe(mem, tmp, &mm->context.iommu_group_mem_list,
+-                      next) {
+-              list_del_rcu(&mem->next);
+-              mm_iommu_do_free(mem);
+-      }
+-}
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -89,6 +89,15 @@ struct tce_iommu_group {
+ };
+ /*
++ * A container needs to remember which preregistered region  it has
++ * referenced to do proper cleanup at the userspace process exit.
++ */
++struct tce_iommu_prereg {
++      struct list_head next;
++      struct mm_iommu_table_group_mem_t *mem;
++};
++
++/*
+  * The container descriptor supports only a single group per container.
+  * Required by the API as the container is not supplied with the IOMMU group
+  * at the moment of initialization.
+@@ -101,6 +110,7 @@ struct tce_container {
+       struct mm_struct *mm;
+       struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES];
+       struct list_head group_list;
++      struct list_head prereg_list;
+ };
+ static long tce_iommu_mm_set(struct tce_container *container)
+@@ -117,10 +127,27 @@ static long tce_iommu_mm_set(struct tce_
+       return 0;
+ }
++static long tce_iommu_prereg_free(struct tce_container *container,
++              struct tce_iommu_prereg *tcemem)
++{
++      long ret;
++
++      ret = mm_iommu_put(container->mm, tcemem->mem);
++      if (ret)
++              return ret;
++
++      list_del(&tcemem->next);
++      kfree(tcemem);
++
++      return 0;
++}
++
+ static long tce_iommu_unregister_pages(struct tce_container *container,
+               __u64 vaddr, __u64 size)
+ {
+       struct mm_iommu_table_group_mem_t *mem;
++      struct tce_iommu_prereg *tcemem;
++      bool found = false;
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK))
+               return -EINVAL;
+@@ -129,7 +156,17 @@ static long tce_iommu_unregister_pages(s
+       if (!mem)
+               return -ENOENT;
+-      return mm_iommu_put(container->mm, mem);
++      list_for_each_entry(tcemem, &container->prereg_list, next) {
++              if (tcemem->mem == mem) {
++                      found = true;
++                      break;
++              }
++      }
++
++      if (!found)
++              return -ENOENT;
++
++      return tce_iommu_prereg_free(container, tcemem);
+ }
+ static long tce_iommu_register_pages(struct tce_container *container,
+@@ -137,16 +174,29 @@ static long tce_iommu_register_pages(str
+ {
+       long ret = 0;
+       struct mm_iommu_table_group_mem_t *mem = NULL;
++      struct tce_iommu_prereg *tcemem;
+       unsigned long entries = size >> PAGE_SHIFT;
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) ||
+                       ((vaddr + size) < vaddr))
+               return -EINVAL;
++      mem = mm_iommu_find(container->mm, vaddr, entries);
++      if (mem) {
++              list_for_each_entry(tcemem, &container->prereg_list, next) {
++                      if (tcemem->mem == mem)
++                              return -EBUSY;
++              }
++      }
++
+       ret = mm_iommu_get(container->mm, vaddr, entries, &mem);
+       if (ret)
+               return ret;
++      tcemem = kzalloc(sizeof(*tcemem), GFP_KERNEL);
++      tcemem->mem = mem;
++      list_add(&tcemem->next, &container->prereg_list);
++
+       container->enabled = true;
+       return 0;
+@@ -333,6 +383,7 @@ static void *tce_iommu_open(unsigned lon
+       mutex_init(&container->lock);
+       INIT_LIST_HEAD_RCU(&container->group_list);
++      INIT_LIST_HEAD_RCU(&container->prereg_list);
+       container->v2 = arg == VFIO_SPAPR_TCE_v2_IOMMU;
+@@ -371,6 +422,14 @@ static void tce_iommu_release(void *iomm
+               tce_iommu_free_table(container, tbl);
+       }
++      while (!list_empty(&container->prereg_list)) {
++              struct tce_iommu_prereg *tcemem;
++
++              tcemem = list_first_entry(&container->prereg_list,
++                              struct tce_iommu_prereg, next);
++              WARN_ON_ONCE(tce_iommu_prereg_free(container, tcemem));
++      }
++
+       tce_iommu_disable(container);
+       if (container->mm)
+               mmdrop(container->mm);
diff --git a/queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch b/queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch
new file mode 100644 (file)
index 0000000..ed44e7d
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:31 +0000
+Subject: [PATCH v2 for-4.9 32/40] s390/zcrypt: Introduce CEX6 toleration
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-32-alexander.levin@verizon.com>
+
+From: Harald Freudenberger <freude@linux.vnet.ibm.com>
+
+[ Upstream commit b3e8652bcbfa04807e44708d4d0c8cdad39c9215 ]
+
+Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/s390/crypto/ap_bus.c |    3 +++
+ drivers/s390/crypto/ap_bus.h |    1 +
+ 2 files changed, 4 insertions(+)
+
+--- a/drivers/s390/crypto/ap_bus.c
++++ b/drivers/s390/crypto/ap_bus.c
+@@ -1712,6 +1712,9 @@ static void ap_scan_bus(struct work_stru
+               ap_dev->queue_depth = queue_depth;
+               ap_dev->raw_hwtype = device_type;
+               ap_dev->device_type = device_type;
++              /* CEX6 toleration: map to CEX5 */
++              if (device_type == AP_DEVICE_TYPE_CEX6)
++                      ap_dev->device_type = AP_DEVICE_TYPE_CEX5;
+               ap_dev->functions = device_functions;
+               spin_lock_init(&ap_dev->lock);
+               INIT_LIST_HEAD(&ap_dev->pendingq);
+--- a/drivers/s390/crypto/ap_bus.h
++++ b/drivers/s390/crypto/ap_bus.h
+@@ -105,6 +105,7 @@ static inline int ap_test_bit(unsigned i
+ #define AP_DEVICE_TYPE_CEX3C  9
+ #define AP_DEVICE_TYPE_CEX4   10
+ #define AP_DEVICE_TYPE_CEX5   11
++#define AP_DEVICE_TYPE_CEX6   12
+ /*
+  * Known function facilities
diff --git a/queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch b/queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch
new file mode 100644 (file)
index 0000000..3d361a5
--- /dev/null
@@ -0,0 +1,45 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:20 +0000
+Subject: [PATCH v2 for-4.9 06/40] scsi: ibmvscsis: Clean up properly if target_submit_cmd/tmr fails
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-6-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit 7435b32e2d2fb5da6c2ae9b9c8ce56d8a3cb3bc3 ]
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -2552,6 +2552,10 @@ static void ibmvscsis_parse_cmd(struct s
+                              data_len, attr, dir, 0);
+       if (rc) {
+               dev_err(&vscsi->dev, "target_submit_cmd failed, rc %d\n", rc);
++              spin_lock_bh(&vscsi->intr_lock);
++              list_del(&cmd->list);
++              ibmvscsis_free_cmd_resources(vscsi, cmd);
++              spin_unlock_bh(&vscsi->intr_lock);
+               goto fail;
+       }
+       return;
+@@ -2631,6 +2635,9 @@ static void ibmvscsis_parse_task(struct
+               if (rc) {
+                       dev_err(&vscsi->dev, "target_submit_tmr failed, rc %d\n",
+                               rc);
++                      spin_lock_bh(&vscsi->intr_lock);
++                      list_del(&cmd->list);
++                      spin_unlock_bh(&vscsi->intr_lock);
+                       cmd->se_cmd.se_tmr_req->response =
+                               TMR_FUNCTION_REJECTED;
+               }
diff --git a/queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch b/queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch
new file mode 100644 (file)
index 0000000..c987464
--- /dev/null
@@ -0,0 +1,58 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:20 +0000
+Subject: [PATCH v2 for-4.9 04/40] scsi: ibmvscsis: Issues from Dan Carpenter/Smatch
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-4-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit 11950d70b52d2bc5e3580da8cd63909ef38d67db ]
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |   13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -1746,14 +1746,7 @@ static long ibmvscsis_mad(struct scsi_in
+               pr_debug("mad: type %d\n", be32_to_cpu(mad->type));
+-              if (be16_to_cpu(mad->length) < 0) {
+-                      dev_err(&vscsi->dev, "mad: length is < 0\n");
+-                      ibmvscsis_post_disconnect(vscsi,
+-                                                ERR_DISCONNECT_RECONNECT, 0);
+-                      rc = SRP_VIOLATION;
+-              } else {
+-                      rc = ibmvscsis_process_mad(vscsi, iue);
+-              }
++              rc = ibmvscsis_process_mad(vscsi, iue);
+               pr_debug("mad: status %hd, rc %ld\n", be16_to_cpu(mad->status),
+                        rc);
+@@ -2523,7 +2516,6 @@ static void ibmvscsis_parse_cmd(struct s
+               dev_err(&vscsi->dev, "0x%llx: parsing SRP descriptor table failed.\n",
+                       srp->tag);
+               goto fail;
+-              return;
+       }
+       cmd->rsp.sol_not = srp->sol_not;
+@@ -3379,7 +3371,8 @@ static int ibmvscsis_probe(struct vio_de
+       INIT_LIST_HEAD(&vscsi->waiting_rsp);
+       INIT_LIST_HEAD(&vscsi->active_q);
+-      snprintf(vscsi->tport.tport_name, 256, "%s", dev_name(&vdev->dev));
++      snprintf(vscsi->tport.tport_name, IBMVSCSIS_NAMELEN, "%s",
++               dev_name(&vdev->dev));
+       pr_debug("probe tport_name: %s\n", vscsi->tport.tport_name);
diff --git a/queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch b/queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch
new file mode 100644 (file)
index 0000000..b25b19f
--- /dev/null
@@ -0,0 +1,822 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:21 +0000
+Subject: [PATCH v2 for-4.9 07/40] scsi: ibmvscsis: Rearrange functions for future patches
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-7-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit 79fac9c9b74f4951c9ce82b22e714bcc34ae4a56 ]
+
+This patch reorders functions in a manner necessary for a follow-on
+patch.  It also makes some minor styling changes (mostly removing extra
+spaces) and fixes some typos.
+
+There are no code changes in this patch, with one exception: due to the
+reordering of the functions, I needed to explicitly declare a function
+at the top of the file.  However, this will be removed in the next patch,
+since the code requiring the predeclaration will be removed.
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |  658 +++++++++++++++----------------
+ 1 file changed, 330 insertions(+), 328 deletions(-)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -22,7 +22,7 @@
+  *
+  ****************************************************************************/
+-#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
++#define pr_fmt(fmt)   KBUILD_MODNAME ": " fmt
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -62,6 +62,8 @@ static long ibmvscsis_parse_command(stru
+ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi);
++static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state);
++
+ static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+                                     struct srp_rsp *rsp)
+ {
+@@ -82,7 +84,7 @@ static void ibmvscsis_determine_resid(st
+               }
+       } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+               if (se_cmd->data_direction == DMA_TO_DEVICE) {
+-                      /*  residual data from an overflow write */
++                      /* residual data from an overflow write */
+                       rsp->flags = SRP_RSP_FLAG_DOOVER;
+                       rsp->data_out_res_cnt = cpu_to_be32(residual_count);
+               } else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+@@ -102,7 +104,7 @@ static void ibmvscsis_determine_resid(st
+  * and the function returns TRUE.
+  *
+  * EXECUTION ENVIRONMENT:
+- *      Interrupt or Process environment
++ *    Interrupt or Process environment
+  */
+ static bool connection_broken(struct scsi_info *vscsi)
+ {
+@@ -325,7 +327,7 @@ static struct viosrp_crq *ibmvscsis_cmd_
+ }
+ /**
+- * ibmvscsis_send_init_message() -  send initialize message to the client
++ * ibmvscsis_send_init_message() - send initialize message to the client
+  * @vscsi:    Pointer to our adapter structure
+  * @format:   Which Init Message format to send
+  *
+@@ -383,13 +385,13 @@ static long ibmvscsis_check_init_msg(str
+                                             vscsi->cmd_q.base_addr);
+               if (crq) {
+                       *format = (uint)(crq->format);
+-                      rc =  ERROR;
++                      rc = ERROR;
+                       crq->valid = INVALIDATE_CMD_RESP_EL;
+                       dma_rmb();
+               }
+       } else {
+               *format = (uint)(crq->format);
+-              rc =  ERROR;
++              rc = ERROR;
+               crq->valid = INVALIDATE_CMD_RESP_EL;
+               dma_rmb();
+       }
+@@ -398,166 +400,6 @@ static long ibmvscsis_check_init_msg(str
+ }
+ /**
+- * ibmvscsis_establish_new_q() - Establish new CRQ queue
+- * @vscsi:    Pointer to our adapter structure
+- * @new_state:        New state being established after resetting the queue
+- *
+- * Must be called with interrupt lock held.
+- */
+-static long ibmvscsis_establish_new_q(struct scsi_info *vscsi,  uint new_state)
+-{
+-      long rc = ADAPT_SUCCESS;
+-      uint format;
+-
+-      vscsi->flags &= PRESERVE_FLAG_FIELDS;
+-      vscsi->rsp_q_timer.timer_pops = 0;
+-      vscsi->debit = 0;
+-      vscsi->credit = 0;
+-
+-      rc = vio_enable_interrupts(vscsi->dma_dev);
+-      if (rc) {
+-              pr_warn("reset_queue: failed to enable interrupts, rc %ld\n",
+-                      rc);
+-              return rc;
+-      }
+-
+-      rc = ibmvscsis_check_init_msg(vscsi, &format);
+-      if (rc) {
+-              dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n",
+-                      rc);
+-              return rc;
+-      }
+-
+-      if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) {
+-              rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+-              switch (rc) {
+-              case H_SUCCESS:
+-              case H_DROPPED:
+-              case H_CLOSED:
+-                      rc = ADAPT_SUCCESS;
+-                      break;
+-
+-              case H_PARAMETER:
+-              case H_HARDWARE:
+-                      break;
+-
+-              default:
+-                      vscsi->state = UNDEFINED;
+-                      rc = H_HARDWARE;
+-                      break;
+-              }
+-      }
+-
+-      return rc;
+-}
+-
+-/**
+- * ibmvscsis_reset_queue() - Reset CRQ Queue
+- * @vscsi:    Pointer to our adapter structure
+- * @new_state:        New state to establish after resetting the queue
+- *
+- * This function calls h_free_q and then calls h_reg_q and does all
+- * of the bookkeeping to get us back to where we can communicate.
+- *
+- * Actually, we don't always call h_free_crq.  A problem was discovered
+- * where one partition would close and reopen his queue, which would
+- * cause his partner to get a transport event, which would cause him to
+- * close and reopen his queue, which would cause the original partition
+- * to get a transport event, etc., etc.  To prevent this, we don't
+- * actually close our queue if the client initiated the reset, (i.e.
+- * either we got a transport event or we have detected that the client's
+- * queue is gone)
+- *
+- * EXECUTION ENVIRONMENT:
+- *    Process environment, called with interrupt lock held
+- */
+-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state)
+-{
+-      int bytes;
+-      long rc = ADAPT_SUCCESS;
+-
+-      pr_debug("reset_queue: flags 0x%x\n", vscsi->flags);
+-
+-      /* don't reset, the client did it for us */
+-      if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) {
+-              vscsi->flags &=  PRESERVE_FLAG_FIELDS;
+-              vscsi->rsp_q_timer.timer_pops = 0;
+-              vscsi->debit = 0;
+-              vscsi->credit = 0;
+-              vscsi->state = new_state;
+-              vio_enable_interrupts(vscsi->dma_dev);
+-      } else {
+-              rc = ibmvscsis_free_command_q(vscsi);
+-              if (rc == ADAPT_SUCCESS) {
+-                      vscsi->state = new_state;
+-
+-                      bytes = vscsi->cmd_q.size * PAGE_SIZE;
+-                      rc = h_reg_crq(vscsi->dds.unit_id,
+-                                     vscsi->cmd_q.crq_token, bytes);
+-                      if (rc == H_CLOSED || rc == H_SUCCESS) {
+-                              rc = ibmvscsis_establish_new_q(vscsi,
+-                                                             new_state);
+-                      }
+-
+-                      if (rc != ADAPT_SUCCESS) {
+-                              pr_debug("reset_queue: reg_crq rc %ld\n", rc);
+-
+-                              vscsi->state = ERR_DISCONNECTED;
+-                              vscsi->flags |=  RESPONSE_Q_DOWN;
+-                              ibmvscsis_free_command_q(vscsi);
+-                      }
+-              } else {
+-                      vscsi->state = ERR_DISCONNECTED;
+-                      vscsi->flags |= RESPONSE_Q_DOWN;
+-              }
+-      }
+-}
+-
+-/**
+- * ibmvscsis_free_cmd_resources() - Free command resources
+- * @vscsi:    Pointer to our adapter structure
+- * @cmd:      Command which is not longer in use
+- *
+- * Must be called with interrupt lock held.
+- */
+-static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
+-                                       struct ibmvscsis_cmd *cmd)
+-{
+-      struct iu_entry *iue = cmd->iue;
+-
+-      switch (cmd->type) {
+-      case TASK_MANAGEMENT:
+-      case SCSI_CDB:
+-              /*
+-               * When the queue goes down this value is cleared, so it
+-               * cannot be cleared in this general purpose function.
+-               */
+-              if (vscsi->debit)
+-                      vscsi->debit -= 1;
+-              break;
+-      case ADAPTER_MAD:
+-              vscsi->flags &= ~PROCESSING_MAD;
+-              break;
+-      case UNSET_TYPE:
+-              break;
+-      default:
+-              dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n",
+-                      cmd->type);
+-              break;
+-      }
+-
+-      cmd->iue = NULL;
+-      list_add_tail(&cmd->list, &vscsi->free_cmd);
+-      srp_iu_put(iue);
+-
+-      if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) &&
+-          list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) {
+-              vscsi->flags &= ~WAIT_FOR_IDLE;
+-              complete(&vscsi->wait_idle);
+-      }
+-}
+-
+-/**
+  * ibmvscsis_disconnect() - Helper function to disconnect
+  * @work:     Pointer to work_struct, gives access to our adapter structure
+  *
+@@ -590,7 +432,7 @@ static void ibmvscsis_disconnect(struct
+        * should transitition to the new state
+        */
+       switch (vscsi->state) {
+-      /*  Should never be called while in this state. */
++      /* Should never be called while in this state. */
+       case NO_QUEUE:
+       /*
+        * Can never transition from this state;
+@@ -807,6 +649,316 @@ static void ibmvscsis_post_disconnect(st
+ }
+ /**
++ * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message
++ * @vscsi:    Pointer to our adapter structure
++ *
++ * Must be called with interrupt lock held.
++ */
++static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi)
++{
++      long rc = ADAPT_SUCCESS;
++
++      switch (vscsi->state) {
++      case NO_QUEUE:
++      case ERR_DISCONNECT:
++      case ERR_DISCONNECT_RECONNECT:
++      case ERR_DISCONNECTED:
++      case UNCONFIGURING:
++      case UNDEFINED:
++              rc = ERROR;
++              break;
++
++      case WAIT_CONNECTION:
++              vscsi->state = CONNECTED;
++              break;
++
++      case WAIT_IDLE:
++      case SRP_PROCESSING:
++      case CONNECTED:
++      case WAIT_ENABLED:
++      case PART_UP_WAIT_ENAB:
++      default:
++              rc = ERROR;
++              dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
++                      vscsi->state);
++              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
++              break;
++      }
++
++      return rc;
++}
++
++/**
++ * ibmvscsis_handle_init_msg() - Respond to an Init Message
++ * @vscsi:    Pointer to our adapter structure
++ *
++ * Must be called with interrupt lock held.
++ */
++static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi)
++{
++      long rc = ADAPT_SUCCESS;
++
++      switch (vscsi->state) {
++      case WAIT_ENABLED:
++              vscsi->state = PART_UP_WAIT_ENAB;
++              break;
++
++      case WAIT_CONNECTION:
++              rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
++              switch (rc) {
++              case H_SUCCESS:
++                      vscsi->state = CONNECTED;
++                      break;
++
++              case H_PARAMETER:
++                      dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
++                              rc);
++                      ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
++                      break;
++
++              case H_DROPPED:
++                      dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
++                              rc);
++                      rc = ERROR;
++                      ibmvscsis_post_disconnect(vscsi,
++                                                ERR_DISCONNECT_RECONNECT, 0);
++                      break;
++
++              case H_CLOSED:
++                      pr_warn("init_msg: failed to send, rc %ld\n", rc);
++                      rc = 0;
++                      break;
++              }
++              break;
++
++      case UNDEFINED:
++              rc = ERROR;
++              break;
++
++      case UNCONFIGURING:
++              break;
++
++      case PART_UP_WAIT_ENAB:
++      case CONNECTED:
++      case SRP_PROCESSING:
++      case WAIT_IDLE:
++      case NO_QUEUE:
++      case ERR_DISCONNECT:
++      case ERR_DISCONNECT_RECONNECT:
++      case ERR_DISCONNECTED:
++      default:
++              rc = ERROR;
++              dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n",
++                      vscsi->state);
++              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
++              break;
++      }
++
++      return rc;
++}
++
++/**
++ * ibmvscsis_init_msg() - Respond to an init message
++ * @vscsi:    Pointer to our adapter structure
++ * @crq:      Pointer to CRQ element containing the Init Message
++ *
++ * EXECUTION ENVIRONMENT:
++ *    Interrupt, interrupt lock held
++ */
++static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq)
++{
++      long rc = ADAPT_SUCCESS;
++
++      pr_debug("init_msg: state 0x%hx\n", vscsi->state);
++
++      rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
++                    (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
++                    0);
++      if (rc == H_SUCCESS) {
++              vscsi->client_data.partition_number =
++                      be64_to_cpu(*(u64 *)vscsi->map_buf);
++              pr_debug("init_msg, part num %d\n",
++                       vscsi->client_data.partition_number);
++      } else {
++              pr_debug("init_msg h_vioctl rc %ld\n", rc);
++              rc = ADAPT_SUCCESS;
++      }
++
++      if (crq->format == INIT_MSG) {
++              rc = ibmvscsis_handle_init_msg(vscsi);
++      } else if (crq->format == INIT_COMPLETE_MSG) {
++              rc = ibmvscsis_handle_init_compl_msg(vscsi);
++      } else {
++              rc = ERROR;
++              dev_err(&vscsi->dev, "init_msg: invalid format %d\n",
++                      (uint)crq->format);
++              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
++      }
++
++      return rc;
++}
++
++/**
++ * ibmvscsis_establish_new_q() - Establish new CRQ queue
++ * @vscsi:    Pointer to our adapter structure
++ * @new_state:        New state being established after resetting the queue
++ *
++ * Must be called with interrupt lock held.
++ */
++static long ibmvscsis_establish_new_q(struct scsi_info *vscsi, uint new_state)
++{
++      long rc = ADAPT_SUCCESS;
++      uint format;
++
++      vscsi->flags &= PRESERVE_FLAG_FIELDS;
++      vscsi->rsp_q_timer.timer_pops = 0;
++      vscsi->debit = 0;
++      vscsi->credit = 0;
++
++      rc = vio_enable_interrupts(vscsi->dma_dev);
++      if (rc) {
++              pr_warn("reset_queue: failed to enable interrupts, rc %ld\n",
++                      rc);
++              return rc;
++      }
++
++      rc = ibmvscsis_check_init_msg(vscsi, &format);
++      if (rc) {
++              dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n",
++                      rc);
++              return rc;
++      }
++
++      if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) {
++              rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
++              switch (rc) {
++              case H_SUCCESS:
++              case H_DROPPED:
++              case H_CLOSED:
++                      rc = ADAPT_SUCCESS;
++                      break;
++
++              case H_PARAMETER:
++              case H_HARDWARE:
++                      break;
++
++              default:
++                      vscsi->state = UNDEFINED;
++                      rc = H_HARDWARE;
++                      break;
++              }
++      }
++
++      return rc;
++}
++
++/**
++ * ibmvscsis_reset_queue() - Reset CRQ Queue
++ * @vscsi:    Pointer to our adapter structure
++ * @new_state:        New state to establish after resetting the queue
++ *
++ * This function calls h_free_q and then calls h_reg_q and does all
++ * of the bookkeeping to get us back to where we can communicate.
++ *
++ * Actually, we don't always call h_free_crq.  A problem was discovered
++ * where one partition would close and reopen his queue, which would
++ * cause his partner to get a transport event, which would cause him to
++ * close and reopen his queue, which would cause the original partition
++ * to get a transport event, etc., etc.  To prevent this, we don't
++ * actually close our queue if the client initiated the reset, (i.e.
++ * either we got a transport event or we have detected that the client's
++ * queue is gone)
++ *
++ * EXECUTION ENVIRONMENT:
++ *    Process environment, called with interrupt lock held
++ */
++static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state)
++{
++      int bytes;
++      long rc = ADAPT_SUCCESS;
++
++      pr_debug("reset_queue: flags 0x%x\n", vscsi->flags);
++
++      /* don't reset, the client did it for us */
++      if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) {
++              vscsi->flags &= PRESERVE_FLAG_FIELDS;
++              vscsi->rsp_q_timer.timer_pops = 0;
++              vscsi->debit = 0;
++              vscsi->credit = 0;
++              vscsi->state = new_state;
++              vio_enable_interrupts(vscsi->dma_dev);
++      } else {
++              rc = ibmvscsis_free_command_q(vscsi);
++              if (rc == ADAPT_SUCCESS) {
++                      vscsi->state = new_state;
++
++                      bytes = vscsi->cmd_q.size * PAGE_SIZE;
++                      rc = h_reg_crq(vscsi->dds.unit_id,
++                                     vscsi->cmd_q.crq_token, bytes);
++                      if (rc == H_CLOSED || rc == H_SUCCESS) {
++                              rc = ibmvscsis_establish_new_q(vscsi,
++                                                             new_state);
++                      }
++
++                      if (rc != ADAPT_SUCCESS) {
++                              pr_debug("reset_queue: reg_crq rc %ld\n", rc);
++
++                              vscsi->state = ERR_DISCONNECTED;
++                              vscsi->flags |= RESPONSE_Q_DOWN;
++                              ibmvscsis_free_command_q(vscsi);
++                      }
++              } else {
++                      vscsi->state = ERR_DISCONNECTED;
++                      vscsi->flags |= RESPONSE_Q_DOWN;
++              }
++      }
++}
++
++/**
++ * ibmvscsis_free_cmd_resources() - Free command resources
++ * @vscsi:    Pointer to our adapter structure
++ * @cmd:      Command which is not longer in use
++ *
++ * Must be called with interrupt lock held.
++ */
++static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
++                                       struct ibmvscsis_cmd *cmd)
++{
++      struct iu_entry *iue = cmd->iue;
++
++      switch (cmd->type) {
++      case TASK_MANAGEMENT:
++      case SCSI_CDB:
++              /*
++               * When the queue goes down this value is cleared, so it
++               * cannot be cleared in this general purpose function.
++               */
++              if (vscsi->debit)
++                      vscsi->debit -= 1;
++              break;
++      case ADAPTER_MAD:
++              vscsi->flags &= ~PROCESSING_MAD;
++              break;
++      case UNSET_TYPE:
++              break;
++      default:
++              dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n",
++                      cmd->type);
++              break;
++      }
++
++      cmd->iue = NULL;
++      list_add_tail(&cmd->list, &vscsi->free_cmd);
++      srp_iu_put(iue);
++
++      if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) &&
++          list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) {
++              vscsi->flags &= ~WAIT_FOR_IDLE;
++              complete(&vscsi->wait_idle);
++      }
++}
++
++/**
+  * ibmvscsis_trans_event() - Handle a Transport Event
+  * @vscsi:    Pointer to our adapter structure
+  * @crq:      Pointer to CRQ entry containing the Transport Event
+@@ -896,7 +1048,7 @@ static long ibmvscsis_trans_event(struct
+               }
+       }
+-      rc =  vscsi->flags & SCHEDULE_DISCONNECT;
++      rc = vscsi->flags & SCHEDULE_DISCONNECT;
+       pr_debug("Leaving trans_event: flags 0x%x, state 0x%hx, rc %ld\n",
+                vscsi->flags, vscsi->state, rc);
+@@ -1221,7 +1373,7 @@ static long ibmvscsis_copy_crq_packet(st
+  * @iue:      Information Unit containing the Adapter Info MAD request
+  *
+  * EXECUTION ENVIRONMENT:
+- *    Interrupt adpater lock is held
++ *    Interrupt adapter lock is held
+  */
+ static long ibmvscsis_adapter_info(struct scsi_info *vscsi,
+                                  struct iu_entry *iue)
+@@ -1692,7 +1844,7 @@ static void ibmvscsis_send_mad_resp(stru
+  * @crq:      Pointer to the CRQ entry containing the MAD request
+  *
+  * EXECUTION ENVIRONMENT:
+- *    Interrupt  called with adapter lock held
++ *    Interrupt, called with adapter lock held
+  */
+ static long ibmvscsis_mad(struct scsi_info *vscsi, struct viosrp_crq *crq)
+ {
+@@ -1858,7 +2010,7 @@ static long ibmvscsis_srp_login_rej(stru
+               break;
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+-                      flag_bits =  RESPONSE_Q_DOWN | CLIENT_FAILED;
++                      flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
+               dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+@@ -2181,156 +2333,6 @@ static long ibmvscsis_ping_response(stru
+ }
+ /**
+- * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message
+- * @vscsi:    Pointer to our adapter structure
+- *
+- * Must be called with interrupt lock held.
+- */
+-static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi)
+-{
+-      long rc = ADAPT_SUCCESS;
+-
+-      switch (vscsi->state) {
+-      case NO_QUEUE:
+-      case ERR_DISCONNECT:
+-      case ERR_DISCONNECT_RECONNECT:
+-      case ERR_DISCONNECTED:
+-      case UNCONFIGURING:
+-      case UNDEFINED:
+-              rc = ERROR;
+-              break;
+-
+-      case WAIT_CONNECTION:
+-              vscsi->state = CONNECTED;
+-              break;
+-
+-      case WAIT_IDLE:
+-      case SRP_PROCESSING:
+-      case CONNECTED:
+-      case WAIT_ENABLED:
+-      case PART_UP_WAIT_ENAB:
+-      default:
+-              rc = ERROR;
+-              dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
+-                      vscsi->state);
+-              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+-              break;
+-      }
+-
+-      return rc;
+-}
+-
+-/**
+- * ibmvscsis_handle_init_msg() - Respond to an Init Message
+- * @vscsi:    Pointer to our adapter structure
+- *
+- * Must be called with interrupt lock held.
+- */
+-static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi)
+-{
+-      long rc = ADAPT_SUCCESS;
+-
+-      switch (vscsi->state) {
+-      case WAIT_ENABLED:
+-              vscsi->state = PART_UP_WAIT_ENAB;
+-              break;
+-
+-      case WAIT_CONNECTION:
+-              rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+-              switch (rc) {
+-              case H_SUCCESS:
+-                      vscsi->state = CONNECTED;
+-                      break;
+-
+-              case H_PARAMETER:
+-                      dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+-                              rc);
+-                      ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+-                      break;
+-
+-              case H_DROPPED:
+-                      dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+-                              rc);
+-                      rc = ERROR;
+-                      ibmvscsis_post_disconnect(vscsi,
+-                                                ERR_DISCONNECT_RECONNECT, 0);
+-                      break;
+-
+-              case H_CLOSED:
+-                      pr_warn("init_msg: failed to send, rc %ld\n", rc);
+-                      rc = 0;
+-                      break;
+-              }
+-              break;
+-
+-      case UNDEFINED:
+-              rc = ERROR;
+-              break;
+-
+-      case UNCONFIGURING:
+-              break;
+-
+-      case PART_UP_WAIT_ENAB:
+-      case CONNECTED:
+-      case SRP_PROCESSING:
+-      case WAIT_IDLE:
+-      case NO_QUEUE:
+-      case ERR_DISCONNECT:
+-      case ERR_DISCONNECT_RECONNECT:
+-      case ERR_DISCONNECTED:
+-      default:
+-              rc = ERROR;
+-              dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n",
+-                      vscsi->state);
+-              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+-              break;
+-      }
+-
+-      return rc;
+-}
+-
+-/**
+- * ibmvscsis_init_msg() - Respond to an init message
+- * @vscsi:    Pointer to our adapter structure
+- * @crq:      Pointer to CRQ element containing the Init Message
+- *
+- * EXECUTION ENVIRONMENT:
+- *    Interrupt, interrupt lock held
+- */
+-static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq)
+-{
+-      long rc = ADAPT_SUCCESS;
+-
+-      pr_debug("init_msg: state 0x%hx\n", vscsi->state);
+-
+-      rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
+-                    (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
+-                    0);
+-      if (rc == H_SUCCESS) {
+-              vscsi->client_data.partition_number =
+-                      be64_to_cpu(*(u64 *)vscsi->map_buf);
+-              pr_debug("init_msg, part num %d\n",
+-                       vscsi->client_data.partition_number);
+-      } else {
+-              pr_debug("init_msg h_vioctl rc %ld\n", rc);
+-              rc = ADAPT_SUCCESS;
+-      }
+-
+-      if (crq->format == INIT_MSG) {
+-              rc = ibmvscsis_handle_init_msg(vscsi);
+-      } else if (crq->format == INIT_COMPLETE_MSG) {
+-              rc = ibmvscsis_handle_init_compl_msg(vscsi);
+-      } else {
+-              rc = ERROR;
+-              dev_err(&vscsi->dev, "init_msg: invalid format %d\n",
+-                      (uint)crq->format);
+-              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+-      }
+-
+-      return rc;
+-}
+-
+-/**
+  * ibmvscsis_parse_command() - Parse an element taken from the cmd rsp queue.
+  * @vscsi:    Pointer to our adapter structure
+  * @crq:      Pointer to CRQ element containing the SRP request
+@@ -2385,7 +2387,7 @@ static long ibmvscsis_parse_command(stru
+               break;
+       case VALID_TRANS_EVENT:
+-              rc =  ibmvscsis_trans_event(vscsi, crq);
++              rc = ibmvscsis_trans_event(vscsi, crq);
+               break;
+       case VALID_INIT_MSG:
+@@ -3270,7 +3272,7 @@ static void ibmvscsis_handle_crq(unsigne
+       /*
+        * if we are in a path where we are waiting for all pending commands
+        * to complete because we received a transport event and anything in
+-       * the command queue is for a new connection,  do nothing
++       * the command queue is for a new connection, do nothing
+        */
+       if (TARGET_STOP(vscsi)) {
+               vio_enable_interrupts(vscsi->dma_dev);
+@@ -3314,7 +3316,7 @@ cmd_work:
+                                * everything but transport events on the queue
+                                *
+                                * need to decrement the queue index so we can
+-                               * look at the elment again
++                               * look at the element again
+                                */
+                               if (vscsi->cmd_q.index)
+                                       vscsi->cmd_q.index -= 1;
+@@ -3988,10 +3990,10 @@ static struct attribute *ibmvscsis_dev_a
+ ATTRIBUTE_GROUPS(ibmvscsis_dev);
+ static struct class ibmvscsis_class = {
+-      .name           = "ibmvscsis",
+-      .dev_release    = ibmvscsis_dev_release,
+-      .class_attrs    = ibmvscsis_class_attrs,
+-      .dev_groups     = ibmvscsis_dev_groups,
++      .name           = "ibmvscsis",
++      .dev_release    = ibmvscsis_dev_release,
++      .class_attrs    = ibmvscsis_class_attrs,
++      .dev_groups     = ibmvscsis_dev_groups,
+ };
+ static struct vio_device_id ibmvscsis_device_table[] = {
diff --git a/queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch b/queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch
new file mode 100644 (file)
index 0000000..e783bf6
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:20 +0000
+Subject: [PATCH v2 for-4.9 05/40] scsi: ibmvscsis: Return correct partition name/# to client
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-5-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit 9c93cf03d4eb3dc58931ff7cac0af9c344fe5e0b ]
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -3387,6 +3387,9 @@ static int ibmvscsis_probe(struct vio_de
+       strncat(vscsi->eye, vdev->name, MAX_EYE);
+       vscsi->dds.unit_id = vdev->unit_address;
++      strncpy(vscsi->dds.partition_name, partition_name,
++              sizeof(vscsi->dds.partition_name));
++      vscsi->dds.partition_num = partition_number;
+       spin_lock_bh(&ibmvscsis_dev_lock);
+       list_add_tail(&vscsi->list, &ibmvscsis_dev_list);
+@@ -3603,7 +3606,7 @@ static int ibmvscsis_get_system_info(voi
+       num = of_get_property(rootdn, "ibm,partition-no", NULL);
+       if (num)
+-              partition_number = *num;
++              partition_number = of_read_number(num, 1);
+       of_node_put(rootdn);
diff --git a/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch
new file mode 100644 (file)
index 0000000..bf4155f
--- /dev/null
@@ -0,0 +1,129 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:22 +0000
+Subject: [PATCH v2 for-4.9 09/40] scsi: ibmvscsis: Synchronize cmds at remove time
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-9-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit 8bf11557d44d00562360d370de8aa70ba89aa0d5 ]
+
+This patch adds code to disconnect from the client, which will make sure
+any outstanding commands have been completed, before continuing on with
+the remove operation.
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |   39 +++++++++++++++++++++++++++----
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h |    3 ++
+ 2 files changed, 37 insertions(+), 5 deletions(-)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -470,6 +470,18 @@ static void ibmvscsis_disconnect(struct
+       case WAIT_ENABLED:
+               switch (new_state) {
++              case UNCONFIGURING:
++                      vscsi->state = new_state;
++                      vscsi->flags |= RESPONSE_Q_DOWN;
++                      vscsi->flags &= ~(SCHEDULE_DISCONNECT |
++                                        DISCONNECT_SCHEDULED);
++                      dma_rmb();
++                      if (vscsi->flags & CFG_SLEEPING) {
++                              vscsi->flags &= ~CFG_SLEEPING;
++                              complete(&vscsi->unconfig);
++                      }
++                      break;
++
+               /* should never happen */
+               case ERR_DISCONNECT:
+               case ERR_DISCONNECT_RECONNECT:
+@@ -482,6 +494,13 @@ static void ibmvscsis_disconnect(struct
+       case WAIT_IDLE:
+               switch (new_state) {
++              case UNCONFIGURING:
++                      vscsi->flags |= RESPONSE_Q_DOWN;
++                      vscsi->state = new_state;
++                      vscsi->flags &= ~(SCHEDULE_DISCONNECT |
++                                        DISCONNECT_SCHEDULED);
++                      ibmvscsis_free_command_q(vscsi);
++                      break;
+               case ERR_DISCONNECT:
+               case ERR_DISCONNECT_RECONNECT:
+                       vscsi->state = new_state;
+@@ -1187,6 +1206,15 @@ static void ibmvscsis_adapter_idle(struc
+               free_qs = true;
+       switch (vscsi->state) {
++      case UNCONFIGURING:
++              ibmvscsis_free_command_q(vscsi);
++              dma_rmb();
++              isync();
++              if (vscsi->flags & CFG_SLEEPING) {
++                      vscsi->flags &= ~CFG_SLEEPING;
++                      complete(&vscsi->unconfig);
++              }
++              break;
+       case ERR_DISCONNECT_RECONNECT:
+               ibmvscsis_reset_queue(vscsi);
+               pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags);
+@@ -3342,6 +3370,7 @@ static int ibmvscsis_probe(struct vio_de
+                    (unsigned long)vscsi);
+       init_completion(&vscsi->wait_idle);
++      init_completion(&vscsi->unconfig);
+       snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev));
+       vscsi->work_q = create_workqueue(wq_name);
+@@ -3397,10 +3426,11 @@ static int ibmvscsis_remove(struct vio_d
+       pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev));
+-      /*
+-       * TBD: Need to handle if there are commands on the waiting_rsp q
+-       *      Actually, can there still be cmds outstanding to tcm?
+-       */
++      spin_lock_bh(&vscsi->intr_lock);
++      ibmvscsis_post_disconnect(vscsi, UNCONFIGURING, 0);
++      vscsi->flags |= CFG_SLEEPING;
++      spin_unlock_bh(&vscsi->intr_lock);
++      wait_for_completion(&vscsi->unconfig);
+       vio_disable_interrupts(vdev);
+       free_irq(vdev->irq, vscsi);
+@@ -3409,7 +3439,6 @@ static int ibmvscsis_remove(struct vio_d
+                        DMA_BIDIRECTIONAL);
+       kfree(vscsi->map_buf);
+       tasklet_kill(&vscsi->work_task);
+-      ibmvscsis_unregister_command_q(vscsi);
+       ibmvscsis_destroy_command_q(vscsi);
+       ibmvscsis_freetimer(vscsi);
+       ibmvscsis_free_cmds(vscsi);
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+@@ -257,6 +257,8 @@ struct scsi_info {
+ #define SCHEDULE_DISCONNECT           0x00400
+       /* disconnect handler is scheduled */
+ #define DISCONNECT_SCHEDULED          0x00800
++      /* remove function is sleeping */
++#define CFG_SLEEPING                  0x01000
+       u32 flags;
+       /* adapter lock */
+       spinlock_t intr_lock;
+@@ -285,6 +287,7 @@ struct scsi_info {
+       struct workqueue_struct *work_q;
+       struct completion wait_idle;
++      struct completion unconfig;
+       struct device dev;
+       struct vio_dev *dma_dev;
+       struct srp_target target;
diff --git a/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch
new file mode 100644 (file)
index 0000000..6da2093
--- /dev/null
@@ -0,0 +1,475 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:21 +0000
+Subject: [PATCH v2 for-4.9 08/40] scsi: ibmvscsis: Synchronize cmds at tpg_enable_store time
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-8-alexander.levin@verizon.com>
+
+From: Michael Cyr <mikecyr@us.ibm.com>
+
+[ Upstream commit c9b3379f60a83288a5e2f8ea75476460978689b0 ]
+
+This patch changes the way the IBM vSCSI server driver manages its
+Command/Response Queue (CRQ).  We used to register the CRQ with phyp at
+probe time.  Now we wait until tpg_enable_store.  Similarly, when
+tpg_enable_store is called to "disable" (i.e. the stored value is 0),
+we unregister the queue with phyp.
+
+One consquence to this is that we have no need for the PART_UP_WAIT_ENAB
+state, since we can't get an Init Message from the client in our CRQ if
+we're waiting to be enabled, since we haven't registered the queue yet.
+
+Signed-off-by: Michael Cyr <mikecyr@us.ibm.com>
+Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Tested-by: Steven Royer <seroyer@linux.vnet.ibm.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c |  224 +++++--------------------------
+ drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h |    2 
+ 2 files changed, 38 insertions(+), 188 deletions(-)
+
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+@@ -62,8 +62,6 @@ static long ibmvscsis_parse_command(stru
+ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi);
+-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state);
+-
+ static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+                                     struct srp_rsp *rsp)
+ {
+@@ -418,7 +416,6 @@ static void ibmvscsis_disconnect(struct
+                                              proc_work);
+       u16 new_state;
+       bool wait_idle = false;
+-      long rc = ADAPT_SUCCESS;
+       spin_lock_bh(&vscsi->intr_lock);
+       new_state = vscsi->new_state;
+@@ -471,30 +468,12 @@ static void ibmvscsis_disconnect(struct
+                       vscsi->state = new_state;
+               break;
+-      /*
+-       * If this is a transition into an error state.
+-       * a client is attempting to establish a connection
+-       * and has violated the RPA protocol.
+-       * There can be nothing pending on the adapter although
+-       * there can be requests in the command queue.
+-       */
+       case WAIT_ENABLED:
+-      case PART_UP_WAIT_ENAB:
+               switch (new_state) {
++              /* should never happen */
+               case ERR_DISCONNECT:
+-                      vscsi->flags |= RESPONSE_Q_DOWN;
+-                      vscsi->state = new_state;
+-                      vscsi->flags &= ~(SCHEDULE_DISCONNECT |
+-                                        DISCONNECT_SCHEDULED);
+-                      ibmvscsis_free_command_q(vscsi);
+-                      break;
+               case ERR_DISCONNECT_RECONNECT:
+-                      ibmvscsis_reset_queue(vscsi, WAIT_ENABLED);
+-                      break;
+-
+-              /* should never happen */
+               case WAIT_IDLE:
+-                      rc = ERROR;
+                       dev_err(&vscsi->dev, "disconnect: invalid state %d for WAIT_IDLE\n",
+                               vscsi->state);
+                       break;
+@@ -631,7 +610,6 @@ static void ibmvscsis_post_disconnect(st
+                       break;
+               case WAIT_ENABLED:
+-              case PART_UP_WAIT_ENAB:
+               case WAIT_IDLE:
+               case WAIT_CONNECTION:
+               case CONNECTED:
+@@ -676,7 +654,6 @@ static long ibmvscsis_handle_init_compl_
+       case SRP_PROCESSING:
+       case CONNECTED:
+       case WAIT_ENABLED:
+-      case PART_UP_WAIT_ENAB:
+       default:
+               rc = ERROR;
+               dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
+@@ -699,10 +676,6 @@ static long ibmvscsis_handle_init_msg(st
+       long rc = ADAPT_SUCCESS;
+       switch (vscsi->state) {
+-      case WAIT_ENABLED:
+-              vscsi->state = PART_UP_WAIT_ENAB;
+-              break;
+-
+       case WAIT_CONNECTION:
+               rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+               switch (rc) {
+@@ -738,7 +711,7 @@ static long ibmvscsis_handle_init_msg(st
+       case UNCONFIGURING:
+               break;
+-      case PART_UP_WAIT_ENAB:
++      case WAIT_ENABLED:
+       case CONNECTED:
+       case SRP_PROCESSING:
+       case WAIT_IDLE:
+@@ -801,11 +774,10 @@ static long ibmvscsis_init_msg(struct sc
+ /**
+  * ibmvscsis_establish_new_q() - Establish new CRQ queue
+  * @vscsi:    Pointer to our adapter structure
+- * @new_state:        New state being established after resetting the queue
+  *
+  * Must be called with interrupt lock held.
+  */
+-static long ibmvscsis_establish_new_q(struct scsi_info *vscsi, uint new_state)
++static long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
+ {
+       long rc = ADAPT_SUCCESS;
+       uint format;
+@@ -817,19 +789,19 @@ static long ibmvscsis_establish_new_q(st
+       rc = vio_enable_interrupts(vscsi->dma_dev);
+       if (rc) {
+-              pr_warn("reset_queue: failed to enable interrupts, rc %ld\n",
++              pr_warn("establish_new_q: failed to enable interrupts, rc %ld\n",
+                       rc);
+               return rc;
+       }
+       rc = ibmvscsis_check_init_msg(vscsi, &format);
+       if (rc) {
+-              dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n",
++              dev_err(&vscsi->dev, "establish_new_q: check_init_msg failed, rc %ld\n",
+                       rc);
+               return rc;
+       }
+-      if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) {
++      if (format == UNUSED_FORMAT) {
+               rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+               switch (rc) {
+               case H_SUCCESS:
+@@ -847,6 +819,8 @@ static long ibmvscsis_establish_new_q(st
+                       rc = H_HARDWARE;
+                       break;
+               }
++      } else if (format == INIT_MSG) {
++              rc = ibmvscsis_handle_init_msg(vscsi);
+       }
+       return rc;
+@@ -855,7 +829,6 @@ static long ibmvscsis_establish_new_q(st
+ /**
+  * ibmvscsis_reset_queue() - Reset CRQ Queue
+  * @vscsi:    Pointer to our adapter structure
+- * @new_state:        New state to establish after resetting the queue
+  *
+  * This function calls h_free_q and then calls h_reg_q and does all
+  * of the bookkeeping to get us back to where we can communicate.
+@@ -872,7 +845,7 @@ static long ibmvscsis_establish_new_q(st
+  * EXECUTION ENVIRONMENT:
+  *    Process environment, called with interrupt lock held
+  */
+-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state)
++static void ibmvscsis_reset_queue(struct scsi_info *vscsi)
+ {
+       int bytes;
+       long rc = ADAPT_SUCCESS;
+@@ -885,19 +858,18 @@ static void ibmvscsis_reset_queue(struct
+               vscsi->rsp_q_timer.timer_pops = 0;
+               vscsi->debit = 0;
+               vscsi->credit = 0;
+-              vscsi->state = new_state;
++              vscsi->state = WAIT_CONNECTION;
+               vio_enable_interrupts(vscsi->dma_dev);
+       } else {
+               rc = ibmvscsis_free_command_q(vscsi);
+               if (rc == ADAPT_SUCCESS) {
+-                      vscsi->state = new_state;
++                      vscsi->state = WAIT_CONNECTION;
+                       bytes = vscsi->cmd_q.size * PAGE_SIZE;
+                       rc = h_reg_crq(vscsi->dds.unit_id,
+                                      vscsi->cmd_q.crq_token, bytes);
+                       if (rc == H_CLOSED || rc == H_SUCCESS) {
+-                              rc = ibmvscsis_establish_new_q(vscsi,
+-                                                             new_state);
++                              rc = ibmvscsis_establish_new_q(vscsi);
+                       }
+                       if (rc != ADAPT_SUCCESS) {
+@@ -1016,10 +988,6 @@ static long ibmvscsis_trans_event(struct
+                                                  TRANS_EVENT));
+                       break;
+-              case PART_UP_WAIT_ENAB:
+-                      vscsi->state = WAIT_ENABLED;
+-                      break;
+-
+               case SRP_PROCESSING:
+                       if ((vscsi->debit > 0) ||
+                           !list_empty(&vscsi->schedule_q) ||
+@@ -1220,15 +1188,18 @@ static void ibmvscsis_adapter_idle(struc
+       switch (vscsi->state) {
+       case ERR_DISCONNECT_RECONNECT:
+-              ibmvscsis_reset_queue(vscsi, WAIT_CONNECTION);
++              ibmvscsis_reset_queue(vscsi);
+               pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags);
+               break;
+       case ERR_DISCONNECT:
+               ibmvscsis_free_command_q(vscsi);
+-              vscsi->flags &= ~DISCONNECT_SCHEDULED;
++              vscsi->flags &= ~(SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED);
+               vscsi->flags |= RESPONSE_Q_DOWN;
+-              vscsi->state = ERR_DISCONNECTED;
++              if (vscsi->tport.enabled)
++                      vscsi->state = ERR_DISCONNECTED;
++              else
++                      vscsi->state = WAIT_ENABLED;
+               pr_debug("adapter_idle, disc: flags 0x%x, state 0x%hx\n",
+                        vscsi->flags, vscsi->state);
+               break;
+@@ -1773,8 +1744,8 @@ static void ibmvscsis_send_messages(stru
+                                       be64_to_cpu(msg_hi),
+                                       be64_to_cpu(cmd->rsp.tag));
+-                      pr_debug("send_messages: tag 0x%llx, rc %ld\n",
+-                               be64_to_cpu(cmd->rsp.tag), rc);
++                      pr_debug("send_messages: cmd %p, tag 0x%llx, rc %ld\n",
++                               cmd, be64_to_cpu(cmd->rsp.tag), rc);
+                       /* if all ok free up the command element resources */
+                       if (rc == H_SUCCESS) {
+@@ -2788,36 +2759,6 @@ static irqreturn_t ibmvscsis_interrupt(i
+ }
+ /**
+- * ibmvscsis_check_q() - Helper function to Check Init Message Valid
+- * @vscsi:    Pointer to our adapter structure
+- *
+- * Checks if a initialize message was queued by the initiatior
+- * while the timing window was open.  This function is called from
+- * probe after the CRQ is created and interrupts are enabled.
+- * It would only be used by adapters who wait for some event before
+- * completing the init handshake with the client.  For ibmvscsi, this
+- * event is waiting for the port to be enabled.
+- *
+- * EXECUTION ENVIRONMENT:
+- *    Process level only, interrupt lock held
+- */
+-static long ibmvscsis_check_q(struct scsi_info *vscsi)
+-{
+-      uint format;
+-      long rc;
+-
+-      rc = ibmvscsis_check_init_msg(vscsi, &format);
+-      if (rc)
+-              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+-      else if (format == UNUSED_FORMAT)
+-              vscsi->state = WAIT_ENABLED;
+-      else
+-              vscsi->state = PART_UP_WAIT_ENAB;
+-
+-      return rc;
+-}
+-
+-/**
+  * ibmvscsis_enable_change_state() - Set new state based on enabled status
+  * @vscsi:    Pointer to our adapter structure
+  *
+@@ -2828,77 +2769,19 @@ static long ibmvscsis_check_q(struct scs
+  */
+ static long ibmvscsis_enable_change_state(struct scsi_info *vscsi)
+ {
++      int bytes;
+       long rc = ADAPT_SUCCESS;
+-handle_state_change:
+-      switch (vscsi->state) {
+-      case WAIT_ENABLED:
+-              rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+-              switch (rc) {
+-              case H_SUCCESS:
+-              case H_DROPPED:
+-              case H_CLOSED:
+-                      vscsi->state =  WAIT_CONNECTION;
+-                      rc = ADAPT_SUCCESS;
+-                      break;
+-
+-              case H_PARAMETER:
+-                      break;
+-
+-              case H_HARDWARE:
+-                      break;
+-
+-              default:
+-                      vscsi->state = UNDEFINED;
+-                      rc = H_HARDWARE;
+-                      break;
+-              }
+-              break;
+-      case PART_UP_WAIT_ENAB:
+-              rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+-              switch (rc) {
+-              case H_SUCCESS:
+-                      vscsi->state = CONNECTED;
+-                      rc = ADAPT_SUCCESS;
+-                      break;
+-
+-              case H_DROPPED:
+-              case H_CLOSED:
+-                      vscsi->state = WAIT_ENABLED;
+-                      goto handle_state_change;
+-
+-              case H_PARAMETER:
+-                      break;
+-
+-              case H_HARDWARE:
+-                      break;
+-
+-              default:
+-                      rc = H_HARDWARE;
+-                      break;
+-              }
+-              break;
+-
+-      case WAIT_CONNECTION:
+-      case WAIT_IDLE:
+-      case SRP_PROCESSING:
+-      case CONNECTED:
+-              rc = ADAPT_SUCCESS;
+-              break;
+-              /* should not be able to get here */
+-      case UNCONFIGURING:
+-              rc = ERROR;
+-              vscsi->state = UNDEFINED;
+-              break;
++      bytes = vscsi->cmd_q.size * PAGE_SIZE;
++      rc = h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, bytes);
++      if (rc == H_CLOSED || rc == H_SUCCESS) {
++              vscsi->state = WAIT_CONNECTION;
++              rc = ibmvscsis_establish_new_q(vscsi);
++      }
+-              /* driver should never allow this to happen */
+-      case ERR_DISCONNECT:
+-      case ERR_DISCONNECT_RECONNECT:
+-      default:
+-              dev_err(&vscsi->dev, "in invalid state %d during enable_change_state\n",
+-                      vscsi->state);
+-              rc = ADAPT_SUCCESS;
+-              break;
++      if (rc != ADAPT_SUCCESS) {
++              vscsi->state = ERR_DISCONNECTED;
++              vscsi->flags |= RESPONSE_Q_DOWN;
+       }
+       return rc;
+@@ -2918,7 +2801,6 @@ handle_state_change:
+  */
+ static long ibmvscsis_create_command_q(struct scsi_info *vscsi, int num_cmds)
+ {
+-      long rc = 0;
+       int pages;
+       struct vio_dev *vdev = vscsi->dma_dev;
+@@ -2942,22 +2824,7 @@ static long ibmvscsis_create_command_q(s
+               return -ENOMEM;
+       }
+-      rc =  h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, PAGE_SIZE);
+-      if (rc) {
+-              if (rc == H_CLOSED) {
+-                      vscsi->state = WAIT_ENABLED;
+-                      rc = 0;
+-              } else {
+-                      dma_unmap_single(&vdev->dev, vscsi->cmd_q.crq_token,
+-                                       PAGE_SIZE, DMA_BIDIRECTIONAL);
+-                      free_page((unsigned long)vscsi->cmd_q.base_addr);
+-                      rc = -ENODEV;
+-              }
+-      } else {
+-              vscsi->state = WAIT_ENABLED;
+-      }
+-
+-      return rc;
++      return 0;
+ }
+ /**
+@@ -3491,31 +3358,12 @@ static int ibmvscsis_probe(struct vio_de
+               goto destroy_WQ;
+       }
+-      spin_lock_bh(&vscsi->intr_lock);
+-      vio_enable_interrupts(vdev);
+-      if (rc) {
+-              dev_err(&vscsi->dev, "enabling interrupts failed, rc %d\n", rc);
+-              rc = -ENODEV;
+-              spin_unlock_bh(&vscsi->intr_lock);
+-              goto free_irq;
+-      }
+-
+-      if (ibmvscsis_check_q(vscsi)) {
+-              rc = ERROR;
+-              dev_err(&vscsi->dev, "probe: check_q failed, rc %d\n", rc);
+-              spin_unlock_bh(&vscsi->intr_lock);
+-              goto disable_interrupt;
+-      }
+-      spin_unlock_bh(&vscsi->intr_lock);
++      vscsi->state = WAIT_ENABLED;
+       dev_set_drvdata(&vdev->dev, vscsi);
+       return 0;
+-disable_interrupt:
+-      vio_disable_interrupts(vdev);
+-free_irq:
+-      free_irq(vdev->irq, vscsi);
+ destroy_WQ:
+       destroy_workqueue(vscsi->work_q);
+ unmap_buf:
+@@ -3909,18 +3757,22 @@ static ssize_t ibmvscsis_tpg_enable_stor
+       }
+       if (tmp) {
+-              tport->enabled = true;
+               spin_lock_bh(&vscsi->intr_lock);
++              tport->enabled = true;
+               lrc = ibmvscsis_enable_change_state(vscsi);
+               if (lrc)
+                       pr_err("enable_change_state failed, rc %ld state %d\n",
+                              lrc, vscsi->state);
+               spin_unlock_bh(&vscsi->intr_lock);
+       } else {
++              spin_lock_bh(&vscsi->intr_lock);
+               tport->enabled = false;
++              /* This simulates the server going down */
++              ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
++              spin_unlock_bh(&vscsi->intr_lock);
+       }
+-      pr_debug("tpg_enable_store, state %d\n", vscsi->state);
++      pr_debug("tpg_enable_store, tmp %ld, state %d\n", tmp, vscsi->state);
+       return count;
+ }
+--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+@@ -204,8 +204,6 @@ struct scsi_info {
+       struct list_head waiting_rsp;
+ #define NO_QUEUE                    0x00
+ #define WAIT_ENABLED                0X01
+-      /* driver has received an initialize command */
+-#define PART_UP_WAIT_ENAB           0x02
+ #define WAIT_CONNECTION             0x04
+       /* have established a connection */
+ #define CONNECTED                   0x08
diff --git a/queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch b/queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch
new file mode 100644 (file)
index 0000000..36ba139
--- /dev/null
@@ -0,0 +1,108 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:32 +0000
+Subject: [PATCH v2 for-4.9 37/40] serial: 8250_pci: Detach low-level driver during PCI error recovery
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-37-alexander.levin@verizon.com>
+
+From: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
+
+[ Upstream commit f209fa03fc9d131b3108c2e4936181eabab87416 ]
+
+During a PCI error recovery, like the ones provoked by EEH in the ppc64
+platform, all IO to the device must be blocked while the recovery is
+completed.  Current 8250_pci implementation only suspends the port
+instead of detaching it, which doesn't prevent incoming accesses like
+TIOCMGET and TIOCMSET calls from reaching the device.  Those end up
+racing with the EEH recovery, crashing it.  Similar races were also
+observed when opening the device and when shutting it down during
+recovery.
+
+This patch implements a more robust IO blockage for the 8250_pci
+recovery by unregistering the port at the beginning of the procedure and
+re-adding it afterwards.  Since the port is detached from the uart
+layer, we can be sure that no request will make through to the device
+during recovery.  This is similar to the solution used by the JSM serial
+driver.
+
+I thank Peter Hurley <peter@hurleysoftware.com> for valuable input on
+this one over one year ago.
+
+Signed-off-by: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/8250/8250_pci.c |   23 +++++++++++++++++++----
+ 1 file changed, 19 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/serial/8250/8250_pci.c
++++ b/drivers/tty/serial/8250/8250_pci.c
+@@ -52,6 +52,7 @@ struct serial_private {
+       struct pci_dev          *dev;
+       unsigned int            nr;
+       struct pci_serial_quirk *quirk;
++      const struct pciserial_board *board;
+       int                     line[0];
+ };
+@@ -3871,6 +3872,7 @@ pciserial_init_ports(struct pci_dev *dev
+               }
+       }
+       priv->nr = i;
++      priv->board = board;
+       return priv;
+ err_deinit:
+@@ -3881,7 +3883,7 @@ err_out:
+ }
+ EXPORT_SYMBOL_GPL(pciserial_init_ports);
+-void pciserial_remove_ports(struct serial_private *priv)
++void pciserial_detach_ports(struct serial_private *priv)
+ {
+       struct pci_serial_quirk *quirk;
+       int i;
+@@ -3895,7 +3897,11 @@ void pciserial_remove_ports(struct seria
+       quirk = find_quirk(priv->dev);
+       if (quirk->exit)
+               quirk->exit(priv->dev);
++}
++void pciserial_remove_ports(struct serial_private *priv)
++{
++      pciserial_detach_ports(priv);
+       kfree(priv);
+ }
+ EXPORT_SYMBOL_GPL(pciserial_remove_ports);
+@@ -5590,7 +5596,7 @@ static pci_ers_result_t serial8250_io_er
+               return PCI_ERS_RESULT_DISCONNECT;
+       if (priv)
+-              pciserial_suspend_ports(priv);
++              pciserial_detach_ports(priv);
+       pci_disable_device(dev);
+@@ -5615,9 +5621,18 @@ static pci_ers_result_t serial8250_io_sl
+ static void serial8250_io_resume(struct pci_dev *dev)
+ {
+       struct serial_private *priv = pci_get_drvdata(dev);
++      const struct pciserial_board *board;
+-      if (priv)
+-              pciserial_resume_ports(priv);
++      if (!priv)
++              return;
++
++      board = priv->board;
++      kfree(priv);
++      priv = pciserial_init_ports(dev, board);
++
++      if (!IS_ERR(priv)) {
++              pci_set_drvdata(dev, priv);
++      }
+ }
+ static const struct pci_error_handlers serial8250_err_handler = {
index 599fe307cc1380002dbd74a17e84de9a6dc5134e..847391f3822cbd68c4924442d2cb84976b406f7e 100644 (file)
@@ -40,3 +40,42 @@ bpf-fix-state-equivalence.patch
 bpf-fix-regression-on-verifier-pruning-wrt-map-lookups.patch
 bpf-fix-mark_reg_unknown_value-for-spilled-regs-on-map-value-marking.patch
 dmaengine-iota-ioat_alloc_chan_resources-should-not-perform-sleeping-allocations.patch
+xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch
+igb-workaround-for-igb-i210-firmware-issue.patch
+igb-add-i211-to-i210-phy-workaround.patch
+scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch
+scsi-ibmvscsis-return-correct-partition-name-to-client.patch
+scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch
+scsi-ibmvscsis-rearrange-functions-for-future-patches.patch
+scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch
+scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch
+x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch
+pci-separate-vf-bar-updates-from-standard-bar-updates.patch
+pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch
+pci-add-comments-about-rom-bar-updating.patch
+pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch
+pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch
+pci-update-bars-using-property-bits-appropriate-for-type.patch
+pci-ignore-bar-updates-on-virtual-functions.patch
+pci-do-any-vf-bar-updates-before-enabling-the-bars.patch
+ibmveth-calculate-gso_segs-for-large-packets.patch
+drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch
+vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch
+powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch
+powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch
+vfio-spapr-reference-mm-in-tce_container.patch
+powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch
+vfio-spapr-add-a-helper-to-create-default-dma-window.patch
+vfio-spapr-postpone-default-window-creation.patch
+drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch
+drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch
+drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch
+block-allow-write_same-commands-with-the-sg_io-ioctl.patch
+s390-zcrypt-introduce-cex6-toleration.patch
+uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch
+slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch
+acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch
+acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch
+serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch
+usb-gadget-udc-atmel-remove-memory-leak.patch
+powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch
diff --git a/queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch b/queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch
new file mode 100644 (file)
index 0000000..5d14466
--- /dev/null
@@ -0,0 +1,179 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:31 +0000
+Subject: [PATCH v2 for-4.9 34/40] slub: move synchronize_sched out of slab_mutex on shrink
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-34-alexander.levin@verizon.com>
+
+From: Vladimir Davydov <vdavydov.dev@gmail.com>
+
+[ Upstream commit 89e364db71fb5e7fc8d93228152abfa67daf35fa ]
+
+synchronize_sched() is a heavy operation and calling it per each cache
+owned by a memory cgroup being destroyed may take quite some time.  What
+is worse, it's currently called under the slab_mutex, stalling all works
+doing cache creation/destruction.
+
+Actually, there isn't much point in calling synchronize_sched() for each
+cache - it's enough to call it just once - after setting cpu_partial for
+all caches and before shrinking them.  This way, we can also move it out
+of the slab_mutex, which we have to hold for iterating over the slab
+cache list.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=172991
+Link: http://lkml.kernel.org/r/0a10d71ecae3db00fb4421bcd3f82bcc911f4be4.1475329751.git.vdavydov.dev@gmail.com
+Signed-off-by: Vladimir Davydov <vdavydov.dev@gmail.com>
+Reported-by: Doug Smythies <dsmythies@telus.net>
+Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
+Cc: Christoph Lameter <cl@linux.com>
+Cc: David Rientjes <rientjes@google.com>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Michal Hocko <mhocko@kernel.org>
+Cc: Pekka Enberg <penberg@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/slab.c        |    4 ++--
+ mm/slab.h        |    2 +-
+ mm/slab_common.c |   27 +++++++++++++++++++++++++--
+ mm/slob.c        |    2 +-
+ mm/slub.c        |   19 ++-----------------
+ 5 files changed, 31 insertions(+), 23 deletions(-)
+
+--- a/mm/slab.c
++++ b/mm/slab.c
+@@ -2332,7 +2332,7 @@ out:
+       return nr_freed;
+ }
+-int __kmem_cache_shrink(struct kmem_cache *cachep, bool deactivate)
++int __kmem_cache_shrink(struct kmem_cache *cachep)
+ {
+       int ret = 0;
+       int node;
+@@ -2352,7 +2352,7 @@ int __kmem_cache_shrink(struct kmem_cach
+ int __kmem_cache_shutdown(struct kmem_cache *cachep)
+ {
+-      return __kmem_cache_shrink(cachep, false);
++      return __kmem_cache_shrink(cachep);
+ }
+ void __kmem_cache_release(struct kmem_cache *cachep)
+--- a/mm/slab.h
++++ b/mm/slab.h
+@@ -146,7 +146,7 @@ static inline unsigned long kmem_cache_f
+ int __kmem_cache_shutdown(struct kmem_cache *);
+ void __kmem_cache_release(struct kmem_cache *);
+-int __kmem_cache_shrink(struct kmem_cache *, bool);
++int __kmem_cache_shrink(struct kmem_cache *);
+ void slab_kmem_cache_release(struct kmem_cache *);
+ struct seq_file;
+--- a/mm/slab_common.c
++++ b/mm/slab_common.c
+@@ -573,6 +573,29 @@ void memcg_deactivate_kmem_caches(struct
+       get_online_cpus();
+       get_online_mems();
++#ifdef CONFIG_SLUB
++      /*
++       * In case of SLUB, we need to disable empty slab caching to
++       * avoid pinning the offline memory cgroup by freeable kmem
++       * pages charged to it. SLAB doesn't need this, as it
++       * periodically purges unused slabs.
++       */
++      mutex_lock(&slab_mutex);
++      list_for_each_entry(s, &slab_caches, list) {
++              c = is_root_cache(s) ? cache_from_memcg_idx(s, idx) : NULL;
++              if (c) {
++                      c->cpu_partial = 0;
++                      c->min_partial = 0;
++              }
++      }
++      mutex_unlock(&slab_mutex);
++      /*
++       * kmem_cache->cpu_partial is checked locklessly (see
++       * put_cpu_partial()). Make sure the change is visible.
++       */
++      synchronize_sched();
++#endif
++
+       mutex_lock(&slab_mutex);
+       list_for_each_entry(s, &slab_caches, list) {
+               if (!is_root_cache(s))
+@@ -584,7 +607,7 @@ void memcg_deactivate_kmem_caches(struct
+               if (!c)
+                       continue;
+-              __kmem_cache_shrink(c, true);
++              __kmem_cache_shrink(c);
+               arr->entries[idx] = NULL;
+       }
+       mutex_unlock(&slab_mutex);
+@@ -755,7 +778,7 @@ int kmem_cache_shrink(struct kmem_cache
+       get_online_cpus();
+       get_online_mems();
+       kasan_cache_shrink(cachep);
+-      ret = __kmem_cache_shrink(cachep, false);
++      ret = __kmem_cache_shrink(cachep);
+       put_online_mems();
+       put_online_cpus();
+       return ret;
+--- a/mm/slob.c
++++ b/mm/slob.c
+@@ -634,7 +634,7 @@ void __kmem_cache_release(struct kmem_ca
+ {
+ }
+-int __kmem_cache_shrink(struct kmem_cache *d, bool deactivate)
++int __kmem_cache_shrink(struct kmem_cache *d)
+ {
+       return 0;
+ }
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -3887,7 +3887,7 @@ EXPORT_SYMBOL(kfree);
+  * being allocated from last increasing the chance that the last objects
+  * are freed in them.
+  */
+-int __kmem_cache_shrink(struct kmem_cache *s, bool deactivate)
++int __kmem_cache_shrink(struct kmem_cache *s)
+ {
+       int node;
+       int i;
+@@ -3899,21 +3899,6 @@ int __kmem_cache_shrink(struct kmem_cach
+       unsigned long flags;
+       int ret = 0;
+-      if (deactivate) {
+-              /*
+-               * Disable empty slabs caching. Used to avoid pinning offline
+-               * memory cgroups by kmem pages that can be freed.
+-               */
+-              s->cpu_partial = 0;
+-              s->min_partial = 0;
+-
+-              /*
+-               * s->cpu_partial is checked locklessly (see put_cpu_partial),
+-               * so we have to make sure the change is visible.
+-               */
+-              synchronize_sched();
+-      }
+-
+       flush_all(s);
+       for_each_kmem_cache_node(s, node, n) {
+               INIT_LIST_HEAD(&discard);
+@@ -3970,7 +3955,7 @@ static int slab_mem_going_offline_callba
+       mutex_lock(&slab_mutex);
+       list_for_each_entry(s, &slab_caches, list)
+-              __kmem_cache_shrink(s, false);
++              __kmem_cache_shrink(s);
+       mutex_unlock(&slab_mutex);
+       return 0;
diff --git a/queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch b/queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch
new file mode 100644 (file)
index 0000000..05ef20c
--- /dev/null
@@ -0,0 +1,48 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:33 +0000
+Subject: [PATCH v2 for-4.9 39/40] usb: gadget: udc: atmel: remove memory leak
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-39-alexander.levin@verizon.com>
+
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+
+[ Upstream commit 32856eea7bf75dfb99b955ada6e147f553a11366 ]
+
+Commit bbe097f092b0 ("usb: gadget: udc: atmel: fix endpoint name")
+introduced a memory leak when unbinding the driver. The endpoint names
+would not be freed. Solve that by including the name as a string in struct
+usba_ep so it is freed when the endpoint is.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/atmel_usba_udc.c |    3 ++-
+ drivers/usb/gadget/udc/atmel_usba_udc.h |    1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
++++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
+@@ -1978,7 +1978,8 @@ static struct usba_ep * atmel_udc_of_ini
+                       dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
+                       goto err;
+               }
+-              ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index);
++              sprintf(ep->name, "ep%d", ep->index);
++              ep->ep.name = ep->name;
+               ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+               ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
++++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
+@@ -280,6 +280,7 @@ struct usba_ep {
+       void __iomem                            *ep_regs;
+       void __iomem                            *dma_regs;
+       void __iomem                            *fifo;
++      char                                    name[8];
+       struct usb_ep                           ep;
+       struct usba_udc                         *udc;
diff --git a/queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch b/queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch
new file mode 100644 (file)
index 0000000..f2ef85e
--- /dev/null
@@ -0,0 +1,174 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:31 +0000
+Subject: [PATCH v2 for-4.9 33/40] [media] uvcvideo: uvc_scan_fallback() for webcams with broken chain
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-33-alexander.levin@verizon.com>
+
+From: Henrik Ingo <henrik.ingo@avoinelama.fi>
+
+[ Upstream commit e950267ab802c8558f1100eafd4087fd039ad634 ]
+
+Some devices have invalid baSourceID references, causing uvc_scan_chain()
+to fail, but if we just take the entities we can find and put them
+together in the most sensible chain we can think of, turns out they do
+work anyway. Note: This heuristic assumes there is a single chain.
+
+At the time of writing, devices known to have such a broken chain are
+  - Acer Integrated Camera (5986:055a)
+  - Realtek rtl157a7 (0bda:57a7)
+
+Signed-off-by: Henrik Ingo <henrik.ingo@avoinelama.fi>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/usb/uvc/uvc_driver.c |  118 +++++++++++++++++++++++++++++++++++--
+ 1 file changed, 112 insertions(+), 6 deletions(-)
+
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -1595,6 +1595,114 @@ static const char *uvc_print_chain(struc
+       return buffer;
+ }
++static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev)
++{
++      struct uvc_video_chain *chain;
++
++      chain = kzalloc(sizeof(*chain), GFP_KERNEL);
++      if (chain == NULL)
++              return NULL;
++
++      INIT_LIST_HEAD(&chain->entities);
++      mutex_init(&chain->ctrl_mutex);
++      chain->dev = dev;
++      v4l2_prio_init(&chain->prio);
++
++      return chain;
++}
++
++/*
++ * Fallback heuristic for devices that don't connect units and terminals in a
++ * valid chain.
++ *
++ * Some devices have invalid baSourceID references, causing uvc_scan_chain()
++ * to fail, but if we just take the entities we can find and put them together
++ * in the most sensible chain we can think of, turns out they do work anyway.
++ * Note: This heuristic assumes there is a single chain.
++ *
++ * At the time of writing, devices known to have such a broken chain are
++ *  - Acer Integrated Camera (5986:055a)
++ *  - Realtek rtl157a7 (0bda:57a7)
++ */
++static int uvc_scan_fallback(struct uvc_device *dev)
++{
++      struct uvc_video_chain *chain;
++      struct uvc_entity *iterm = NULL;
++      struct uvc_entity *oterm = NULL;
++      struct uvc_entity *entity;
++      struct uvc_entity *prev;
++
++      /*
++       * Start by locating the input and output terminals. We only support
++       * devices with exactly one of each for now.
++       */
++      list_for_each_entry(entity, &dev->entities, list) {
++              if (UVC_ENTITY_IS_ITERM(entity)) {
++                      if (iterm)
++                              return -EINVAL;
++                      iterm = entity;
++              }
++
++              if (UVC_ENTITY_IS_OTERM(entity)) {
++                      if (oterm)
++                              return -EINVAL;
++                      oterm = entity;
++              }
++      }
++
++      if (iterm == NULL || oterm == NULL)
++              return -EINVAL;
++
++      /* Allocate the chain and fill it. */
++      chain = uvc_alloc_chain(dev);
++      if (chain == NULL)
++              return -ENOMEM;
++
++      if (uvc_scan_chain_entity(chain, oterm) < 0)
++              goto error;
++
++      prev = oterm;
++
++      /*
++       * Add all Processing and Extension Units with two pads. The order
++       * doesn't matter much, use reverse list traversal to connect units in
++       * UVC descriptor order as we build the chain from output to input. This
++       * leads to units appearing in the order meant by the manufacturer for
++       * the cameras known to require this heuristic.
++       */
++      list_for_each_entry_reverse(entity, &dev->entities, list) {
++              if (entity->type != UVC_VC_PROCESSING_UNIT &&
++                  entity->type != UVC_VC_EXTENSION_UNIT)
++                      continue;
++
++              if (entity->num_pads != 2)
++                      continue;
++
++              if (uvc_scan_chain_entity(chain, entity) < 0)
++                      goto error;
++
++              prev->baSourceID[0] = entity->id;
++              prev = entity;
++      }
++
++      if (uvc_scan_chain_entity(chain, iterm) < 0)
++              goto error;
++
++      prev->baSourceID[0] = iterm->id;
++
++      list_add_tail(&chain->list, &dev->chains);
++
++      uvc_trace(UVC_TRACE_PROBE,
++                "Found a video chain by fallback heuristic (%s).\n",
++                uvc_print_chain(chain));
++
++      return 0;
++
++error:
++      kfree(chain);
++      return -EINVAL;
++}
++
+ /*
+  * Scan the device for video chains and register video devices.
+  *
+@@ -1617,15 +1725,10 @@ static int uvc_scan_device(struct uvc_de
+               if (term->chain.next || term->chain.prev)
+                       continue;
+-              chain = kzalloc(sizeof(*chain), GFP_KERNEL);
++              chain = uvc_alloc_chain(dev);
+               if (chain == NULL)
+                       return -ENOMEM;
+-              INIT_LIST_HEAD(&chain->entities);
+-              mutex_init(&chain->ctrl_mutex);
+-              chain->dev = dev;
+-              v4l2_prio_init(&chain->prio);
+-
+               term->flags |= UVC_ENTITY_FLAG_DEFAULT;
+               if (uvc_scan_chain(chain, term) < 0) {
+@@ -1639,6 +1742,9 @@ static int uvc_scan_device(struct uvc_de
+               list_add_tail(&chain->list, &dev->chains);
+       }
++      if (list_empty(&dev->chains))
++              uvc_scan_fallback(dev);
++
+       if (list_empty(&dev->chains)) {
+               uvc_printk(KERN_INFO, "No valid video chain found.\n");
+               return -1;
diff --git a/queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch b/queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch
new file mode 100644 (file)
index 0000000..83901e3
--- /dev/null
@@ -0,0 +1,167 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:28 +0000
+Subject: [PATCH v2 for-4.9 26/40] vfio/spapr: Add a helper to create default DMA window
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-26-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit 6f01cc692a16405235d5c34056455b182682123c ]
+
+There is already a helper to create a DMA window which does allocate
+a table and programs it to the IOMMU group. However
+tce_iommu_take_ownership_ddw() did not use it and did these 2 calls
+itself to simplify error path.
+
+Since we are going to delay the default window creation till
+the default window is accessed/removed or new window is added,
+we need a helper to create a default window from all these cases.
+
+This adds tce_iommu_create_default_window(). Since it relies on
+a VFIO container to have at least one IOMMU group (for future use),
+this changes tce_iommu_attach_group() to add a group to the container
+first and then call the new helper.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vfio/vfio_iommu_spapr_tce.c |   87 +++++++++++++++++-------------------
+ 1 file changed, 42 insertions(+), 45 deletions(-)
+
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -784,6 +784,29 @@ static long tce_iommu_remove_window(stru
+       return 0;
+ }
++static long tce_iommu_create_default_window(struct tce_container *container)
++{
++      long ret;
++      __u64 start_addr = 0;
++      struct tce_iommu_group *tcegrp;
++      struct iommu_table_group *table_group;
++
++      if (!tce_groups_attached(container))
++              return -ENODEV;
++
++      tcegrp = list_first_entry(&container->group_list,
++                      struct tce_iommu_group, next);
++      table_group = iommu_group_get_iommudata(tcegrp->grp);
++      if (!table_group)
++              return -ENODEV;
++
++      ret = tce_iommu_create_window(container, IOMMU_PAGE_SHIFT_4K,
++                      table_group->tce32_size, 1, &start_addr);
++      WARN_ON_ONCE(!ret && start_addr);
++
++      return ret;
++}
++
+ static long tce_iommu_ioctl(void *iommu_data,
+                                unsigned int cmd, unsigned long arg)
+ {
+@@ -1199,9 +1222,6 @@ static void tce_iommu_release_ownership_
+ static long tce_iommu_take_ownership_ddw(struct tce_container *container,
+               struct iommu_table_group *table_group)
+ {
+-      long i, ret = 0;
+-      struct iommu_table *tbl = NULL;
+-
+       if (!table_group->ops->create_table || !table_group->ops->set_window ||
+                       !table_group->ops->release_ownership) {
+               WARN_ON_ONCE(1);
+@@ -1210,47 +1230,7 @@ static long tce_iommu_take_ownership_ddw
+       table_group->ops->take_ownership(table_group);
+-      /*
+-       * If it the first group attached, check if there is
+-       * a default DMA window and create one if none as
+-       * the userspace expects it to exist.
+-       */
+-      if (!tce_groups_attached(container) && !container->tables[0]) {
+-              ret = tce_iommu_create_table(container,
+-                              table_group,
+-                              0, /* window number */
+-                              IOMMU_PAGE_SHIFT_4K,
+-                              table_group->tce32_size,
+-                              1, /* default levels */
+-                              &tbl);
+-              if (ret)
+-                      goto release_exit;
+-              else
+-                      container->tables[0] = tbl;
+-      }
+-
+-      /* Set all windows to the new group */
+-      for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
+-              tbl = container->tables[i];
+-
+-              if (!tbl)
+-                      continue;
+-
+-              /* Set the default window to a new group */
+-              ret = table_group->ops->set_window(table_group, i, tbl);
+-              if (ret)
+-                      goto release_exit;
+-      }
+-
+       return 0;
+-
+-release_exit:
+-      for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
+-              table_group->ops->unset_window(table_group, i);
+-
+-      table_group->ops->release_ownership(table_group);
+-
+-      return ret;
+ }
+ static int tce_iommu_attach_group(void *iommu_data,
+@@ -1260,6 +1240,7 @@ static int tce_iommu_attach_group(void *
+       struct tce_container *container = iommu_data;
+       struct iommu_table_group *table_group;
+       struct tce_iommu_group *tcegrp = NULL;
++      bool create_default_window = false;
+       mutex_lock(&container->lock);
+@@ -1302,14 +1283,30 @@ static int tce_iommu_attach_group(void *
+       }
+       if (!table_group->ops || !table_group->ops->take_ownership ||
+-                      !table_group->ops->release_ownership)
++                      !table_group->ops->release_ownership) {
+               ret = tce_iommu_take_ownership(container, table_group);
+-      else
++      } else {
+               ret = tce_iommu_take_ownership_ddw(container, table_group);
++              if (!tce_groups_attached(container) && !container->tables[0])
++                      create_default_window = true;
++      }
+       if (!ret) {
+               tcegrp->grp = iommu_group;
+               list_add(&tcegrp->next, &container->group_list);
++              /*
++               * If it the first group attached, check if there is
++               * a default DMA window and create one if none as
++               * the userspace expects it to exist.
++               */
++              if (create_default_window) {
++                      ret = tce_iommu_create_default_window(container);
++                      if (ret) {
++                              list_del(&tcegrp->next);
++                              tce_iommu_release_ownership_ddw(container,
++                                              table_group);
++                      }
++              }
+       }
+ unlock_exit:
diff --git a/queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch b/queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch
new file mode 100644 (file)
index 0000000..1d6c42a
--- /dev/null
@@ -0,0 +1,80 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:26 +0000
+Subject: [PATCH v2 for-4.9 21/40] vfio/spapr: Postpone allocation of userspace version of TCE table
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-21-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit 39701e56f5f16ea0cf8fc9e8472e645f8de91d23 ]
+
+The iommu_table struct manages a hardware TCE table and a vmalloc'd
+table with corresponding userspace addresses. Both are allocated when
+the default DMA window is created and this happens when the very first
+group is attached to a container.
+
+As we are going to allow the userspace to configure container in one
+memory context and pas container fd to another, we have to postpones
+such allocations till a container fd is passed to the destination
+user process so we would account locked memory limit against the actual
+container user constrainsts.
+
+This postpones the it_userspace array allocation till it is used first
+time for mapping. The unmapping patch already checks if the array is
+allocated.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vfio/vfio_iommu_spapr_tce.c |   20 +++++++-------------
+ 1 file changed, 7 insertions(+), 13 deletions(-)
+
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -509,6 +509,12 @@ static long tce_iommu_build_v2(struct tc
+       unsigned long hpa;
+       enum dma_data_direction dirtmp;
++      if (!tbl->it_userspace) {
++              ret = tce_iommu_userspace_view_alloc(tbl);
++              if (ret)
++                      return ret;
++      }
++
+       for (i = 0; i < pages; ++i) {
+               struct mm_iommu_table_group_mem_t *mem = NULL;
+               unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl,
+@@ -582,15 +588,6 @@ static long tce_iommu_create_table(struc
+       WARN_ON(!ret && !(*ptbl)->it_ops->free);
+       WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size));
+-      if (!ret && container->v2) {
+-              ret = tce_iommu_userspace_view_alloc(*ptbl);
+-              if (ret)
+-                      (*ptbl)->it_ops->free(*ptbl);
+-      }
+-
+-      if (ret)
+-              decrement_locked_vm(table_size >> PAGE_SHIFT);
+-
+       return ret;
+ }
+@@ -1062,10 +1059,7 @@ static int tce_iommu_take_ownership(stru
+               if (!tbl || !tbl->it_map)
+                       continue;
+-              rc = tce_iommu_userspace_view_alloc(tbl);
+-              if (!rc)
+-                      rc = iommu_take_ownership(tbl);
+-
++              rc = iommu_take_ownership(tbl);
+               if (rc) {
+                       for (j = 0; j < i; ++j)
+                               iommu_release_ownership(
diff --git a/queue-4.9/vfio-spapr-postpone-default-window-creation.patch b/queue-4.9/vfio-spapr-postpone-default-window-creation.patch
new file mode 100644 (file)
index 0000000..9cd8888
--- /dev/null
@@ -0,0 +1,150 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:29 +0000
+Subject: [PATCH v2 for-4.9 27/40] vfio/spapr: Postpone default window creation
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-27-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit d9c728949ddc9de5734bf3b12ea906ca8a77f2a0 ]
+
+We are going to allow the userspace to configure container in
+one memory context and pass container fd to another so
+we are postponing memory allocations accounted against
+the locked memory limit. One of previous patches took care of
+it_userspace.
+
+At the moment we create the default DMA window when the first group is
+attached to a container; this is done for the userspace which is not
+DDW-aware but familiar with the SPAPR TCE IOMMU v2 in the part of memory
+pre-registration - such client expects the default DMA window to exist.
+
+This postpones the default DMA window allocation till one of
+the folliwing happens:
+1. first map/unmap request arrives;
+2. new window is requested;
+This adds noop for the case when the userspace requested removal
+of the default window which has not been created yet.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vfio/vfio_iommu_spapr_tce.c |   40 ++++++++++++++++++++++--------------
+ 1 file changed, 25 insertions(+), 15 deletions(-)
+
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -106,6 +106,7 @@ struct tce_container {
+       struct mutex lock;
+       bool enabled;
+       bool v2;
++      bool def_window_pending;
+       unsigned long locked_pages;
+       struct mm_struct *mm;
+       struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES];
+@@ -791,6 +792,9 @@ static long tce_iommu_create_default_win
+       struct tce_iommu_group *tcegrp;
+       struct iommu_table_group *table_group;
++      if (!container->def_window_pending)
++              return 0;
++
+       if (!tce_groups_attached(container))
+               return -ENODEV;
+@@ -804,6 +808,9 @@ static long tce_iommu_create_default_win
+                       table_group->tce32_size, 1, &start_addr);
+       WARN_ON_ONCE(!ret && start_addr);
++      if (!ret)
++              container->def_window_pending = false;
++
+       return ret;
+ }
+@@ -907,6 +914,10 @@ static long tce_iommu_ioctl(void *iommu_
+                               VFIO_DMA_MAP_FLAG_WRITE))
+                       return -EINVAL;
++              ret = tce_iommu_create_default_window(container);
++              if (ret)
++                      return ret;
++
+               num = tce_iommu_find_table(container, param.iova, &tbl);
+               if (num < 0)
+                       return -ENXIO;
+@@ -970,6 +981,10 @@ static long tce_iommu_ioctl(void *iommu_
+               if (param.flags)
+                       return -EINVAL;
++              ret = tce_iommu_create_default_window(container);
++              if (ret)
++                      return ret;
++
+               num = tce_iommu_find_table(container, param.iova, &tbl);
+               if (num < 0)
+                       return -ENXIO;
+@@ -1107,6 +1122,10 @@ static long tce_iommu_ioctl(void *iommu_
+               mutex_lock(&container->lock);
++              ret = tce_iommu_create_default_window(container);
++              if (ret)
++                      return ret;
++
+               ret = tce_iommu_create_window(container, create.page_shift,
+                               create.window_size, create.levels,
+                               &create.start_addr);
+@@ -1143,6 +1162,11 @@ static long tce_iommu_ioctl(void *iommu_
+               if (remove.flags)
+                       return -EINVAL;
++              if (container->def_window_pending && !remove.start_addr) {
++                      container->def_window_pending = false;
++                      return 0;
++              }
++
+               mutex_lock(&container->lock);
+               ret = tce_iommu_remove_window(container, remove.start_addr);
+@@ -1240,7 +1264,6 @@ static int tce_iommu_attach_group(void *
+       struct tce_container *container = iommu_data;
+       struct iommu_table_group *table_group;
+       struct tce_iommu_group *tcegrp = NULL;
+-      bool create_default_window = false;
+       mutex_lock(&container->lock);
+@@ -1288,25 +1311,12 @@ static int tce_iommu_attach_group(void *
+       } else {
+               ret = tce_iommu_take_ownership_ddw(container, table_group);
+               if (!tce_groups_attached(container) && !container->tables[0])
+-                      create_default_window = true;
++                      container->def_window_pending = true;
+       }
+       if (!ret) {
+               tcegrp->grp = iommu_group;
+               list_add(&tcegrp->next, &container->group_list);
+-              /*
+-               * If it the first group attached, check if there is
+-               * a default DMA window and create one if none as
+-               * the userspace expects it to exist.
+-               */
+-              if (create_default_window) {
+-                      ret = tce_iommu_create_default_window(container);
+-                      if (ret) {
+-                              list_del(&tcegrp->next);
+-                              tce_iommu_release_ownership_ddw(container,
+-                                              table_group);
+-                      }
+-              }
+       }
+ unlock_exit:
diff --git a/queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch b/queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch
new file mode 100644 (file)
index 0000000..39feb9b
--- /dev/null
@@ -0,0 +1,485 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:27 +0000
+Subject: [PATCH v2 for-4.9 24/40] vfio/spapr: Reference mm in tce_container
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-24-alexander.levin@verizon.com>
+
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+
+[ Upstream commit bc82d122ae4a0e9f971f13403995898fcfa0c09e ]
+
+In some situations the userspace memory context may live longer than
+the userspace process itself so if we need to do proper memory context
+cleanup, we better have tce_container take a reference to mm_struct and
+use it later when the process is gone (@current or @current->mm is NULL).
+
+This references mm and stores the pointer in the container; this is done
+in a new helper - tce_iommu_mm_set() - when one of the following happens:
+- a container is enabled (IOMMU v1);
+- a first attempt to pre-register memory is made (IOMMU v2);
+- a DMA window is created (IOMMU v2).
+The @mm stays referenced till the container is destroyed.
+
+This replaces current->mm with container->mm everywhere except debug
+prints.
+
+This adds a check that current->mm is the same as the one stored in
+the container to prevent userspace from making changes to a memory
+context of other processes.
+
+DMA map/unmap ioctls() do not check for @mm as they already check
+for @enabled which is set after tce_iommu_mm_set() is called.
+
+This does not reference a task as multiple threads within the same mm
+are allowed to ioctl() to vfio and supposedly they will have same limits
+and capabilities and if they do not, we'll just fail with no harm made.
+
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Acked-by: Alex Williamson <alex.williamson@redhat.com>
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/vfio/vfio_iommu_spapr_tce.c |  160 ++++++++++++++++++++++--------------
+ 1 file changed, 100 insertions(+), 60 deletions(-)
+
+--- a/drivers/vfio/vfio_iommu_spapr_tce.c
++++ b/drivers/vfio/vfio_iommu_spapr_tce.c
+@@ -31,49 +31,49 @@
+ static void tce_iommu_detach_group(void *iommu_data,
+               struct iommu_group *iommu_group);
+-static long try_increment_locked_vm(long npages)
++static long try_increment_locked_vm(struct mm_struct *mm, long npages)
+ {
+       long ret = 0, locked, lock_limit;
+-      if (!current || !current->mm)
+-              return -ESRCH; /* process exited */
++      if (WARN_ON_ONCE(!mm))
++              return -EPERM;
+       if (!npages)
+               return 0;
+-      down_write(&current->mm->mmap_sem);
+-      locked = current->mm->locked_vm + npages;
++      down_write(&mm->mmap_sem);
++      locked = mm->locked_vm + npages;
+       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+               ret = -ENOMEM;
+       else
+-              current->mm->locked_vm += npages;
++              mm->locked_vm += npages;
+       pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
+                       npages << PAGE_SHIFT,
+-                      current->mm->locked_vm << PAGE_SHIFT,
++                      mm->locked_vm << PAGE_SHIFT,
+                       rlimit(RLIMIT_MEMLOCK),
+                       ret ? " - exceeded" : "");
+-      up_write(&current->mm->mmap_sem);
++      up_write(&mm->mmap_sem);
+       return ret;
+ }
+-static void decrement_locked_vm(long npages)
++static void decrement_locked_vm(struct mm_struct *mm, long npages)
+ {
+-      if (!current || !current->mm || !npages)
+-              return; /* process exited */
++      if (!mm || !npages)
++              return;
+-      down_write(&current->mm->mmap_sem);
+-      if (WARN_ON_ONCE(npages > current->mm->locked_vm))
+-              npages = current->mm->locked_vm;
+-      current->mm->locked_vm -= npages;
++      down_write(&mm->mmap_sem);
++      if (WARN_ON_ONCE(npages > mm->locked_vm))
++              npages = mm->locked_vm;
++      mm->locked_vm -= npages;
+       pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid,
+                       npages << PAGE_SHIFT,
+-                      current->mm->locked_vm << PAGE_SHIFT,
++                      mm->locked_vm << PAGE_SHIFT,
+                       rlimit(RLIMIT_MEMLOCK));
+-      up_write(&current->mm->mmap_sem);
++      up_write(&mm->mmap_sem);
+ }
+ /*
+@@ -98,26 +98,38 @@ struct tce_container {
+       bool enabled;
+       bool v2;
+       unsigned long locked_pages;
++      struct mm_struct *mm;
+       struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES];
+       struct list_head group_list;
+ };
++static long tce_iommu_mm_set(struct tce_container *container)
++{
++      if (container->mm) {
++              if (container->mm == current->mm)
++                      return 0;
++              return -EPERM;
++      }
++      BUG_ON(!current->mm);
++      container->mm = current->mm;
++      atomic_inc(&container->mm->mm_count);
++
++      return 0;
++}
++
+ static long tce_iommu_unregister_pages(struct tce_container *container,
+               __u64 vaddr, __u64 size)
+ {
+       struct mm_iommu_table_group_mem_t *mem;
+-      if (!current || !current->mm)
+-              return -ESRCH; /* process exited */
+-
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK))
+               return -EINVAL;
+-      mem = mm_iommu_find(current->mm, vaddr, size >> PAGE_SHIFT);
++      mem = mm_iommu_find(container->mm, vaddr, size >> PAGE_SHIFT);
+       if (!mem)
+               return -ENOENT;
+-      return mm_iommu_put(current->mm, mem);
++      return mm_iommu_put(container->mm, mem);
+ }
+ static long tce_iommu_register_pages(struct tce_container *container,
+@@ -127,14 +139,11 @@ static long tce_iommu_register_pages(str
+       struct mm_iommu_table_group_mem_t *mem = NULL;
+       unsigned long entries = size >> PAGE_SHIFT;
+-      if (!current || !current->mm)
+-              return -ESRCH; /* process exited */
+-
+       if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) ||
+                       ((vaddr + size) < vaddr))
+               return -EINVAL;
+-      ret = mm_iommu_get(current->mm, vaddr, entries, &mem);
++      ret = mm_iommu_get(container->mm, vaddr, entries, &mem);
+       if (ret)
+               return ret;
+@@ -143,7 +152,8 @@ static long tce_iommu_register_pages(str
+       return 0;
+ }
+-static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl)
++static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl,
++              struct mm_struct *mm)
+ {
+       unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) *
+                       tbl->it_size, PAGE_SIZE);
+@@ -152,13 +162,13 @@ static long tce_iommu_userspace_view_all
+       BUG_ON(tbl->it_userspace);
+-      ret = try_increment_locked_vm(cb >> PAGE_SHIFT);
++      ret = try_increment_locked_vm(mm, cb >> PAGE_SHIFT);
+       if (ret)
+               return ret;
+       uas = vzalloc(cb);
+       if (!uas) {
+-              decrement_locked_vm(cb >> PAGE_SHIFT);
++              decrement_locked_vm(mm, cb >> PAGE_SHIFT);
+               return -ENOMEM;
+       }
+       tbl->it_userspace = uas;
+@@ -166,7 +176,8 @@ static long tce_iommu_userspace_view_all
+       return 0;
+ }
+-static void tce_iommu_userspace_view_free(struct iommu_table *tbl)
++static void tce_iommu_userspace_view_free(struct iommu_table *tbl,
++              struct mm_struct *mm)
+ {
+       unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) *
+                       tbl->it_size, PAGE_SIZE);
+@@ -176,7 +187,7 @@ static void tce_iommu_userspace_view_fre
+       vfree(tbl->it_userspace);
+       tbl->it_userspace = NULL;
+-      decrement_locked_vm(cb >> PAGE_SHIFT);
++      decrement_locked_vm(mm, cb >> PAGE_SHIFT);
+ }
+ static bool tce_page_is_contained(struct page *page, unsigned page_shift)
+@@ -236,9 +247,6 @@ static int tce_iommu_enable(struct tce_c
+       struct iommu_table_group *table_group;
+       struct tce_iommu_group *tcegrp;
+-      if (!current->mm)
+-              return -ESRCH; /* process exited */
+-
+       if (container->enabled)
+               return -EBUSY;
+@@ -283,8 +291,12 @@ static int tce_iommu_enable(struct tce_c
+       if (!table_group->tce32_size)
+               return -EPERM;
++      ret = tce_iommu_mm_set(container);
++      if (ret)
++              return ret;
++
+       locked = table_group->tce32_size >> PAGE_SHIFT;
+-      ret = try_increment_locked_vm(locked);
++      ret = try_increment_locked_vm(container->mm, locked);
+       if (ret)
+               return ret;
+@@ -302,10 +314,8 @@ static void tce_iommu_disable(struct tce
+       container->enabled = false;
+-      if (!current->mm)
+-              return;
+-
+-      decrement_locked_vm(container->locked_pages);
++      BUG_ON(!container->mm);
++      decrement_locked_vm(container->mm, container->locked_pages);
+ }
+ static void *tce_iommu_open(unsigned long arg)
+@@ -332,7 +342,8 @@ static void *tce_iommu_open(unsigned lon
+ static int tce_iommu_clear(struct tce_container *container,
+               struct iommu_table *tbl,
+               unsigned long entry, unsigned long pages);
+-static void tce_iommu_free_table(struct iommu_table *tbl);
++static void tce_iommu_free_table(struct tce_container *container,
++              struct iommu_table *tbl);
+ static void tce_iommu_release(void *iommu_data)
+ {
+@@ -357,10 +368,12 @@ static void tce_iommu_release(void *iomm
+                       continue;
+               tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
+-              tce_iommu_free_table(tbl);
++              tce_iommu_free_table(container, tbl);
+       }
+       tce_iommu_disable(container);
++      if (container->mm)
++              mmdrop(container->mm);
+       mutex_destroy(&container->lock);
+       kfree(container);
+@@ -375,13 +388,14 @@ static void tce_iommu_unuse_page(struct
+       put_page(page);
+ }
+-static int tce_iommu_prereg_ua_to_hpa(unsigned long tce, unsigned long size,
++static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container,
++              unsigned long tce, unsigned long size,
+               unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem)
+ {
+       long ret = 0;
+       struct mm_iommu_table_group_mem_t *mem;
+-      mem = mm_iommu_lookup(current->mm, tce, size);
++      mem = mm_iommu_lookup(container->mm, tce, size);
+       if (!mem)
+               return -EINVAL;
+@@ -394,18 +408,18 @@ static int tce_iommu_prereg_ua_to_hpa(un
+       return 0;
+ }
+-static void tce_iommu_unuse_page_v2(struct iommu_table *tbl,
+-              unsigned long entry)
++static void tce_iommu_unuse_page_v2(struct tce_container *container,
++              struct iommu_table *tbl, unsigned long entry)
+ {
+       struct mm_iommu_table_group_mem_t *mem = NULL;
+       int ret;
+       unsigned long hpa = 0;
+       unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
+-      if (!pua || !current || !current->mm)
++      if (!pua)
+               return;
+-      ret = tce_iommu_prereg_ua_to_hpa(*pua, IOMMU_PAGE_SIZE(tbl),
++      ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl),
+                       &hpa, &mem);
+       if (ret)
+               pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n",
+@@ -435,7 +449,7 @@ static int tce_iommu_clear(struct tce_co
+                       continue;
+               if (container->v2) {
+-                      tce_iommu_unuse_page_v2(tbl, entry);
++                      tce_iommu_unuse_page_v2(container, tbl, entry);
+                       continue;
+               }
+@@ -516,7 +530,7 @@ static long tce_iommu_build_v2(struct tc
+       enum dma_data_direction dirtmp;
+       if (!tbl->it_userspace) {
+-              ret = tce_iommu_userspace_view_alloc(tbl);
++              ret = tce_iommu_userspace_view_alloc(tbl, container->mm);
+               if (ret)
+                       return ret;
+       }
+@@ -526,8 +540,8 @@ static long tce_iommu_build_v2(struct tc
+               unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl,
+                               entry + i);
+-              ret = tce_iommu_prereg_ua_to_hpa(tce, IOMMU_PAGE_SIZE(tbl),
+-                              &hpa, &mem);
++              ret = tce_iommu_prereg_ua_to_hpa(container,
++                              tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem);
+               if (ret)
+                       break;
+@@ -548,7 +562,7 @@ static long tce_iommu_build_v2(struct tc
+               ret = iommu_tce_xchg(tbl, entry + i, &hpa, &dirtmp);
+               if (ret) {
+                       /* dirtmp cannot be DMA_NONE here */
+-                      tce_iommu_unuse_page_v2(tbl, entry + i);
++                      tce_iommu_unuse_page_v2(container, tbl, entry + i);
+                       pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n",
+                                       __func__, entry << tbl->it_page_shift,
+                                       tce, ret);
+@@ -556,7 +570,7 @@ static long tce_iommu_build_v2(struct tc
+               }
+               if (dirtmp != DMA_NONE)
+-                      tce_iommu_unuse_page_v2(tbl, entry + i);
++                      tce_iommu_unuse_page_v2(container, tbl, entry + i);
+               *pua = tce;
+@@ -584,7 +598,7 @@ static long tce_iommu_create_table(struc
+       if (!table_size)
+               return -EINVAL;
+-      ret = try_increment_locked_vm(table_size >> PAGE_SHIFT);
++      ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT);
+       if (ret)
+               return ret;
+@@ -597,13 +611,14 @@ static long tce_iommu_create_table(struc
+       return ret;
+ }
+-static void tce_iommu_free_table(struct iommu_table *tbl)
++static void tce_iommu_free_table(struct tce_container *container,
++              struct iommu_table *tbl)
+ {
+       unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
+-      tce_iommu_userspace_view_free(tbl);
++      tce_iommu_userspace_view_free(tbl, container->mm);
+       tbl->it_ops->free(tbl);
+-      decrement_locked_vm(pages);
++      decrement_locked_vm(container->mm, pages);
+ }
+ static long tce_iommu_create_window(struct tce_container *container,
+@@ -666,7 +681,7 @@ unset_exit:
+               table_group = iommu_group_get_iommudata(tcegrp->grp);
+               table_group->ops->unset_window(table_group, num);
+       }
+-      tce_iommu_free_table(tbl);
++      tce_iommu_free_table(container, tbl);
+       return ret;
+ }
+@@ -704,7 +719,7 @@ static long tce_iommu_remove_window(stru
+       /* Free table */
+       tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
+-      tce_iommu_free_table(tbl);
++      tce_iommu_free_table(container, tbl);
+       container->tables[num] = NULL;
+       return 0;
+@@ -730,7 +745,17 @@ static long tce_iommu_ioctl(void *iommu_
+               }
+               return (ret < 0) ? 0 : ret;
++      }
++
++      /*
++       * Sanity check to prevent one userspace from manipulating
++       * another userspace mm.
++       */
++      BUG_ON(!container);
++      if (container->mm && container->mm != current->mm)
++              return -EPERM;
++      switch (cmd) {
+       case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
+               struct vfio_iommu_spapr_tce_info info;
+               struct tce_iommu_group *tcegrp;
+@@ -891,6 +916,10 @@ static long tce_iommu_ioctl(void *iommu_
+               minsz = offsetofend(struct vfio_iommu_spapr_register_memory,
+                               size);
++              ret = tce_iommu_mm_set(container);
++              if (ret)
++                      return ret;
++
+               if (copy_from_user(&param, (void __user *)arg, minsz))
+                       return -EFAULT;
+@@ -914,6 +943,9 @@ static long tce_iommu_ioctl(void *iommu_
+               if (!container->v2)
+                       break;
++              if (!container->mm)
++                      return -EPERM;
++
+               minsz = offsetofend(struct vfio_iommu_spapr_register_memory,
+                               size);
+@@ -972,6 +1004,10 @@ static long tce_iommu_ioctl(void *iommu_
+               if (!container->v2)
+                       break;
++              ret = tce_iommu_mm_set(container);
++              if (ret)
++                      return ret;
++
+               if (!tce_groups_attached(container))
+                       return -ENXIO;
+@@ -1006,6 +1042,10 @@ static long tce_iommu_ioctl(void *iommu_
+               if (!container->v2)
+                       break;
++              ret = tce_iommu_mm_set(container);
++              if (ret)
++                      return ret;
++
+               if (!tce_groups_attached(container))
+                       return -ENXIO;
+@@ -1046,7 +1086,7 @@ static void tce_iommu_release_ownership(
+                       continue;
+               tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
+-              tce_iommu_userspace_view_free(tbl);
++              tce_iommu_userspace_view_free(tbl, container->mm);
+               if (tbl->it_map)
+                       iommu_release_ownership(tbl);
diff --git a/queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch b/queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch
new file mode 100644 (file)
index 0000000..6e1624c
--- /dev/null
@@ -0,0 +1,124 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:22 +0000
+Subject: [PATCH v2 for-4.9 10/40] x86/hyperv: Handle unknown NMIs on one CPU when unknown_nmi_panic
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-10-alexander.levin@verizon.com>
+
+From: Vitaly Kuznetsov <vkuznets@redhat.com>
+
+[ Upstream commit 59107e2f48831daedc46973ce4988605ab066de3 ]
+
+There is a feature in Hyper-V ('Debug-VM --InjectNonMaskableInterrupt')
+which injects NMI to the guest. We may want to crash the guest and do kdump
+on this NMI by enabling unknown_nmi_panic. To make kdump succeed we need to
+allow the kdump kernel to re-establish VMBus connection so it will see
+VMBus devices (storage, network,..).
+
+To properly unload VMBus making it possible to start over during kdump we
+need to do the following:
+
+ - Send an 'unload' message to the hypervisor. This can be done on any CPU
+   so we do this the crashing CPU.
+
+ - Receive the 'unload finished' reply message. WS2012R2 delivers this
+   message to the CPU which was used to establish VMBus connection during
+   module load and this CPU may differ from the CPU sending 'unload'.
+
+Receiving a VMBus message means the following:
+
+ - There is a per-CPU slot in memory for one message. This slot can in
+   theory be accessed by any CPU.
+
+ - We get an interrupt on the CPU when a message was placed into the slot.
+
+ - When we read the message we need to clear the slot and signal the fact
+   to the hypervisor. In case there are more messages to this CPU pending
+   the hypervisor will deliver the next message. The signaling is done by
+   writing to an MSR so this can only be done on the appropriate CPU.
+
+To avoid doing cross-CPU work on crash we have vmbus_wait_for_unload()
+function which checks message slots for all CPUs in a loop waiting for the
+'unload finished' messages. However, there is an issue which arises when
+these conditions are met:
+
+ - We're crashing on a CPU which is different from the one which was used
+   to initially contact the hypervisor.
+
+ - The CPU which was used for the initial contact is blocked with interrupts
+   disabled and there is a message pending in the message slot.
+
+In this case we won't be able to read the 'unload finished' message on the
+crashing CPU. This is reproducible when we receive unknown NMIs on all CPUs
+simultaneously: the first CPU entering panic() will proceed to crash and
+all other CPUs will stop themselves with interrupts disabled.
+
+The suggested solution is to handle unknown NMIs for Hyper-V guests on the
+first CPU which gets them only. This will allow us to rely on VMBus
+interrupt handler being able to receive the 'unload finish' message in
+case it is delivered to a different CPU.
+
+The issue is not reproducible on WS2016 as Debug-VM delivers NMI to the
+boot CPU only, WS2012R2 and earlier Hyper-V versions are affected.
+
+Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
+Acked-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: devel@linuxdriverproject.org
+Cc: Haiyang Zhang <haiyangz@microsoft.com>
+Link: http://lkml.kernel.org/r/20161202100720.28121-1-vkuznets@redhat.com
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kernel/cpu/mshyperv.c |   24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/arch/x86/kernel/cpu/mshyperv.c
++++ b/arch/x86/kernel/cpu/mshyperv.c
+@@ -31,6 +31,7 @@
+ #include <asm/apic.h>
+ #include <asm/timer.h>
+ #include <asm/reboot.h>
++#include <asm/nmi.h>
+ struct ms_hyperv_info ms_hyperv;
+ EXPORT_SYMBOL_GPL(ms_hyperv);
+@@ -158,6 +159,26 @@ static unsigned char hv_get_nmi_reason(v
+       return 0;
+ }
++#ifdef CONFIG_X86_LOCAL_APIC
++/*
++ * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes
++ * it dificult to process CHANNELMSG_UNLOAD in case of crash. Handle
++ * unknown NMI on the first CPU which gets it.
++ */
++static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs)
++{
++      static atomic_t nmi_cpu = ATOMIC_INIT(-1);
++
++      if (!unknown_nmi_panic)
++              return NMI_DONE;
++
++      if (atomic_cmpxchg(&nmi_cpu, -1, raw_smp_processor_id()) != -1)
++              return NMI_HANDLED;
++
++      return NMI_DONE;
++}
++#endif
++
+ static void __init ms_hyperv_init_platform(void)
+ {
+       /*
+@@ -183,6 +204,9 @@ static void __init ms_hyperv_init_platfo
+               pr_info("HyperV: LAPIC Timer Frequency: %#x\n",
+                       lapic_timer_frequency);
+       }
++
++      register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST,
++                           "hv_nmi_unknown");
+ #endif
+       if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
diff --git a/queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch b/queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch
new file mode 100644 (file)
index 0000000..fcb021f
--- /dev/null
@@ -0,0 +1,85 @@
+From foo@baz Mon Mar 20 11:41:01 CET 2017
+From: alexander.levin@verizon.com
+Date: Fri, 17 Mar 2017 00:48:18 +0000
+Subject: [PATCH v2 for-4.9 01/40] xen: do not re-use pirq number cached in pci device msi msg data
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
+Message-ID: <20170317004812.26960-1-alexander.levin@verizon.com>
+
+From: Dan Streetman <ddstreet@ieee.org>
+
+[ Upstream commit c74fd80f2f41d05f350bb478151021f88551afe8 ]
+
+Revert the main part of commit:
+af42b8d12f8a ("xen: fix MSI setup and teardown for PV on HVM guests")
+
+That commit introduced reading the pci device's msi message data to see
+if a pirq was previously configured for the device's msi/msix, and re-use
+that pirq.  At the time, that was the correct behavior.  However, a
+later change to Qemu caused it to call into the Xen hypervisor to unmap
+all pirqs for a pci device, when the pci device disables its MSI/MSIX
+vectors; specifically the Qemu commit:
+c976437c7dba9c7444fb41df45468968aaa326ad
+("qemu-xen: free all the pirqs for msi/msix when driver unload")
+
+Once Qemu added this pirq unmapping, it was no longer correct for the
+kernel to re-use the pirq number cached in the pci device msi message
+data.  All Qemu releases since 2.1.0 contain the patch that unmaps the
+pirqs when the pci device disables its MSI/MSIX vectors.
+
+This bug is causing failures to initialize multiple NVMe controllers
+under Xen, because the NVMe driver sets up a single MSIX vector for
+each controller (concurrently), and then after using that to talk to
+the controller for some configuration data, it disables the single MSIX
+vector and re-configures all the MSIX vectors it needs.  So the MSIX
+setup code tries to re-use the cached pirq from the first vector
+for each controller, but the hypervisor has already given away that
+pirq to another controller, and its initialization fails.
+
+This is discussed in more detail at:
+https://lists.xen.org/archives/html/xen-devel/2017-01/msg00447.html
+
+Fixes: af42b8d12f8a ("xen: fix MSI setup and teardown for PV on HVM guests")
+Signed-off-by: Dan Streetman <dan.streetman@canonical.com>
+Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
+Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/pci/xen.c |   23 +++++++----------------
+ 1 file changed, 7 insertions(+), 16 deletions(-)
+
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -234,23 +234,14 @@ static int xen_hvm_setup_msi_irqs(struct
+               return 1;
+       for_each_pci_msi_entry(msidesc, dev) {
+-              __pci_read_msi_msg(msidesc, &msg);
+-              pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+-                      ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+-              if (msg.data != XEN_PIRQ_MSI_DATA ||
+-                  xen_irq_from_pirq(pirq) < 0) {
+-                      pirq = xen_allocate_pirq_msi(dev, msidesc);
+-                      if (pirq < 0) {
+-                              irq = -ENODEV;
+-                              goto error;
+-                      }
+-                      xen_msi_compose_msg(dev, pirq, &msg);
+-                      __pci_write_msi_msg(msidesc, &msg);
+-                      dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
+-              } else {
+-                      dev_dbg(&dev->dev,
+-                              "xen: msi already bound to pirq=%d\n", pirq);
++              pirq = xen_allocate_pirq_msi(dev, msidesc);
++              if (pirq < 0) {
++                      irq = -ENODEV;
++                      goto error;
+               }
++              xen_msi_compose_msg(dev, pirq, &msg);
++              __pci_write_msi_msg(msidesc, &msg);
++              dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
+               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
+                                              (type == PCI_CAP_ID_MSI) ? nvec : 1,
+                                              (type == PCI_CAP_ID_MSIX) ?