--- /dev/null
+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
+ {}
+ };
--- /dev/null
+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
+ {}
+ };
--- /dev/null
+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);
--- /dev/null
+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;
+ }
+
+ /*
--- /dev/null
+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,
+ },
+ };
+
--- /dev/null
+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
--- /dev/null
+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;
+ }
+
--- /dev/null
+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)
--- /dev/null
+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);
--- /dev/null
+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;
--- /dev/null
+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, ®ion, 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;
+
--- /dev/null
+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;
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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,
--- /dev/null
+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, ®ion, 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];
--- /dev/null
+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, ®ion, 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;
--- /dev/null
+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);
+ }
--- /dev/null
+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(¤t->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, ¤t->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, ¤t->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,
+- ¤t->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,
+- ¤t->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;
+
--- /dev/null
+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),
--- /dev/null
+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);
--- /dev/null
+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
--- /dev/null
+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;
+ }
--- /dev/null
+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);
+
--- /dev/null
+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[] = {
--- /dev/null
+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);
+
--- /dev/null
+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;
--- /dev/null
+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
--- /dev/null
+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 = {
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
--- /dev/null
+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;
--- /dev/null
+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;
+
--- /dev/null
+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;
--- /dev/null
+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:
--- /dev/null
+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(
--- /dev/null
+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:
--- /dev/null
+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(¤t->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(¤t->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(¤t->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(¤t->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(¶m, (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);
+
--- /dev/null
+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)
--- /dev/null
+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) ?