From cb720af4c7fcc05745ee6c9f107b0fbed274c168 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Mar 2017 11:49:24 +0100 Subject: [PATCH] 4.9-stable patches added patches: acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch block-allow-write_same-commands-with-the-sg_io-ioctl.patch drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch ibmveth-calculate-gso_segs-for-large-packets.patch igb-add-i211-to-i210-phy-workaround.patch igb-workaround-for-igb-i210-firmware-issue.patch pci-add-comments-about-rom-bar-updating.patch pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch pci-do-any-vf-bar-updates-before-enabling-the-bars.patch pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch pci-ignore-bar-updates-on-virtual-functions.patch pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch pci-separate-vf-bar-updates-from-standard-bar-updates.patch pci-update-bars-using-property-bits-appropriate-for-type.patch powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch s390-zcrypt-introduce-cex6-toleration.patch scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch scsi-ibmvscsis-rearrange-functions-for-future-patches.patch scsi-ibmvscsis-return-correct-partition-name-to-client.patch scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch usb-gadget-udc-atmel-remove-memory-leak.patch uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch vfio-spapr-add-a-helper-to-create-default-dma-window.patch vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch vfio-spapr-postpone-default-window-creation.patch vfio-spapr-reference-mm-in-tce_container.patch x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch --- ...rks-for-dell-precision-5520-and-3520.patch | 52 ++ ...ake-dell-latitude-3350-ethernet-work.patch | 48 + ...e_same-commands-with-the-sg_io-ioctl.patch | 82 ++ ...ound-mappings-in-get_next_pkt_raw-v2.patch | 91 ++ ...or-overlay-immediate-channel-indices.patch | 143 +++ ...separately-when-constructing-classes.patch | 271 ++++++ ...it-chid-into-chid.ctrl-and-chid.user.patch | 450 ++++++++++ ...calculate-gso_segs-for-large-packets.patch | 60 ++ .../igb-add-i211-to-i210-phy-workaround.patch | 35 + ...rkaround-for-igb-i210-firmware-issue.patch | 40 + ...-add-comments-about-rom-bar-updating.patch | 67 ++ ...om_enable-and-pci_rom_address_enable.patch | 37 + ...bar-updates-before-enabling-the-bars.patch | 65 ++ ...ars-while-vf-memory-space-is-enabled.patch | 57 ++ ...ore-bar-updates-on-virtual-functions.patch | 56 ++ ...esource_bar-and-pci_iov_resource_bar.patch | 156 ++++ ...ar-updates-from-standard-bar-updates.patch | 135 +++ ...g-property-bits-appropriate-for-type.patch | 54 ++ ...ss-mm_struct-to-init-cleanup-helpers.patch | 102 +++ ...u-stop-using-current-in-mm_iommu_xxx.patch | 248 ++++++ ...d-break-when-cma-n-spapr_tce_iommu-y.patch | 41 + ...put-pages-on-vfio-container-shutdown.patch | 211 +++++ ...390-zcrypt-introduce-cex6-toleration.patch | 43 + ...perly-if-target_submit_cmd-tmr-fails.patch | 45 + ...sis-issues-from-dan-carpenter-smatch.patch | 58 ++ ...arrange-functions-for-future-patches.patch | 822 ++++++++++++++++++ ...urn-correct-partition-name-to-client.patch | 43 + ...csis-synchronize-cmds-at-remove-time.patch | 129 +++ ...ronize-cmds-at-tpg_enable_store-time.patch | 475 ++++++++++ ...vel-driver-during-pci-error-recovery.patch | 108 +++ queue-4.9/series | 39 + ...ze_sched-out-of-slab_mutex-on-shrink.patch | 179 ++++ ...-gadget-udc-atmel-remove-memory-leak.patch | 48 + ...llback-for-webcams-with-broken-chain.patch | 174 ++++ ...-helper-to-create-default-dma-window.patch | 167 ++++ ...on-of-userspace-version-of-tce-table.patch | 80 ++ ...apr-postpone-default-window-creation.patch | 150 ++++ ...-spapr-reference-mm-in-tce_container.patch | 485 +++++++++++ ...is-on-one-cpu-when-unknown_nmi_panic.patch | 124 +++ ...er-cached-in-pci-device-msi-msg-data.patch | 85 ++ 40 files changed, 5755 insertions(+) create mode 100644 queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch create mode 100644 queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch create mode 100644 queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch create mode 100644 queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch create mode 100644 queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch create mode 100644 queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch create mode 100644 queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch create mode 100644 queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch create mode 100644 queue-4.9/igb-add-i211-to-i210-phy-workaround.patch create mode 100644 queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch create mode 100644 queue-4.9/pci-add-comments-about-rom-bar-updating.patch create mode 100644 queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch create mode 100644 queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch create mode 100644 queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch create mode 100644 queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch create mode 100644 queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch create mode 100644 queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch create mode 100644 queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch create mode 100644 queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch create mode 100644 queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch create mode 100644 queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch create mode 100644 queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch create mode 100644 queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch create mode 100644 queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch create mode 100644 queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch create mode 100644 queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch create mode 100644 queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch create mode 100644 queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch create mode 100644 queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch create mode 100644 queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch create mode 100644 queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch create mode 100644 queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch create mode 100644 queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch create mode 100644 queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch create mode 100644 queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch create mode 100644 queue-4.9/vfio-spapr-postpone-default-window-creation.patch create mode 100644 queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch create mode 100644 queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch create mode 100644 queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch diff --git a/queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch b/queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch new file mode 100644 index 00000000000..687885164d4 --- /dev/null +++ b/queue-4.9/acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch @@ -0,0 +1,52 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:32 +0000 +Subject: [PATCH v2 for-4.9 35/40] ACPI / blacklist: add _REV quirks for Dell Precision 5520 and 3520 +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-35-alexander.levin@verizon.com> + +From: Alex Hung + +[ 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 +[ rjw: Changelog ] +Signed-off-by: Rafael J. Wysocki + +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/acpi/blacklist.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/acpi/blacklist.c ++++ b/drivers/acpi/blacklist.c +@@ -160,6 +160,22 @@ static struct dmi_system_id acpi_rev_dmi + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), + }, + }, ++ { ++ .callback = dmi_enable_rev_override, ++ .ident = "DELL Precision 5520", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"), ++ }, ++ }, ++ { ++ .callback = dmi_enable_rev_override, ++ .ident = "DELL Precision 3520", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"), ++ }, ++ }, + #endif + {} + }; diff --git a/queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch b/queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch new file mode 100644 index 00000000000..75a74ff9f1f --- /dev/null +++ b/queue-4.9/acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch @@ -0,0 +1,48 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:32 +0000 +Subject: [PATCH v2 for-4.9 36/40] ACPI / blacklist: Make Dell Latitude 3350 ethernet work +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-36-alexander.levin@verizon.com> + +From: Michael Pobega + +[ 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 +[ rjw: Changelog ] +Signed-off-by: Rafael J. Wysocki + +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/acpi/blacklist.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/acpi/blacklist.c ++++ b/drivers/acpi/blacklist.c +@@ -176,6 +176,18 @@ static struct dmi_system_id acpi_rev_dmi + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"), + }, + }, ++ /* ++ * Resolves a quirk with the Dell Latitude 3350 that ++ * causes the ethernet adapter to not function. ++ */ ++ { ++ .callback = dmi_enable_rev_override, ++ .ident = "DELL Latitude 3350", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"), ++ }, ++ }, + #endif + {} + }; diff --git a/queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch b/queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch new file mode 100644 index 00000000000..30ef7040dd2 --- /dev/null +++ b/queue-4.9/block-allow-write_same-commands-with-the-sg_io-ioctl.patch @@ -0,0 +1,82 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:30 +0000 +Subject: [PATCH v2 for-4.9 31/40] block: allow WRITE_SAME commands with the SG_IO ioctl +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-31-alexander.levin@verizon.com> + +From: Mauricio Faria de Oliveira + +[ 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 "" [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 +Signed-off-by: Brahadambal Srinivasan +Reported-by: Manjunatha H R +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + block/scsi_ioctl.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/block/scsi_ioctl.c ++++ b/block/scsi_ioctl.c +@@ -182,6 +182,9 @@ static void blk_set_cmd_filter_defaults( + __set_bit(WRITE_16, filter->write_ok); + __set_bit(WRITE_LONG, filter->write_ok); + __set_bit(WRITE_LONG_2, filter->write_ok); ++ __set_bit(WRITE_SAME, filter->write_ok); ++ __set_bit(WRITE_SAME_16, filter->write_ok); ++ __set_bit(WRITE_SAME_32, filter->write_ok); + __set_bit(ERASE, filter->write_ok); + __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok); + __set_bit(MODE_SELECT, filter->write_ok); diff --git a/queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch b/queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch new file mode 100644 index 00000000000..a9e14032c88 --- /dev/null +++ b/queue-4.9/drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch @@ -0,0 +1,91 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:26 +0000 +Subject: [PATCH v2 for-4.9 20/40] Drivers: hv: ring_buffer: count on wrap around mappings in get_next_pkt_raw() (v2) +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-20-alexander.levin@verizon.com> + +From: Vitaly Kuznetsov + +[ 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 +Signed-off-by: K. Y. Srinivasan +Tested-by: Dexuan Cui +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/hyperv.h | 32 +++++++++++--------------------- + 1 file changed, 11 insertions(+), 21 deletions(-) + +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1548,31 +1548,23 @@ static inline struct vmpacket_descriptor + get_next_pkt_raw(struct vmbus_channel *channel) + { + struct hv_ring_buffer_info *ring_info = &channel->inbound; +- u32 read_loc = ring_info->priv_read_index; ++ u32 priv_read_loc = ring_info->priv_read_index; + void *ring_buffer = hv_get_ring_buffer(ring_info); +- struct vmpacket_descriptor *cur_desc; +- u32 packetlen; + u32 dsize = ring_info->ring_datasize; +- u32 delta = read_loc - ring_info->ring_buffer->read_index; ++ /* ++ * delta is the difference between what is available to read and ++ * what was already consumed in place. We commit read index after ++ * the whole batch is processed. ++ */ ++ u32 delta = priv_read_loc >= ring_info->ring_buffer->read_index ? ++ priv_read_loc - ring_info->ring_buffer->read_index : ++ (dsize - ring_info->ring_buffer->read_index) + priv_read_loc; + u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta); + + if (bytes_avail_toread < sizeof(struct vmpacket_descriptor)) + return NULL; + +- if ((read_loc + sizeof(*cur_desc)) > dsize) +- return NULL; +- +- cur_desc = ring_buffer + read_loc; +- packetlen = cur_desc->len8 << 3; +- +- /* +- * If the packet under consideration is wrapping around, +- * return failure. +- */ +- if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1)) +- return NULL; +- +- return cur_desc; ++ return ring_buffer + priv_read_loc; + } + + /* +@@ -1584,16 +1576,14 @@ static inline void put_pkt_raw(struct vm + struct vmpacket_descriptor *desc) + { + struct hv_ring_buffer_info *ring_info = &channel->inbound; +- u32 read_loc = ring_info->priv_read_index; + u32 packetlen = desc->len8 << 3; + u32 dsize = ring_info->ring_datasize; + +- if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize) +- BUG(); + /* + * Include the packet trailer. + */ + ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER; ++ ring_info->priv_read_index %= dsize; + } + + /* diff --git a/queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch b/queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch new file mode 100644 index 00000000000..d5479da0af9 --- /dev/null +++ b/queue-4.9/drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch @@ -0,0 +1,143 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:29 +0000 +Subject: [PATCH v2 for-4.9 28/40] drm/nouveau/disp/gp102: fix cursor/overlay immediate channel indices +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-28-alexander.levin@verizon.com> + +From: Ben Skeggs + +[ Upstream commit e50fcff15fe120ef2103a9e18af6644235c2b14d ] + +Signed-off-by: Ben Skeggs +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 ++ */ ++#include "channv50.h" ++#include "rootnv50.h" ++ ++#include ++ ++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 ++ */ ++#include "channv50.h" ++#include "rootnv50.h" ++ ++#include ++ ++const struct nv50_disp_pioc_oclass ++gp102_disp_oimm_oclass = { ++ .base.oclass = GK104_DISP_OVERLAY, ++ .base.minver = 0, ++ .base.maxver = 0, ++ .ctor = nv50_disp_oimm_new, ++ .func = &gf119_disp_pioc_func, ++ .chid = { 9, 13 }, ++}; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c +@@ -36,8 +36,8 @@ gp104_disp_root = { + &gp104_disp_ovly_oclass, + }, + .pioc = { +- &gk104_disp_oimm_oclass, +- &gk104_disp_curs_oclass, ++ &gp102_disp_oimm_oclass, ++ &gp102_disp_curs_oclass, + }, + }; + diff --git a/queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch b/queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch new file mode 100644 index 00000000000..ab32fa6fdd4 --- /dev/null +++ b/queue-4.9/drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch @@ -0,0 +1,271 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:30 +0000 +Subject: [PATCH v2 for-4.9 30/40] drm/nouveau/disp/nv50-: specify ctrl/user separately when constructing classes +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-30-alexander.levin@verizon.com> + +From: Ben Skeggs + +[ Upstream commit 2a32b9b1866a2ee9f01fbf2a48d99012f0120739 ] + +Signed-off-by: Ben Skeggs +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c | 11 ++++++----- + drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h | 15 +++++++++------ + drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c | 6 +++--- + drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c | 2 +- + drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c | 6 +++--- + drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 4 ++-- + 14 files changed, 32 insertions(+), 28 deletions(-) + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +@@ -263,7 +263,7 @@ nv50_disp_chan = { + int + nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, +- struct nv50_disp_root *root, int chid, int head, ++ struct nv50_disp_root *root, int ctrl, int user, int head, + const struct nvkm_oclass *oclass, + struct nv50_disp_chan *chan) + { +@@ -273,8 +273,8 @@ nv50_disp_chan_ctor(const struct nv50_di + chan->func = func; + chan->mthd = mthd; + chan->root = root; +- chan->chid.ctrl = chid; +- chan->chid.user = chid; ++ chan->chid.ctrl = ctrl; ++ chan->chid.user = user; + chan->head = head; + + if (disp->chan[chan->chid.user]) { +@@ -288,7 +288,7 @@ nv50_disp_chan_ctor(const struct nv50_di + int + nv50_disp_chan_new_(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, +- struct nv50_disp_root *root, int chid, int head, ++ struct nv50_disp_root *root, int ctrl, int user, int head, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) + { +@@ -298,5 +298,6 @@ nv50_disp_chan_new_(const struct nv50_di + return -ENOMEM; + *pobject = &chan->object; + +- return nv50_disp_chan_ctor(func, mthd, root, chid, head, oclass, chan); ++ return nv50_disp_chan_ctor(func, mthd, root, ctrl, user, ++ head, oclass, chan); + } +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h +@@ -29,11 +29,11 @@ struct nv50_disp_chan_func { + + int nv50_disp_chan_ctor(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, +- struct nv50_disp_root *, int chid, int head, ++ struct nv50_disp_root *, int ctrl, int user, int head, + const struct nvkm_oclass *, struct nv50_disp_chan *); + int nv50_disp_chan_new_(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, +- struct nv50_disp_root *, int chid, int head, ++ struct nv50_disp_root *, int ctrl, int user, int head, + const struct nvkm_oclass *, struct nvkm_object **); + + extern const struct nv50_disp_chan_func nv50_disp_pioc_func; +@@ -94,13 +94,16 @@ extern const struct nv50_disp_chan_mthd + struct nv50_disp_pioc_oclass { + int (*ctor)(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, +- struct nv50_disp_root *, int chid, ++ struct nv50_disp_root *, int ctrl, int user, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; +- int chid; ++ struct { ++ int ctrl; ++ int user; ++ } chid; + }; + + extern const struct nv50_disp_pioc_oclass nv50_disp_oimm_oclass; +@@ -123,12 +126,12 @@ extern const struct nv50_disp_pioc_oclas + + int nv50_disp_curs_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, +- struct nv50_disp_root *, int chid, ++ struct nv50_disp_root *, int ctrl, int user, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + int nv50_disp_oimm_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, +- struct nv50_disp_root *, int chid, ++ struct nv50_disp_root *, int ctrl, int user, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + #endif +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c +@@ -33,5 +33,5 @@ g84_disp_curs_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, +- .chid = 7, ++ .chid = { 7, 7 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c +@@ -33,5 +33,5 @@ gf119_disp_curs_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, +- .chid = 13, ++ .chid = { 13, 13 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c +@@ -33,5 +33,5 @@ gk104_disp_curs_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, +- .chid = 13, ++ .chid = { 13, 13 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c +@@ -33,5 +33,5 @@ gt215_disp_curs_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, +- .chid = 7, ++ .chid = { 7, 7 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c +@@ -33,7 +33,7 @@ + int + nv50_disp_curs_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, +- struct nv50_disp_root *root, int chid, ++ struct nv50_disp_root *root, int ctrl, int user, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) + { +@@ -54,7 +54,7 @@ nv50_disp_curs_new(const struct nv50_dis + } else + return ret; + +- return nv50_disp_chan_new_(func, mthd, root, chid + head, ++ return nv50_disp_chan_new_(func, mthd, root, ctrl + head, user + head, + head, oclass, pobject); + } + +@@ -65,5 +65,5 @@ nv50_disp_curs_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, +- .chid = 7, ++ .chid = { 7, 7 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c +@@ -149,7 +149,7 @@ nv50_disp_dmac_new_(const struct nv50_di + chan->func = func; + + ret = nv50_disp_chan_ctor(&nv50_disp_dmac_func_, mthd, root, +- chid, head, oclass, &chan->base); ++ chid, chid, head, oclass, &chan->base); + if (ret) + return ret; + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c +@@ -33,5 +33,5 @@ g84_disp_oimm_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, +- .chid = 5, ++ .chid = { 5, 5 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c +@@ -33,5 +33,5 @@ gf119_disp_oimm_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, +- .chid = 9, ++ .chid = { 9, 9 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c +@@ -33,5 +33,5 @@ gk104_disp_oimm_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, +- .chid = 9, ++ .chid = { 9, 9 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c +@@ -33,5 +33,5 @@ gt215_disp_oimm_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, +- .chid = 5, ++ .chid = { 5, 5 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c +@@ -33,7 +33,7 @@ + int + nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, +- struct nv50_disp_root *root, int chid, ++ struct nv50_disp_root *root, int ctrl, int user, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) + { +@@ -54,7 +54,7 @@ nv50_disp_oimm_new(const struct nv50_dis + } else + return ret; + +- return nv50_disp_chan_new_(func, mthd, root, chid + head, ++ return nv50_disp_chan_new_(func, mthd, root, ctrl + head, user + head, + head, oclass, pobject); + } + +@@ -65,5 +65,5 @@ nv50_disp_oimm_oclass = { + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, +- .chid = 5, ++ .chid = { 5, 5 }, + }; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +@@ -207,8 +207,8 @@ nv50_disp_root_pioc_new_(const struct nv + { + const struct nv50_disp_pioc_oclass *sclass = oclass->priv; + struct nv50_disp_root *root = nv50_disp_root(oclass->parent); +- return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid, +- oclass, data, size, pobject); ++ return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid.ctrl, ++ sclass->chid.user, oclass, data, size, pobject); + } + + static int diff --git a/queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch b/queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch new file mode 100644 index 00000000000..9ebee8ef2ca --- /dev/null +++ b/queue-4.9/drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch @@ -0,0 +1,450 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:29 +0000 +Subject: [PATCH v2 for-4.9 29/40] drm/nouveau/disp/nv50-: split chid into chid.ctrl and chid.user +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-29-alexander.levin@verizon.com> + +From: Ben Skeggs + +[ Upstream commit 4391d7f5c79a9fe6fa11cf6c160ca7f7bdb49d2a ] + +GP102/GP104 make life difficult by redefining the channel indices for +some registers, but not others. + +Signed-off-by: Ben Skeggs +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c | 23 +++++---- + drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h | 6 ++ + drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c | 44 +++++++++---------- + drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c | 23 +++++---- + drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c | 44 +++++++++---------- + drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c | 28 ++++++------ + drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c | 30 ++++++------ + 7 files changed, 106 insertions(+), 92 deletions(-) + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +@@ -82,7 +82,7 @@ nv50_disp_chan_mthd(struct nv50_disp_cha + + if (mthd->addr) { + snprintf(cname_, sizeof(cname_), "%s %d", +- mthd->name, chan->chid); ++ mthd->name, chan->chid.user); + cname = cname_; + } + +@@ -139,7 +139,7 @@ nv50_disp_chan_uevent_ctor(struct nvkm_o + if (!(ret = nvif_unvers(ret, &data, &size, args->none))) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; +- notify->index = chan->chid; ++ notify->index = chan->chid.user; + return 0; + } + +@@ -159,7 +159,7 @@ nv50_disp_chan_rd32(struct nvkm_object * + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; +- *data = nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); ++ *data = nvkm_rd32(device, 0x640000 + (chan->chid.user * 0x1000) + addr); + return 0; + } + +@@ -169,7 +169,7 @@ nv50_disp_chan_wr32(struct nvkm_object * + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; +- nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); ++ nvkm_wr32(device, 0x640000 + (chan->chid.user * 0x1000) + addr, data); + return 0; + } + +@@ -196,7 +196,7 @@ nv50_disp_chan_map(struct nvkm_object *o + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *addr = device->func->resource_addr(device, 0) + +- 0x640000 + (chan->chid * 0x1000); ++ 0x640000 + (chan->chid.user * 0x1000); + *size = 0x001000; + return 0; + } +@@ -243,8 +243,8 @@ nv50_disp_chan_dtor(struct nvkm_object * + { + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; +- if (chan->chid >= 0) +- disp->chan[chan->chid] = NULL; ++ if (chan->chid.user >= 0) ++ disp->chan[chan->chid.user] = NULL; + return chan->func->dtor ? chan->func->dtor(chan) : chan; + } + +@@ -273,14 +273,15 @@ nv50_disp_chan_ctor(const struct nv50_di + chan->func = func; + chan->mthd = mthd; + chan->root = root; +- chan->chid = chid; ++ chan->chid.ctrl = chid; ++ chan->chid.user = chid; + chan->head = head; + +- if (disp->chan[chan->chid]) { +- chan->chid = -1; ++ if (disp->chan[chan->chid.user]) { ++ chan->chid.user = -1; + return -EBUSY; + } +- disp->chan[chan->chid] = chan; ++ disp->chan[chan->chid.user] = chan; + return 0; + } + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h +@@ -7,7 +7,11 @@ struct nv50_disp_chan { + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; + struct nv50_disp_root *root; +- int chid; ++ ++ struct { ++ int ctrl; ++ int user; ++ } chid; + int head; + + struct nvkm_object object; +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c +@@ -32,8 +32,8 @@ gf119_disp_dmac_bind(struct nv50_disp_dm + struct nvkm_object *object, u32 handle) + { + return nvkm_ramht_insert(chan->base.root->ramht, object, +- chan->base.chid, -9, handle, +- chan->base.chid << 27 | 0x00000001); ++ chan->base.chid.user, -9, handle, ++ chan->base.chid.user << 27 | 0x00000001); + } + + void +@@ -42,22 +42,23 @@ gf119_disp_dmac_fini(struct nv50_disp_dm + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->base.chid; ++ int ctrl = chan->base.chid.ctrl; ++ int user = chan->base.chid.user; + + /* deactivate channel */ +- nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); +- nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); ++ nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00001010, 0x00001000); ++ nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) ++ if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x001e0000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d fini: %08x\n", chid, +- nvkm_rd32(device, 0x610490 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d fini: %08x\n", user, ++ nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); + } + + /* disable error reporting and completion notification */ +- nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); +- nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); ++ nvkm_mask(device, 0x610090, 0x00000001 << user, 0x00000000); ++ nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000000); + } + + static int +@@ -66,26 +67,27 @@ gf119_disp_dmac_init(struct nv50_disp_dm + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->base.chid; ++ int ctrl = chan->base.chid.ctrl; ++ int user = chan->base.chid.user; + + /* enable error reporting */ +- nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); ++ nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user); + + /* initialise channel for dma command submission */ +- nvkm_wr32(device, 0x610494 + (chid * 0x0010), chan->push); +- nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); +- nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); +- nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); +- nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); +- nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); ++ nvkm_wr32(device, 0x610494 + (ctrl * 0x0010), chan->push); ++ nvkm_wr32(device, 0x610498 + (ctrl * 0x0010), 0x00010000); ++ nvkm_wr32(device, 0x61049c + (ctrl * 0x0010), 0x00000001); ++ nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010); ++ nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000); ++ nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) ++ if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d init: %08x\n", chid, +- nvkm_rd32(device, 0x610490 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d init: %08x\n", user, ++ nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); + return -EBUSY; + } + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c +@@ -32,26 +32,27 @@ gp104_disp_dmac_init(struct nv50_disp_dm + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->base.chid; ++ int ctrl = chan->base.chid.ctrl; ++ int user = chan->base.chid.user; + + /* enable error reporting */ +- nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); ++ nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user); + + /* initialise channel for dma command submission */ +- nvkm_wr32(device, 0x611494 + (chid * 0x0010), chan->push); +- nvkm_wr32(device, 0x611498 + (chid * 0x0010), 0x00010000); +- nvkm_wr32(device, 0x61149c + (chid * 0x0010), 0x00000001); +- nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); +- nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); +- nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); ++ nvkm_wr32(device, 0x611494 + (ctrl * 0x0010), chan->push); ++ nvkm_wr32(device, 0x611498 + (ctrl * 0x0010), 0x00010000); ++ nvkm_wr32(device, 0x61149c + (ctrl * 0x0010), 0x00000001); ++ nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010); ++ nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000); ++ nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) ++ if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d init: %08x\n", chid, +- nvkm_rd32(device, 0x610490 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d init: %08x\n", user, ++ nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); + return -EBUSY; + } + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c +@@ -179,9 +179,9 @@ nv50_disp_dmac_bind(struct nv50_disp_dma + struct nvkm_object *object, u32 handle) + { + return nvkm_ramht_insert(chan->base.root->ramht, object, +- chan->base.chid, -10, handle, +- chan->base.chid << 28 | +- chan->base.chid); ++ chan->base.chid.user, -10, handle, ++ chan->base.chid.user << 28 | ++ chan->base.chid.user); + } + + static void +@@ -190,21 +190,22 @@ nv50_disp_dmac_fini(struct nv50_disp_dma + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->base.chid; ++ int ctrl = chan->base.chid.ctrl; ++ int user = chan->base.chid.user; + + /* deactivate channel */ +- nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); +- nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); ++ nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00001010, 0x00001000); ++ nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) ++ if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x001e0000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, +- nvkm_rd32(device, 0x610200 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d fini timeout, %08x\n", user, ++ nvkm_rd32(device, 0x610200 + (ctrl * 0x10))); + } + + /* disable error reporting and completion notifications */ +- nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); ++ nvkm_mask(device, 0x610028, 0x00010001 << user, 0x00000000 << user); + } + + static int +@@ -213,26 +214,27 @@ nv50_disp_dmac_init(struct nv50_disp_dma + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->base.chid; ++ int ctrl = chan->base.chid.ctrl; ++ int user = chan->base.chid.user; + + /* enable error reporting */ +- nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); ++ nvkm_mask(device, 0x610028, 0x00010000 << user, 0x00010000 << user); + + /* initialise channel for dma command submission */ +- nvkm_wr32(device, 0x610204 + (chid * 0x0010), chan->push); +- nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); +- nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); +- nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); +- nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); +- nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); ++ nvkm_wr32(device, 0x610204 + (ctrl * 0x0010), chan->push); ++ nvkm_wr32(device, 0x610208 + (ctrl * 0x0010), 0x00010000); ++ nvkm_wr32(device, 0x61020c + (ctrl * 0x0010), ctrl); ++ nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000010, 0x00000010); ++ nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), 0x00000000); ++ nvkm_wr32(device, 0x610200 + (ctrl * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) ++ if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x80000000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d init timeout, %08x\n", chid, +- nvkm_rd32(device, 0x610200 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d init timeout, %08x\n", user, ++ nvkm_rd32(device, 0x610200 + (ctrl * 0x10))); + return -EBUSY; + } + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c +@@ -32,20 +32,21 @@ gf119_disp_pioc_fini(struct nv50_disp_ch + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->chid; ++ int ctrl = chan->chid.ctrl; ++ int user = chan->chid.user; + +- nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); ++ nvkm_mask(device, 0x610490 + (ctrl * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) ++ if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x00030000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d fini: %08x\n", chid, +- nvkm_rd32(device, 0x610490 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d fini: %08x\n", user, ++ nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); + } + + /* disable error reporting and completion notification */ +- nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); +- nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); ++ nvkm_mask(device, 0x610090, 0x00000001 << user, 0x00000000); ++ nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000000); + } + + static int +@@ -54,20 +55,21 @@ gf119_disp_pioc_init(struct nv50_disp_ch + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->chid; ++ int ctrl = chan->chid.ctrl; ++ int user = chan->chid.user; + + /* enable error reporting */ +- nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); ++ nvkm_mask(device, 0x6100a0, 0x00000001 << user, 0x00000001 << user); + + /* activate channel */ +- nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); ++ nvkm_wr32(device, 0x610490 + (ctrl * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, +- u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10)); ++ u32 tmp = nvkm_rd32(device, 0x610490 + (ctrl * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d init: %08x\n", chid, +- nvkm_rd32(device, 0x610490 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d init: %08x\n", user, ++ nvkm_rd32(device, 0x610490 + (ctrl * 0x10))); + return -EBUSY; + } + +--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c +@@ -32,15 +32,16 @@ nv50_disp_pioc_fini(struct nv50_disp_cha + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->chid; ++ int ctrl = chan->chid.ctrl; ++ int user = chan->chid.user; + +- nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); ++ nvkm_mask(device, 0x610200 + (ctrl * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) ++ if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x00030000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d timeout: %08x\n", chid, +- nvkm_rd32(device, 0x610200 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d timeout: %08x\n", user, ++ nvkm_rd32(device, 0x610200 + (ctrl * 0x10))); + } + } + +@@ -50,26 +51,27 @@ nv50_disp_pioc_init(struct nv50_disp_cha + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; +- int chid = chan->chid; ++ int ctrl = chan->chid.ctrl; ++ int user = chan->chid.user; + +- nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); ++ nvkm_wr32(device, 0x610200 + (ctrl * 0x10), 0x00002000); + if (nvkm_msec(device, 2000, +- if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) ++ if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x00030000)) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d timeout0: %08x\n", chid, +- nvkm_rd32(device, 0x610200 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d timeout0: %08x\n", user, ++ nvkm_rd32(device, 0x610200 + (ctrl * 0x10))); + return -EBUSY; + } + +- nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); ++ nvkm_wr32(device, 0x610200 + (ctrl * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, +- u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10)); ++ u32 tmp = nvkm_rd32(device, 0x610200 + (ctrl * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { +- nvkm_error(subdev, "ch %d timeout1: %08x\n", chid, +- nvkm_rd32(device, 0x610200 + (chid * 0x10))); ++ nvkm_error(subdev, "ch %d timeout1: %08x\n", user, ++ nvkm_rd32(device, 0x610200 + (ctrl * 0x10))); + return -EBUSY; + } + diff --git a/queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch b/queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch new file mode 100644 index 00000000000..5d90801d2b4 --- /dev/null +++ b/queue-4.9/ibmveth-calculate-gso_segs-for-large-packets.patch @@ -0,0 +1,60 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:25 +0000 +Subject: [PATCH v2 for-4.9 19/40] ibmveth: calculate gso_segs for large packets +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-19-alexander.levin@verizon.com> + +From: Thomas Falcon + +[ Upstream commit 94acf164dc8f1184e8d0737be7125134c2701dbe ] + +Include calculations to compute the number of segments +that comprise an aggregated large packet. + +Signed-off-by: Thomas Falcon +Reviewed-by: Marcelo Ricardo Leitner +Reviewed-by: Jonathan Maxwell +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/ibm/ibmveth.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/ibm/ibmveth.c ++++ b/drivers/net/ethernet/ibm/ibmveth.c +@@ -1181,7 +1181,9 @@ map_failed: + + static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) + { ++ struct tcphdr *tcph; + int offset = 0; ++ int hdr_len; + + /* only TCP packets will be aggregated */ + if (skb->protocol == htons(ETH_P_IP)) { +@@ -1208,14 +1210,20 @@ static void ibmveth_rx_mss_helper(struct + /* if mss is not set through Large Packet bit/mss in rx buffer, + * expect that the mss will be written to the tcp header checksum. + */ ++ tcph = (struct tcphdr *)(skb->data + offset); + if (lrg_pkt) { + skb_shinfo(skb)->gso_size = mss; + } else if (offset) { +- struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset); +- + skb_shinfo(skb)->gso_size = ntohs(tcph->check); + tcph->check = 0; + } ++ ++ if (skb_shinfo(skb)->gso_size) { ++ hdr_len = offset + tcph->doff * 4; ++ skb_shinfo(skb)->gso_segs = ++ DIV_ROUND_UP(skb->len - hdr_len, ++ skb_shinfo(skb)->gso_size); ++ } + } + + static int ibmveth_poll(struct napi_struct *napi, int budget) diff --git a/queue-4.9/igb-add-i211-to-i210-phy-workaround.patch b/queue-4.9/igb-add-i211-to-i210-phy-workaround.patch new file mode 100644 index 00000000000..c0c56760766 --- /dev/null +++ b/queue-4.9/igb-add-i211-to-i210-phy-workaround.patch @@ -0,0 +1,35 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:19 +0000 +Subject: [PATCH v2 for-4.9 03/40] igb: add i211 to i210 PHY workaround +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-3-alexander.levin@verizon.com> + +From: Todd Fujinaka + +[ 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 +Tested-by: Aaron Brown +Signed-off-by: Jeff Kirsher +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/igb/e1000_phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/intel/igb/e1000_phy.c ++++ b/drivers/net/ethernet/intel/igb/e1000_phy.c +@@ -78,7 +78,7 @@ s32 igb_get_phy_id(struct e1000_hw *hw) + u16 phy_id; + + /* ensure PHY page selection to fix misconfigured i210 */ +- if (hw->mac.type == e1000_i210) ++ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) + phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0); + + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); diff --git a/queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch b/queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch new file mode 100644 index 00000000000..0ff31421c02 --- /dev/null +++ b/queue-4.9/igb-workaround-for-igb-i210-firmware-issue.patch @@ -0,0 +1,40 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:19 +0000 +Subject: [PATCH v2 for-4.9 02/40] igb: Workaround for igb i210 firmware issue +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-2-alexander.levin@verizon.com> + +From: Chris J Arges + +[ 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 +Tested-by: Aaron Brown +Signed-off-by: Jeff Kirsher +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/igb/e1000_phy.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/ethernet/intel/igb/e1000_phy.c ++++ b/drivers/net/ethernet/intel/igb/e1000_phy.c +@@ -77,6 +77,10 @@ s32 igb_get_phy_id(struct e1000_hw *hw) + s32 ret_val = 0; + u16 phy_id; + ++ /* ensure PHY page selection to fix misconfigured i210 */ ++ if (hw->mac.type == e1000_i210) ++ phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0); ++ + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; diff --git a/queue-4.9/pci-add-comments-about-rom-bar-updating.patch b/queue-4.9/pci-add-comments-about-rom-bar-updating.patch new file mode 100644 index 00000000000..db04916c10f --- /dev/null +++ b/queue-4.9/pci-add-comments-about-rom-bar-updating.patch @@ -0,0 +1,67 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:23 +0000 +Subject: [PATCH v2 for-4.9 13/40] PCI: Add comments about ROM BAR updating +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-13-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + diff --git a/queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch b/queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch new file mode 100644 index 00000000000..2daa5b56cec --- /dev/null +++ b/queue-4.9/pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch @@ -0,0 +1,37 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:23 +0000 +Subject: [PATCH v2 for-4.9 14/40] PCI: Decouple IORESOURCE_ROM_ENABLE and PCI_ROM_ADDRESS_ENABLE +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-14-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -227,7 +227,8 @@ int __pci_read_base(struct pci_dev *dev, + mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; + } + } else { +- res->flags |= (l & IORESOURCE_ROM_ENABLE); ++ if (l & PCI_ROM_ADDRESS_ENABLE) ++ res->flags |= IORESOURCE_ROM_ENABLE; + l64 = l & PCI_ROM_ADDRESS_MASK; + sz64 = sz & PCI_ROM_ADDRESS_MASK; + mask64 = (u32)PCI_ROM_ADDRESS_MASK; diff --git a/queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch b/queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch new file mode 100644 index 00000000000..55f23da477e --- /dev/null +++ b/queue-4.9/pci-do-any-vf-bar-updates-before-enabling-the-bars.patch @@ -0,0 +1,65 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:25 +0000 +Subject: [PATCH v2 for-4.9 18/40] PCI: Do any VF BAR updates before enabling the BARs +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-18-alexander.levin@verizon.com> + +From: Gavin Shan + +[ 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 +Signed-off-by: Gavin Shan +Signed-off-by: Bjorn Helgaas + +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/iov.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/pci/iov.c ++++ b/drivers/pci/iov.c +@@ -306,13 +306,6 @@ static int sriov_enable(struct pci_dev * + return rc; + } + +- pci_iov_set_numvfs(dev, nr_virtfn); +- iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; +- pci_cfg_access_lock(dev); +- pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); +- msleep(100); +- pci_cfg_access_unlock(dev); +- + iov->initial_VFs = initial; + if (nr_virtfn < initial) + initial = nr_virtfn; +@@ -323,6 +316,13 @@ static int sriov_enable(struct pci_dev * + goto err_pcibios; + } + ++ pci_iov_set_numvfs(dev, nr_virtfn); ++ iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; ++ pci_cfg_access_lock(dev); ++ pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); ++ msleep(100); ++ pci_cfg_access_unlock(dev); ++ + for (i = 0; i < initial; i++) { + rc = pci_iov_add_virtfn(dev, i, 0); + if (rc) diff --git a/queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch b/queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch new file mode 100644 index 00000000000..5a1be4f7caf --- /dev/null +++ b/queue-4.9/pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch @@ -0,0 +1,57 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:24 +0000 +Subject: [PATCH v2 for-4.9 15/40] PCI: Don't update VF BARs while VF memory space is enabled +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-15-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/iov.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/pci/iov.c ++++ b/drivers/pci/iov.c +@@ -566,6 +566,7 @@ void pci_iov_update_resource(struct pci_ + struct resource *res = dev->resource + resno; + int vf_bar = resno - PCI_IOV_RESOURCES; + struct pci_bus_region region; ++ u16 cmd; + u32 new; + int reg; + +@@ -577,6 +578,13 @@ void pci_iov_update_resource(struct pci_ + if (!iov) + return; + ++ pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); ++ if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { ++ dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", ++ vf_bar, res); ++ return; ++ } ++ + /* + * Ignore unimplemented BARs, unused resource slots for 64-bit + * BARs, and non-movable resources, e.g., those described via diff --git a/queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch b/queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch new file mode 100644 index 00000000000..f9bcb5b831e --- /dev/null +++ b/queue-4.9/pci-ignore-bar-updates-on-virtual-functions.patch @@ -0,0 +1,56 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:24 +0000 +Subject: [PATCH v2 for-4.9 17/40] PCI: Ignore BAR updates on virtual functions +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-17-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/pci.c | 4 ---- + drivers/pci/setup-res.c | 5 ++--- + 2 files changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -564,10 +564,6 @@ static void pci_restore_bars(struct pci_ + { + int i; + +- /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ +- if (dev->is_virtfn) +- return; +- + for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) + pci_update_resource(dev, i); + } +--- a/drivers/pci/setup-res.c ++++ b/drivers/pci/setup-res.c +@@ -34,10 +34,9 @@ static void pci_std_update_resource(stru + int reg; + struct resource *res = dev->resource + resno; + +- if (dev->is_virtfn) { +- dev_warn(&dev->dev, "can't update VF BAR%d\n", resno); ++ /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ ++ if (dev->is_virtfn) + return; +- } + + /* + * Ignore resources for unimplemented BARs and unused resource slots diff --git a/queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch b/queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch new file mode 100644 index 00000000000..e53ec67791d --- /dev/null +++ b/queue-4.9/pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch @@ -0,0 +1,156 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:23 +0000 +Subject: [PATCH v2 for-4.9 12/40] PCI: Remove pci_resource_bar() and pci_iov_resource_bar() +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-12-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/iov.c | 18 ------------------ + drivers/pci/pci.c | 30 ------------------------------ + drivers/pci/pci.h | 6 ------ + drivers/pci/setup-res.c | 13 +++++++------ + 4 files changed, 7 insertions(+), 60 deletions(-) + +--- a/drivers/pci/iov.c ++++ b/drivers/pci/iov.c +@@ -554,24 +554,6 @@ void pci_iov_release(struct pci_dev *dev + } + + /** +- * pci_iov_resource_bar - get position of the SR-IOV BAR +- * @dev: the PCI device +- * @resno: the resource number +- * +- * Returns position of the BAR encapsulated in the SR-IOV capability. +- */ +-int pci_iov_resource_bar(struct pci_dev *dev, int resno) +-{ +- if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END) +- return 0; +- +- BUG_ON(!dev->is_physfn); +- +- return dev->sriov->pos + PCI_SRIOV_BAR + +- 4 * (resno - PCI_IOV_RESOURCES); +-} +- +-/** + * pci_iov_update_resource - update a VF BAR + * @dev: the PCI device + * @resno: the resource number +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -4835,36 +4835,6 @@ int pci_select_bars(struct pci_dev *dev, + } + EXPORT_SYMBOL(pci_select_bars); + +-/** +- * pci_resource_bar - get position of the BAR associated with a resource +- * @dev: the PCI device +- * @resno: the resource number +- * @type: the BAR type to be filled in +- * +- * Returns BAR position in config space, or 0 if the BAR is invalid. +- */ +-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) +-{ +- int reg; +- +- if (resno < PCI_ROM_RESOURCE) { +- *type = pci_bar_unknown; +- return PCI_BASE_ADDRESS_0 + 4 * resno; +- } else if (resno == PCI_ROM_RESOURCE) { +- *type = pci_bar_mem32; +- return dev->rom_base_reg; +- } else if (resno < PCI_BRIDGE_RESOURCES) { +- /* device specific resource */ +- *type = pci_bar_unknown; +- reg = pci_iov_resource_bar(dev, resno); +- if (reg) +- return reg; +- } +- +- dev_err(&dev->dev, "BAR %d: invalid resource\n", resno); +- return 0; +-} +- + /* Some architectures require additional programming to enable VGA */ + static arch_set_vga_state_t arch_set_vga_state; + +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -245,7 +245,6 @@ bool pci_bus_read_dev_vendor_id(struct p + int pci_setup_device(struct pci_dev *dev); + int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, + struct resource *res, unsigned int reg); +-int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); + void pci_configure_ari(struct pci_dev *dev); + void __pci_bus_size_bridges(struct pci_bus *bus, + struct list_head *realloc_head); +@@ -289,7 +288,6 @@ static inline void pci_restore_ats_state + #ifdef CONFIG_PCI_IOV + int pci_iov_init(struct pci_dev *dev); + void pci_iov_release(struct pci_dev *dev); +-int pci_iov_resource_bar(struct pci_dev *dev, int resno); + void pci_iov_update_resource(struct pci_dev *dev, int resno); + resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno); + void pci_restore_iov_state(struct pci_dev *dev); +@@ -304,10 +302,6 @@ static inline void pci_iov_release(struc + + { + } +-static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno) +-{ +- return 0; +-} + static inline void pci_restore_iov_state(struct pci_dev *dev) + { + } +--- a/drivers/pci/setup-res.c ++++ b/drivers/pci/setup-res.c +@@ -32,7 +32,6 @@ static void pci_std_update_resource(stru + u16 cmd; + u32 new, check, mask; + int reg; +- enum pci_bar_type type; + struct resource *res = dev->resource + resno; + + if (dev->is_virtfn) { +@@ -66,14 +65,16 @@ static void pci_std_update_resource(stru + else + mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + +- reg = pci_resource_bar(dev, resno, &type); +- if (!reg) +- return; +- if (type != pci_bar_unknown) { ++ if (resno < PCI_ROM_RESOURCE) { ++ reg = PCI_BASE_ADDRESS_0 + 4 * resno; ++ } else if (resno == PCI_ROM_RESOURCE) { + if (!(res->flags & IORESOURCE_ROM_ENABLE)) + return; ++ ++ reg = dev->rom_base_reg; + new |= PCI_ROM_ADDRESS_ENABLE; +- } ++ } else ++ return; + + /* + * We can't update a 64-bit BAR atomically, so when possible, diff --git a/queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch b/queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch new file mode 100644 index 00000000000..8762d009546 --- /dev/null +++ b/queue-4.9/pci-separate-vf-bar-updates-from-standard-bar-updates.patch @@ -0,0 +1,135 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:22 +0000 +Subject: [PATCH v2 for-4.9 11/40] PCI: Separate VF BAR updates from standard BAR updates +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-11-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Reviewed-by: Gavin Shan +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include "pci.h" + +- +-void pci_update_resource(struct pci_dev *dev, int resno) ++static void pci_std_update_resource(struct pci_dev *dev, int resno) + { + struct pci_bus_region region; + bool disable; +@@ -110,6 +109,16 @@ void pci_update_resource(struct pci_dev + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + ++void pci_update_resource(struct pci_dev *dev, int resno) ++{ ++ if (resno <= PCI_ROM_RESOURCE) ++ pci_std_update_resource(dev, resno); ++#ifdef CONFIG_PCI_IOV ++ else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) ++ pci_iov_update_resource(dev, resno); ++#endif ++} ++ + int pci_claim_resource(struct pci_dev *dev, int resource) + { + struct resource *res = &dev->resource[resource]; diff --git a/queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch b/queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch new file mode 100644 index 00000000000..c05e78f0bef --- /dev/null +++ b/queue-4.9/pci-update-bars-using-property-bits-appropriate-for-type.patch @@ -0,0 +1,54 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:24 +0000 +Subject: [PATCH v2 for-4.9 16/40] PCI: Update BARs using property bits appropriate for type +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-16-alexander.levin@verizon.com> + +From: Bjorn Helgaas + +[ 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 +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch b/queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch new file mode 100644 index 00000000000..6d7cb8c91c3 --- /dev/null +++ b/queue-4.9/powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch @@ -0,0 +1,102 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:26 +0000 +Subject: [PATCH v2 for-4.9 22/40] powerpc/iommu: Pass mm_struct to init/cleanup helpers +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-22-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: David Gibson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/include/asm/mmu_context.h | 4 ++-- + arch/powerpc/kernel/setup-common.c | 2 +- + arch/powerpc/mm/mmu_context_book3s64.c | 4 ++-- + arch/powerpc/mm/mmu_context_iommu.c | 9 +++++---- + 4 files changed, 10 insertions(+), 9 deletions(-) + +--- a/arch/powerpc/include/asm/mmu_context.h ++++ b/arch/powerpc/include/asm/mmu_context.h +@@ -23,8 +23,8 @@ extern bool mm_iommu_preregistered(void) + extern long mm_iommu_get(unsigned long ua, unsigned long entries, + struct mm_iommu_table_group_mem_t **pmem); + extern long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem); +-extern void mm_iommu_init(mm_context_t *ctx); +-extern void mm_iommu_cleanup(mm_context_t *ctx); ++extern void mm_iommu_init(struct mm_struct *mm); ++extern void mm_iommu_cleanup(struct mm_struct *mm); + extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua, + unsigned long size); + extern struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua, +--- a/arch/powerpc/kernel/setup-common.c ++++ b/arch/powerpc/kernel/setup-common.c +@@ -915,7 +915,7 @@ void __init setup_arch(char **cmdline_p) + init_mm.context.pte_frag = NULL; + #endif + #ifdef CONFIG_SPAPR_TCE_IOMMU +- mm_iommu_init(&init_mm.context); ++ mm_iommu_init(&init_mm); + #endif + irqstack_early_init(); + exc_lvl_early_init(); +--- a/arch/powerpc/mm/mmu_context_book3s64.c ++++ b/arch/powerpc/mm/mmu_context_book3s64.c +@@ -115,7 +115,7 @@ int init_new_context(struct task_struct + mm->context.pte_frag = NULL; + #endif + #ifdef CONFIG_SPAPR_TCE_IOMMU +- mm_iommu_init(&mm->context); ++ mm_iommu_init(mm); + #endif + return 0; + } +@@ -160,7 +160,7 @@ static inline void destroy_pagetable_pag + void destroy_context(struct mm_struct *mm) + { + #ifdef CONFIG_SPAPR_TCE_IOMMU +- mm_iommu_cleanup(&mm->context); ++ mm_iommu_cleanup(mm); + #endif + + #ifdef CONFIG_PPC_ICSWX +--- a/arch/powerpc/mm/mmu_context_iommu.c ++++ b/arch/powerpc/mm/mmu_context_iommu.c +@@ -373,16 +373,17 @@ void mm_iommu_mapped_dec(struct mm_iommu + } + EXPORT_SYMBOL_GPL(mm_iommu_mapped_dec); + +-void mm_iommu_init(mm_context_t *ctx) ++void mm_iommu_init(struct mm_struct *mm) + { +- INIT_LIST_HEAD_RCU(&ctx->iommu_group_mem_list); ++ INIT_LIST_HEAD_RCU(&mm->context.iommu_group_mem_list); + } + +-void mm_iommu_cleanup(mm_context_t *ctx) ++void mm_iommu_cleanup(struct mm_struct *mm) + { + struct mm_iommu_table_group_mem_t *mem, *tmp; + +- list_for_each_entry_safe(mem, tmp, &ctx->iommu_group_mem_list, next) { ++ list_for_each_entry_safe(mem, tmp, &mm->context.iommu_group_mem_list, ++ next) { + list_del_rcu(&mem->next); + mm_iommu_do_free(mem); + } diff --git a/queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch b/queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch new file mode 100644 index 00000000000..a50434aee55 --- /dev/null +++ b/queue-4.9/powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch @@ -0,0 +1,248 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:27 +0000 +Subject: [PATCH v2 for-4.9 23/40] powerpc/iommu: Stop using @current in mm_iommu_xxx +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-23-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: David Gibson +Acked-by: Alex Williamson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + diff --git a/queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch b/queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch new file mode 100644 index 00000000000..88895c3ca99 --- /dev/null +++ b/queue-4.9/powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch @@ -0,0 +1,41 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:33 +0000 +Subject: [PATCH v2 for-4.9 40/40] powerpc/mm: Fix build break when CMA=n && SPAPR_TCE_IOMMU=y +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-40-alexander.levin@verizon.com> + +From: Michael Ellerman + +[ 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 +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/mm/mmu_context_iommu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/mm/mmu_context_iommu.c ++++ b/arch/powerpc/mm/mmu_context_iommu.c +@@ -184,7 +184,7 @@ long mm_iommu_get(struct mm_struct *mm, + * of the CMA zone if possible. NOTE: faulting in + migration + * can be expensive. Batching can be considered later + */ +- if (get_pageblock_migratetype(page) == MIGRATE_CMA) { ++ if (is_migrate_cma_page(page)) { + if (mm_iommu_move_page_from_cma(page)) + goto populate; + if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT), diff --git a/queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch b/queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch new file mode 100644 index 00000000000..e8b50b8178c --- /dev/null +++ b/queue-4.9/powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch @@ -0,0 +1,211 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:27 +0000 +Subject: [PATCH v2 for-4.9 25/40] powerpc/mm/iommu, vfio/spapr: Put pages on VFIO container shutdown +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-25-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: Nicholas Piggin +Acked-by: Alex Williamson +Reviewed-by: David Gibson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/mm/mmu_context_book3s64.c | 4 -- + arch/powerpc/mm/mmu_context_iommu.c | 11 ----- + drivers/vfio/vfio_iommu_spapr_tce.c | 61 ++++++++++++++++++++++++++++++++- + 3 files changed, 61 insertions(+), 15 deletions(-) + +--- a/arch/powerpc/mm/mmu_context_book3s64.c ++++ b/arch/powerpc/mm/mmu_context_book3s64.c +@@ -156,13 +156,11 @@ static inline void destroy_pagetable_pag + } + #endif + +- + void destroy_context(struct mm_struct *mm) + { + #ifdef CONFIG_SPAPR_TCE_IOMMU +- mm_iommu_cleanup(mm); ++ WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list)); + #endif +- + #ifdef CONFIG_PPC_ICSWX + drop_cop(mm->context.acop, mm); + kfree(mm->context.cop_lockp); +--- a/arch/powerpc/mm/mmu_context_iommu.c ++++ b/arch/powerpc/mm/mmu_context_iommu.c +@@ -365,14 +365,3 @@ void mm_iommu_init(struct mm_struct *mm) + { + INIT_LIST_HEAD_RCU(&mm->context.iommu_group_mem_list); + } +- +-void mm_iommu_cleanup(struct mm_struct *mm) +-{ +- struct mm_iommu_table_group_mem_t *mem, *tmp; +- +- list_for_each_entry_safe(mem, tmp, &mm->context.iommu_group_mem_list, +- next) { +- list_del_rcu(&mem->next); +- mm_iommu_do_free(mem); +- } +-} +--- a/drivers/vfio/vfio_iommu_spapr_tce.c ++++ b/drivers/vfio/vfio_iommu_spapr_tce.c +@@ -89,6 +89,15 @@ struct tce_iommu_group { + }; + + /* ++ * A container needs to remember which preregistered region it has ++ * referenced to do proper cleanup at the userspace process exit. ++ */ ++struct tce_iommu_prereg { ++ struct list_head next; ++ struct mm_iommu_table_group_mem_t *mem; ++}; ++ ++/* + * The container descriptor supports only a single group per container. + * Required by the API as the container is not supplied with the IOMMU group + * at the moment of initialization. +@@ -101,6 +110,7 @@ struct tce_container { + struct mm_struct *mm; + struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; + struct list_head group_list; ++ struct list_head prereg_list; + }; + + static long tce_iommu_mm_set(struct tce_container *container) +@@ -117,10 +127,27 @@ static long tce_iommu_mm_set(struct tce_ + return 0; + } + ++static long tce_iommu_prereg_free(struct tce_container *container, ++ struct tce_iommu_prereg *tcemem) ++{ ++ long ret; ++ ++ ret = mm_iommu_put(container->mm, tcemem->mem); ++ if (ret) ++ return ret; ++ ++ list_del(&tcemem->next); ++ kfree(tcemem); ++ ++ return 0; ++} ++ + static long tce_iommu_unregister_pages(struct tce_container *container, + __u64 vaddr, __u64 size) + { + struct mm_iommu_table_group_mem_t *mem; ++ struct tce_iommu_prereg *tcemem; ++ bool found = false; + + if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK)) + return -EINVAL; +@@ -129,7 +156,17 @@ static long tce_iommu_unregister_pages(s + if (!mem) + return -ENOENT; + +- return mm_iommu_put(container->mm, mem); ++ list_for_each_entry(tcemem, &container->prereg_list, next) { ++ if (tcemem->mem == mem) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ return -ENOENT; ++ ++ return tce_iommu_prereg_free(container, tcemem); + } + + static long tce_iommu_register_pages(struct tce_container *container, +@@ -137,16 +174,29 @@ static long tce_iommu_register_pages(str + { + long ret = 0; + struct mm_iommu_table_group_mem_t *mem = NULL; ++ struct tce_iommu_prereg *tcemem; + unsigned long entries = size >> PAGE_SHIFT; + + if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) || + ((vaddr + size) < vaddr)) + return -EINVAL; + ++ mem = mm_iommu_find(container->mm, vaddr, entries); ++ if (mem) { ++ list_for_each_entry(tcemem, &container->prereg_list, next) { ++ if (tcemem->mem == mem) ++ return -EBUSY; ++ } ++ } ++ + ret = mm_iommu_get(container->mm, vaddr, entries, &mem); + if (ret) + return ret; + ++ tcemem = kzalloc(sizeof(*tcemem), GFP_KERNEL); ++ tcemem->mem = mem; ++ list_add(&tcemem->next, &container->prereg_list); ++ + container->enabled = true; + + return 0; +@@ -333,6 +383,7 @@ static void *tce_iommu_open(unsigned lon + + mutex_init(&container->lock); + INIT_LIST_HEAD_RCU(&container->group_list); ++ INIT_LIST_HEAD_RCU(&container->prereg_list); + + container->v2 = arg == VFIO_SPAPR_TCE_v2_IOMMU; + +@@ -371,6 +422,14 @@ static void tce_iommu_release(void *iomm + tce_iommu_free_table(container, tbl); + } + ++ while (!list_empty(&container->prereg_list)) { ++ struct tce_iommu_prereg *tcemem; ++ ++ tcemem = list_first_entry(&container->prereg_list, ++ struct tce_iommu_prereg, next); ++ WARN_ON_ONCE(tce_iommu_prereg_free(container, tcemem)); ++ } ++ + tce_iommu_disable(container); + if (container->mm) + mmdrop(container->mm); diff --git a/queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch b/queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch new file mode 100644 index 00000000000..ed44e7d6aa4 --- /dev/null +++ b/queue-4.9/s390-zcrypt-introduce-cex6-toleration.patch @@ -0,0 +1,43 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:31 +0000 +Subject: [PATCH v2 for-4.9 32/40] s390/zcrypt: Introduce CEX6 toleration +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-32-alexander.levin@verizon.com> + +From: Harald Freudenberger + +[ Upstream commit b3e8652bcbfa04807e44708d4d0c8cdad39c9215 ] + +Signed-off-by: Harald Freudenberger +Signed-off-by: Martin Schwidefsky +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/crypto/ap_bus.c | 3 +++ + drivers/s390/crypto/ap_bus.h | 1 + + 2 files changed, 4 insertions(+) + +--- a/drivers/s390/crypto/ap_bus.c ++++ b/drivers/s390/crypto/ap_bus.c +@@ -1712,6 +1712,9 @@ static void ap_scan_bus(struct work_stru + ap_dev->queue_depth = queue_depth; + ap_dev->raw_hwtype = device_type; + ap_dev->device_type = device_type; ++ /* CEX6 toleration: map to CEX5 */ ++ if (device_type == AP_DEVICE_TYPE_CEX6) ++ ap_dev->device_type = AP_DEVICE_TYPE_CEX5; + ap_dev->functions = device_functions; + spin_lock_init(&ap_dev->lock); + INIT_LIST_HEAD(&ap_dev->pendingq); +--- a/drivers/s390/crypto/ap_bus.h ++++ b/drivers/s390/crypto/ap_bus.h +@@ -105,6 +105,7 @@ static inline int ap_test_bit(unsigned i + #define AP_DEVICE_TYPE_CEX3C 9 + #define AP_DEVICE_TYPE_CEX4 10 + #define AP_DEVICE_TYPE_CEX5 11 ++#define AP_DEVICE_TYPE_CEX6 12 + + /* + * Known function facilities diff --git a/queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch b/queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch new file mode 100644 index 00000000000..3d361a523d9 --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch @@ -0,0 +1,45 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:20 +0000 +Subject: [PATCH v2 for-4.9 06/40] scsi: ibmvscsis: Clean up properly if target_submit_cmd/tmr fails +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-6-alexander.levin@verizon.com> + +From: Michael Cyr + +[ Upstream commit 7435b32e2d2fb5da6c2ae9b9c8ce56d8a3cb3bc3 ] + +Signed-off-by: Michael Cyr +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +@@ -2552,6 +2552,10 @@ static void ibmvscsis_parse_cmd(struct s + data_len, attr, dir, 0); + if (rc) { + dev_err(&vscsi->dev, "target_submit_cmd failed, rc %d\n", rc); ++ spin_lock_bh(&vscsi->intr_lock); ++ list_del(&cmd->list); ++ ibmvscsis_free_cmd_resources(vscsi, cmd); ++ spin_unlock_bh(&vscsi->intr_lock); + goto fail; + } + return; +@@ -2631,6 +2635,9 @@ static void ibmvscsis_parse_task(struct + if (rc) { + dev_err(&vscsi->dev, "target_submit_tmr failed, rc %d\n", + rc); ++ spin_lock_bh(&vscsi->intr_lock); ++ list_del(&cmd->list); ++ spin_unlock_bh(&vscsi->intr_lock); + cmd->se_cmd.se_tmr_req->response = + TMR_FUNCTION_REJECTED; + } diff --git a/queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch b/queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch new file mode 100644 index 00000000000..c98746431ea --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch @@ -0,0 +1,58 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:20 +0000 +Subject: [PATCH v2 for-4.9 04/40] scsi: ibmvscsis: Issues from Dan Carpenter/Smatch +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-4-alexander.levin@verizon.com> + +From: Michael Cyr + +[ Upstream commit 11950d70b52d2bc5e3580da8cd63909ef38d67db ] + +Signed-off-by: Michael Cyr +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +@@ -1746,14 +1746,7 @@ static long ibmvscsis_mad(struct scsi_in + + pr_debug("mad: type %d\n", be32_to_cpu(mad->type)); + +- if (be16_to_cpu(mad->length) < 0) { +- dev_err(&vscsi->dev, "mad: length is < 0\n"); +- ibmvscsis_post_disconnect(vscsi, +- ERR_DISCONNECT_RECONNECT, 0); +- rc = SRP_VIOLATION; +- } else { +- rc = ibmvscsis_process_mad(vscsi, iue); +- } ++ rc = ibmvscsis_process_mad(vscsi, iue); + + pr_debug("mad: status %hd, rc %ld\n", be16_to_cpu(mad->status), + rc); +@@ -2523,7 +2516,6 @@ static void ibmvscsis_parse_cmd(struct s + dev_err(&vscsi->dev, "0x%llx: parsing SRP descriptor table failed.\n", + srp->tag); + goto fail; +- return; + } + + cmd->rsp.sol_not = srp->sol_not; +@@ -3379,7 +3371,8 @@ static int ibmvscsis_probe(struct vio_de + INIT_LIST_HEAD(&vscsi->waiting_rsp); + INIT_LIST_HEAD(&vscsi->active_q); + +- snprintf(vscsi->tport.tport_name, 256, "%s", dev_name(&vdev->dev)); ++ snprintf(vscsi->tport.tport_name, IBMVSCSIS_NAMELEN, "%s", ++ dev_name(&vdev->dev)); + + pr_debug("probe tport_name: %s\n", vscsi->tport.tport_name); + diff --git a/queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch b/queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch new file mode 100644 index 00000000000..b25b19f1950 --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-rearrange-functions-for-future-patches.patch @@ -0,0 +1,822 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:21 +0000 +Subject: [PATCH v2 for-4.9 07/40] scsi: ibmvscsis: Rearrange functions for future patches +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-7-alexander.levin@verizon.com> + +From: Michael Cyr + +[ 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 +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include +@@ -62,6 +62,8 @@ static long ibmvscsis_parse_command(stru + + static void ibmvscsis_adapter_idle(struct scsi_info *vscsi); + ++static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state); ++ + static void ibmvscsis_determine_resid(struct se_cmd *se_cmd, + struct srp_rsp *rsp) + { +@@ -82,7 +84,7 @@ static void ibmvscsis_determine_resid(st + } + } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + if (se_cmd->data_direction == DMA_TO_DEVICE) { +- /* residual data from an overflow write */ ++ /* residual data from an overflow write */ + rsp->flags = SRP_RSP_FLAG_DOOVER; + rsp->data_out_res_cnt = cpu_to_be32(residual_count); + } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { +@@ -102,7 +104,7 @@ static void ibmvscsis_determine_resid(st + * and the function returns TRUE. + * + * EXECUTION ENVIRONMENT: +- * Interrupt or Process environment ++ * Interrupt or Process environment + */ + static bool connection_broken(struct scsi_info *vscsi) + { +@@ -325,7 +327,7 @@ static struct viosrp_crq *ibmvscsis_cmd_ + } + + /** +- * ibmvscsis_send_init_message() - send initialize message to the client ++ * ibmvscsis_send_init_message() - send initialize message to the client + * @vscsi: Pointer to our adapter structure + * @format: Which Init Message format to send + * +@@ -383,13 +385,13 @@ static long ibmvscsis_check_init_msg(str + vscsi->cmd_q.base_addr); + if (crq) { + *format = (uint)(crq->format); +- rc = ERROR; ++ rc = ERROR; + crq->valid = INVALIDATE_CMD_RESP_EL; + dma_rmb(); + } + } else { + *format = (uint)(crq->format); +- rc = ERROR; ++ rc = ERROR; + crq->valid = INVALIDATE_CMD_RESP_EL; + dma_rmb(); + } +@@ -398,166 +400,6 @@ static long ibmvscsis_check_init_msg(str + } + + /** +- * ibmvscsis_establish_new_q() - Establish new CRQ queue +- * @vscsi: Pointer to our adapter structure +- * @new_state: New state being established after resetting the queue +- * +- * Must be called with interrupt lock held. +- */ +-static long ibmvscsis_establish_new_q(struct scsi_info *vscsi, uint new_state) +-{ +- long rc = ADAPT_SUCCESS; +- uint format; +- +- vscsi->flags &= PRESERVE_FLAG_FIELDS; +- vscsi->rsp_q_timer.timer_pops = 0; +- vscsi->debit = 0; +- vscsi->credit = 0; +- +- rc = vio_enable_interrupts(vscsi->dma_dev); +- if (rc) { +- pr_warn("reset_queue: failed to enable interrupts, rc %ld\n", +- rc); +- return rc; +- } +- +- rc = ibmvscsis_check_init_msg(vscsi, &format); +- if (rc) { +- dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n", +- rc); +- return rc; +- } +- +- if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) { +- rc = ibmvscsis_send_init_message(vscsi, INIT_MSG); +- switch (rc) { +- case H_SUCCESS: +- case H_DROPPED: +- case H_CLOSED: +- rc = ADAPT_SUCCESS; +- break; +- +- case H_PARAMETER: +- case H_HARDWARE: +- break; +- +- default: +- vscsi->state = UNDEFINED; +- rc = H_HARDWARE; +- break; +- } +- } +- +- return rc; +-} +- +-/** +- * ibmvscsis_reset_queue() - Reset CRQ Queue +- * @vscsi: Pointer to our adapter structure +- * @new_state: New state to establish after resetting the queue +- * +- * This function calls h_free_q and then calls h_reg_q and does all +- * of the bookkeeping to get us back to where we can communicate. +- * +- * Actually, we don't always call h_free_crq. A problem was discovered +- * where one partition would close and reopen his queue, which would +- * cause his partner to get a transport event, which would cause him to +- * close and reopen his queue, which would cause the original partition +- * to get a transport event, etc., etc. To prevent this, we don't +- * actually close our queue if the client initiated the reset, (i.e. +- * either we got a transport event or we have detected that the client's +- * queue is gone) +- * +- * EXECUTION ENVIRONMENT: +- * Process environment, called with interrupt lock held +- */ +-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state) +-{ +- int bytes; +- long rc = ADAPT_SUCCESS; +- +- pr_debug("reset_queue: flags 0x%x\n", vscsi->flags); +- +- /* don't reset, the client did it for us */ +- if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) { +- vscsi->flags &= PRESERVE_FLAG_FIELDS; +- vscsi->rsp_q_timer.timer_pops = 0; +- vscsi->debit = 0; +- vscsi->credit = 0; +- vscsi->state = new_state; +- vio_enable_interrupts(vscsi->dma_dev); +- } else { +- rc = ibmvscsis_free_command_q(vscsi); +- if (rc == ADAPT_SUCCESS) { +- vscsi->state = new_state; +- +- bytes = vscsi->cmd_q.size * PAGE_SIZE; +- rc = h_reg_crq(vscsi->dds.unit_id, +- vscsi->cmd_q.crq_token, bytes); +- if (rc == H_CLOSED || rc == H_SUCCESS) { +- rc = ibmvscsis_establish_new_q(vscsi, +- new_state); +- } +- +- if (rc != ADAPT_SUCCESS) { +- pr_debug("reset_queue: reg_crq rc %ld\n", rc); +- +- vscsi->state = ERR_DISCONNECTED; +- vscsi->flags |= RESPONSE_Q_DOWN; +- ibmvscsis_free_command_q(vscsi); +- } +- } else { +- vscsi->state = ERR_DISCONNECTED; +- vscsi->flags |= RESPONSE_Q_DOWN; +- } +- } +-} +- +-/** +- * ibmvscsis_free_cmd_resources() - Free command resources +- * @vscsi: Pointer to our adapter structure +- * @cmd: Command which is not longer in use +- * +- * Must be called with interrupt lock held. +- */ +-static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi, +- struct ibmvscsis_cmd *cmd) +-{ +- struct iu_entry *iue = cmd->iue; +- +- switch (cmd->type) { +- case TASK_MANAGEMENT: +- case SCSI_CDB: +- /* +- * When the queue goes down this value is cleared, so it +- * cannot be cleared in this general purpose function. +- */ +- if (vscsi->debit) +- vscsi->debit -= 1; +- break; +- case ADAPTER_MAD: +- vscsi->flags &= ~PROCESSING_MAD; +- break; +- case UNSET_TYPE: +- break; +- default: +- dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n", +- cmd->type); +- break; +- } +- +- cmd->iue = NULL; +- list_add_tail(&cmd->list, &vscsi->free_cmd); +- srp_iu_put(iue); +- +- if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) && +- list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) { +- vscsi->flags &= ~WAIT_FOR_IDLE; +- complete(&vscsi->wait_idle); +- } +-} +- +-/** + * ibmvscsis_disconnect() - Helper function to disconnect + * @work: Pointer to work_struct, gives access to our adapter structure + * +@@ -590,7 +432,7 @@ static void ibmvscsis_disconnect(struct + * should transitition to the new state + */ + switch (vscsi->state) { +- /* Should never be called while in this state. */ ++ /* Should never be called while in this state. */ + case NO_QUEUE: + /* + * Can never transition from this state; +@@ -807,6 +649,316 @@ static void ibmvscsis_post_disconnect(st + } + + /** ++ * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message ++ * @vscsi: Pointer to our adapter structure ++ * ++ * Must be called with interrupt lock held. ++ */ ++static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi) ++{ ++ long rc = ADAPT_SUCCESS; ++ ++ switch (vscsi->state) { ++ case NO_QUEUE: ++ case ERR_DISCONNECT: ++ case ERR_DISCONNECT_RECONNECT: ++ case ERR_DISCONNECTED: ++ case UNCONFIGURING: ++ case UNDEFINED: ++ rc = ERROR; ++ break; ++ ++ case WAIT_CONNECTION: ++ vscsi->state = CONNECTED; ++ break; ++ ++ case WAIT_IDLE: ++ case SRP_PROCESSING: ++ case CONNECTED: ++ case WAIT_ENABLED: ++ case PART_UP_WAIT_ENAB: ++ default: ++ rc = ERROR; ++ dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n", ++ vscsi->state); ++ ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); ++ break; ++ } ++ ++ return rc; ++} ++ ++/** ++ * ibmvscsis_handle_init_msg() - Respond to an Init Message ++ * @vscsi: Pointer to our adapter structure ++ * ++ * Must be called with interrupt lock held. ++ */ ++static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi) ++{ ++ long rc = ADAPT_SUCCESS; ++ ++ switch (vscsi->state) { ++ case WAIT_ENABLED: ++ vscsi->state = PART_UP_WAIT_ENAB; ++ break; ++ ++ case WAIT_CONNECTION: ++ rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG); ++ switch (rc) { ++ case H_SUCCESS: ++ vscsi->state = CONNECTED; ++ break; ++ ++ case H_PARAMETER: ++ dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n", ++ rc); ++ ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0); ++ break; ++ ++ case H_DROPPED: ++ dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n", ++ rc); ++ rc = ERROR; ++ ibmvscsis_post_disconnect(vscsi, ++ ERR_DISCONNECT_RECONNECT, 0); ++ break; ++ ++ case H_CLOSED: ++ pr_warn("init_msg: failed to send, rc %ld\n", rc); ++ rc = 0; ++ break; ++ } ++ break; ++ ++ case UNDEFINED: ++ rc = ERROR; ++ break; ++ ++ case UNCONFIGURING: ++ break; ++ ++ case PART_UP_WAIT_ENAB: ++ case CONNECTED: ++ case SRP_PROCESSING: ++ case WAIT_IDLE: ++ case NO_QUEUE: ++ case ERR_DISCONNECT: ++ case ERR_DISCONNECT_RECONNECT: ++ case ERR_DISCONNECTED: ++ default: ++ rc = ERROR; ++ dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n", ++ vscsi->state); ++ ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); ++ break; ++ } ++ ++ return rc; ++} ++ ++/** ++ * ibmvscsis_init_msg() - Respond to an init message ++ * @vscsi: Pointer to our adapter structure ++ * @crq: Pointer to CRQ element containing the Init Message ++ * ++ * EXECUTION ENVIRONMENT: ++ * Interrupt, interrupt lock held ++ */ ++static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq) ++{ ++ long rc = ADAPT_SUCCESS; ++ ++ pr_debug("init_msg: state 0x%hx\n", vscsi->state); ++ ++ rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO, ++ (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0, ++ 0); ++ if (rc == H_SUCCESS) { ++ vscsi->client_data.partition_number = ++ be64_to_cpu(*(u64 *)vscsi->map_buf); ++ pr_debug("init_msg, part num %d\n", ++ vscsi->client_data.partition_number); ++ } else { ++ pr_debug("init_msg h_vioctl rc %ld\n", rc); ++ rc = ADAPT_SUCCESS; ++ } ++ ++ if (crq->format == INIT_MSG) { ++ rc = ibmvscsis_handle_init_msg(vscsi); ++ } else if (crq->format == INIT_COMPLETE_MSG) { ++ rc = ibmvscsis_handle_init_compl_msg(vscsi); ++ } else { ++ rc = ERROR; ++ dev_err(&vscsi->dev, "init_msg: invalid format %d\n", ++ (uint)crq->format); ++ ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); ++ } ++ ++ return rc; ++} ++ ++/** ++ * ibmvscsis_establish_new_q() - Establish new CRQ queue ++ * @vscsi: Pointer to our adapter structure ++ * @new_state: New state being established after resetting the queue ++ * ++ * Must be called with interrupt lock held. ++ */ ++static long ibmvscsis_establish_new_q(struct scsi_info *vscsi, uint new_state) ++{ ++ long rc = ADAPT_SUCCESS; ++ uint format; ++ ++ vscsi->flags &= PRESERVE_FLAG_FIELDS; ++ vscsi->rsp_q_timer.timer_pops = 0; ++ vscsi->debit = 0; ++ vscsi->credit = 0; ++ ++ rc = vio_enable_interrupts(vscsi->dma_dev); ++ if (rc) { ++ pr_warn("reset_queue: failed to enable interrupts, rc %ld\n", ++ rc); ++ return rc; ++ } ++ ++ rc = ibmvscsis_check_init_msg(vscsi, &format); ++ if (rc) { ++ dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n", ++ rc); ++ return rc; ++ } ++ ++ if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) { ++ rc = ibmvscsis_send_init_message(vscsi, INIT_MSG); ++ switch (rc) { ++ case H_SUCCESS: ++ case H_DROPPED: ++ case H_CLOSED: ++ rc = ADAPT_SUCCESS; ++ break; ++ ++ case H_PARAMETER: ++ case H_HARDWARE: ++ break; ++ ++ default: ++ vscsi->state = UNDEFINED; ++ rc = H_HARDWARE; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++/** ++ * ibmvscsis_reset_queue() - Reset CRQ Queue ++ * @vscsi: Pointer to our adapter structure ++ * @new_state: New state to establish after resetting the queue ++ * ++ * This function calls h_free_q and then calls h_reg_q and does all ++ * of the bookkeeping to get us back to where we can communicate. ++ * ++ * Actually, we don't always call h_free_crq. A problem was discovered ++ * where one partition would close and reopen his queue, which would ++ * cause his partner to get a transport event, which would cause him to ++ * close and reopen his queue, which would cause the original partition ++ * to get a transport event, etc., etc. To prevent this, we don't ++ * actually close our queue if the client initiated the reset, (i.e. ++ * either we got a transport event or we have detected that the client's ++ * queue is gone) ++ * ++ * EXECUTION ENVIRONMENT: ++ * Process environment, called with interrupt lock held ++ */ ++static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state) ++{ ++ int bytes; ++ long rc = ADAPT_SUCCESS; ++ ++ pr_debug("reset_queue: flags 0x%x\n", vscsi->flags); ++ ++ /* don't reset, the client did it for us */ ++ if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) { ++ vscsi->flags &= PRESERVE_FLAG_FIELDS; ++ vscsi->rsp_q_timer.timer_pops = 0; ++ vscsi->debit = 0; ++ vscsi->credit = 0; ++ vscsi->state = new_state; ++ vio_enable_interrupts(vscsi->dma_dev); ++ } else { ++ rc = ibmvscsis_free_command_q(vscsi); ++ if (rc == ADAPT_SUCCESS) { ++ vscsi->state = new_state; ++ ++ bytes = vscsi->cmd_q.size * PAGE_SIZE; ++ rc = h_reg_crq(vscsi->dds.unit_id, ++ vscsi->cmd_q.crq_token, bytes); ++ if (rc == H_CLOSED || rc == H_SUCCESS) { ++ rc = ibmvscsis_establish_new_q(vscsi, ++ new_state); ++ } ++ ++ if (rc != ADAPT_SUCCESS) { ++ pr_debug("reset_queue: reg_crq rc %ld\n", rc); ++ ++ vscsi->state = ERR_DISCONNECTED; ++ vscsi->flags |= RESPONSE_Q_DOWN; ++ ibmvscsis_free_command_q(vscsi); ++ } ++ } else { ++ vscsi->state = ERR_DISCONNECTED; ++ vscsi->flags |= RESPONSE_Q_DOWN; ++ } ++ } ++} ++ ++/** ++ * ibmvscsis_free_cmd_resources() - Free command resources ++ * @vscsi: Pointer to our adapter structure ++ * @cmd: Command which is not longer in use ++ * ++ * Must be called with interrupt lock held. ++ */ ++static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi, ++ struct ibmvscsis_cmd *cmd) ++{ ++ struct iu_entry *iue = cmd->iue; ++ ++ switch (cmd->type) { ++ case TASK_MANAGEMENT: ++ case SCSI_CDB: ++ /* ++ * When the queue goes down this value is cleared, so it ++ * cannot be cleared in this general purpose function. ++ */ ++ if (vscsi->debit) ++ vscsi->debit -= 1; ++ break; ++ case ADAPTER_MAD: ++ vscsi->flags &= ~PROCESSING_MAD; ++ break; ++ case UNSET_TYPE: ++ break; ++ default: ++ dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n", ++ cmd->type); ++ break; ++ } ++ ++ cmd->iue = NULL; ++ list_add_tail(&cmd->list, &vscsi->free_cmd); ++ srp_iu_put(iue); ++ ++ if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) && ++ list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) { ++ vscsi->flags &= ~WAIT_FOR_IDLE; ++ complete(&vscsi->wait_idle); ++ } ++} ++ ++/** + * ibmvscsis_trans_event() - Handle a Transport Event + * @vscsi: Pointer to our adapter structure + * @crq: Pointer to CRQ entry containing the Transport Event +@@ -896,7 +1048,7 @@ static long ibmvscsis_trans_event(struct + } + } + +- rc = vscsi->flags & SCHEDULE_DISCONNECT; ++ rc = vscsi->flags & SCHEDULE_DISCONNECT; + + pr_debug("Leaving trans_event: flags 0x%x, state 0x%hx, rc %ld\n", + vscsi->flags, vscsi->state, rc); +@@ -1221,7 +1373,7 @@ static long ibmvscsis_copy_crq_packet(st + * @iue: Information Unit containing the Adapter Info MAD request + * + * EXECUTION ENVIRONMENT: +- * Interrupt adpater lock is held ++ * Interrupt adapter lock is held + */ + static long ibmvscsis_adapter_info(struct scsi_info *vscsi, + struct iu_entry *iue) +@@ -1692,7 +1844,7 @@ static void ibmvscsis_send_mad_resp(stru + * @crq: Pointer to the CRQ entry containing the MAD request + * + * EXECUTION ENVIRONMENT: +- * Interrupt called with adapter lock held ++ * Interrupt, called with adapter lock held + */ + static long ibmvscsis_mad(struct scsi_info *vscsi, struct viosrp_crq *crq) + { +@@ -1858,7 +2010,7 @@ static long ibmvscsis_srp_login_rej(stru + break; + case H_PERMISSION: + if (connection_broken(vscsi)) +- flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED; ++ flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED; + dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n", + rc); + ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, +@@ -2181,156 +2333,6 @@ static long ibmvscsis_ping_response(stru + } + + /** +- * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message +- * @vscsi: Pointer to our adapter structure +- * +- * Must be called with interrupt lock held. +- */ +-static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi) +-{ +- long rc = ADAPT_SUCCESS; +- +- switch (vscsi->state) { +- case NO_QUEUE: +- case ERR_DISCONNECT: +- case ERR_DISCONNECT_RECONNECT: +- case ERR_DISCONNECTED: +- case UNCONFIGURING: +- case UNDEFINED: +- rc = ERROR; +- break; +- +- case WAIT_CONNECTION: +- vscsi->state = CONNECTED; +- break; +- +- case WAIT_IDLE: +- case SRP_PROCESSING: +- case CONNECTED: +- case WAIT_ENABLED: +- case PART_UP_WAIT_ENAB: +- default: +- rc = ERROR; +- dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n", +- vscsi->state); +- ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); +- break; +- } +- +- return rc; +-} +- +-/** +- * ibmvscsis_handle_init_msg() - Respond to an Init Message +- * @vscsi: Pointer to our adapter structure +- * +- * Must be called with interrupt lock held. +- */ +-static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi) +-{ +- long rc = ADAPT_SUCCESS; +- +- switch (vscsi->state) { +- case WAIT_ENABLED: +- vscsi->state = PART_UP_WAIT_ENAB; +- break; +- +- case WAIT_CONNECTION: +- rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG); +- switch (rc) { +- case H_SUCCESS: +- vscsi->state = CONNECTED; +- break; +- +- case H_PARAMETER: +- dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n", +- rc); +- ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0); +- break; +- +- case H_DROPPED: +- dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n", +- rc); +- rc = ERROR; +- ibmvscsis_post_disconnect(vscsi, +- ERR_DISCONNECT_RECONNECT, 0); +- break; +- +- case H_CLOSED: +- pr_warn("init_msg: failed to send, rc %ld\n", rc); +- rc = 0; +- break; +- } +- break; +- +- case UNDEFINED: +- rc = ERROR; +- break; +- +- case UNCONFIGURING: +- break; +- +- case PART_UP_WAIT_ENAB: +- case CONNECTED: +- case SRP_PROCESSING: +- case WAIT_IDLE: +- case NO_QUEUE: +- case ERR_DISCONNECT: +- case ERR_DISCONNECT_RECONNECT: +- case ERR_DISCONNECTED: +- default: +- rc = ERROR; +- dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n", +- vscsi->state); +- ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); +- break; +- } +- +- return rc; +-} +- +-/** +- * ibmvscsis_init_msg() - Respond to an init message +- * @vscsi: Pointer to our adapter structure +- * @crq: Pointer to CRQ element containing the Init Message +- * +- * EXECUTION ENVIRONMENT: +- * Interrupt, interrupt lock held +- */ +-static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq) +-{ +- long rc = ADAPT_SUCCESS; +- +- pr_debug("init_msg: state 0x%hx\n", vscsi->state); +- +- rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO, +- (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0, +- 0); +- if (rc == H_SUCCESS) { +- vscsi->client_data.partition_number = +- be64_to_cpu(*(u64 *)vscsi->map_buf); +- pr_debug("init_msg, part num %d\n", +- vscsi->client_data.partition_number); +- } else { +- pr_debug("init_msg h_vioctl rc %ld\n", rc); +- rc = ADAPT_SUCCESS; +- } +- +- if (crq->format == INIT_MSG) { +- rc = ibmvscsis_handle_init_msg(vscsi); +- } else if (crq->format == INIT_COMPLETE_MSG) { +- rc = ibmvscsis_handle_init_compl_msg(vscsi); +- } else { +- rc = ERROR; +- dev_err(&vscsi->dev, "init_msg: invalid format %d\n", +- (uint)crq->format); +- ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); +- } +- +- return rc; +-} +- +-/** + * ibmvscsis_parse_command() - Parse an element taken from the cmd rsp queue. + * @vscsi: Pointer to our adapter structure + * @crq: Pointer to CRQ element containing the SRP request +@@ -2385,7 +2387,7 @@ static long ibmvscsis_parse_command(stru + break; + + case VALID_TRANS_EVENT: +- rc = ibmvscsis_trans_event(vscsi, crq); ++ rc = ibmvscsis_trans_event(vscsi, crq); + break; + + case VALID_INIT_MSG: +@@ -3270,7 +3272,7 @@ static void ibmvscsis_handle_crq(unsigne + /* + * if we are in a path where we are waiting for all pending commands + * to complete because we received a transport event and anything in +- * the command queue is for a new connection, do nothing ++ * the command queue is for a new connection, do nothing + */ + if (TARGET_STOP(vscsi)) { + vio_enable_interrupts(vscsi->dma_dev); +@@ -3314,7 +3316,7 @@ cmd_work: + * everything but transport events on the queue + * + * need to decrement the queue index so we can +- * look at the elment again ++ * look at the element again + */ + if (vscsi->cmd_q.index) + vscsi->cmd_q.index -= 1; +@@ -3988,10 +3990,10 @@ static struct attribute *ibmvscsis_dev_a + ATTRIBUTE_GROUPS(ibmvscsis_dev); + + static struct class ibmvscsis_class = { +- .name = "ibmvscsis", +- .dev_release = ibmvscsis_dev_release, +- .class_attrs = ibmvscsis_class_attrs, +- .dev_groups = ibmvscsis_dev_groups, ++ .name = "ibmvscsis", ++ .dev_release = ibmvscsis_dev_release, ++ .class_attrs = ibmvscsis_class_attrs, ++ .dev_groups = ibmvscsis_dev_groups, + }; + + static struct vio_device_id ibmvscsis_device_table[] = { diff --git a/queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch b/queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch new file mode 100644 index 00000000000..e783bf6665a --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-return-correct-partition-name-to-client.patch @@ -0,0 +1,43 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:20 +0000 +Subject: [PATCH v2 for-4.9 05/40] scsi: ibmvscsis: Return correct partition name/# to client +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-5-alexander.levin@verizon.com> + +From: Michael Cyr + +[ Upstream commit 9c93cf03d4eb3dc58931ff7cac0af9c344fe5e0b ] + +Signed-off-by: Michael Cyr +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +@@ -3387,6 +3387,9 @@ static int ibmvscsis_probe(struct vio_de + strncat(vscsi->eye, vdev->name, MAX_EYE); + + vscsi->dds.unit_id = vdev->unit_address; ++ strncpy(vscsi->dds.partition_name, partition_name, ++ sizeof(vscsi->dds.partition_name)); ++ vscsi->dds.partition_num = partition_number; + + spin_lock_bh(&ibmvscsis_dev_lock); + list_add_tail(&vscsi->list, &ibmvscsis_dev_list); +@@ -3603,7 +3606,7 @@ static int ibmvscsis_get_system_info(voi + + num = of_get_property(rootdn, "ibm,partition-no", NULL); + if (num) +- partition_number = *num; ++ partition_number = of_read_number(num, 1); + + of_node_put(rootdn); + diff --git a/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch new file mode 100644 index 00000000000..bf4155fef8e --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch @@ -0,0 +1,129 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:22 +0000 +Subject: [PATCH v2 for-4.9 09/40] scsi: ibmvscsis: Synchronize cmds at remove time +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-9-alexander.levin@verizon.com> + +From: Michael Cyr + +[ 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 +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 39 +++++++++++++++++++++++++++---- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h | 3 ++ + 2 files changed, 37 insertions(+), 5 deletions(-) + +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +@@ -470,6 +470,18 @@ static void ibmvscsis_disconnect(struct + + case WAIT_ENABLED: + switch (new_state) { ++ case UNCONFIGURING: ++ vscsi->state = new_state; ++ vscsi->flags |= RESPONSE_Q_DOWN; ++ vscsi->flags &= ~(SCHEDULE_DISCONNECT | ++ DISCONNECT_SCHEDULED); ++ dma_rmb(); ++ if (vscsi->flags & CFG_SLEEPING) { ++ vscsi->flags &= ~CFG_SLEEPING; ++ complete(&vscsi->unconfig); ++ } ++ break; ++ + /* should never happen */ + case ERR_DISCONNECT: + case ERR_DISCONNECT_RECONNECT: +@@ -482,6 +494,13 @@ static void ibmvscsis_disconnect(struct + + case WAIT_IDLE: + switch (new_state) { ++ case UNCONFIGURING: ++ vscsi->flags |= RESPONSE_Q_DOWN; ++ vscsi->state = new_state; ++ vscsi->flags &= ~(SCHEDULE_DISCONNECT | ++ DISCONNECT_SCHEDULED); ++ ibmvscsis_free_command_q(vscsi); ++ break; + case ERR_DISCONNECT: + case ERR_DISCONNECT_RECONNECT: + vscsi->state = new_state; +@@ -1187,6 +1206,15 @@ static void ibmvscsis_adapter_idle(struc + free_qs = true; + + switch (vscsi->state) { ++ case UNCONFIGURING: ++ ibmvscsis_free_command_q(vscsi); ++ dma_rmb(); ++ isync(); ++ if (vscsi->flags & CFG_SLEEPING) { ++ vscsi->flags &= ~CFG_SLEEPING; ++ complete(&vscsi->unconfig); ++ } ++ break; + case ERR_DISCONNECT_RECONNECT: + ibmvscsis_reset_queue(vscsi); + pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags); +@@ -3342,6 +3370,7 @@ static int ibmvscsis_probe(struct vio_de + (unsigned long)vscsi); + + init_completion(&vscsi->wait_idle); ++ init_completion(&vscsi->unconfig); + + snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev)); + vscsi->work_q = create_workqueue(wq_name); +@@ -3397,10 +3426,11 @@ static int ibmvscsis_remove(struct vio_d + + pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev)); + +- /* +- * TBD: Need to handle if there are commands on the waiting_rsp q +- * Actually, can there still be cmds outstanding to tcm? +- */ ++ spin_lock_bh(&vscsi->intr_lock); ++ ibmvscsis_post_disconnect(vscsi, UNCONFIGURING, 0); ++ vscsi->flags |= CFG_SLEEPING; ++ spin_unlock_bh(&vscsi->intr_lock); ++ wait_for_completion(&vscsi->unconfig); + + vio_disable_interrupts(vdev); + free_irq(vdev->irq, vscsi); +@@ -3409,7 +3439,6 @@ static int ibmvscsis_remove(struct vio_d + DMA_BIDIRECTIONAL); + kfree(vscsi->map_buf); + tasklet_kill(&vscsi->work_task); +- ibmvscsis_unregister_command_q(vscsi); + ibmvscsis_destroy_command_q(vscsi); + ibmvscsis_freetimer(vscsi); + ibmvscsis_free_cmds(vscsi); +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +@@ -257,6 +257,8 @@ struct scsi_info { + #define SCHEDULE_DISCONNECT 0x00400 + /* disconnect handler is scheduled */ + #define DISCONNECT_SCHEDULED 0x00800 ++ /* remove function is sleeping */ ++#define CFG_SLEEPING 0x01000 + u32 flags; + /* adapter lock */ + spinlock_t intr_lock; +@@ -285,6 +287,7 @@ struct scsi_info { + + struct workqueue_struct *work_q; + struct completion wait_idle; ++ struct completion unconfig; + struct device dev; + struct vio_dev *dma_dev; + struct srp_target target; diff --git a/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch new file mode 100644 index 00000000000..6da2093b9be --- /dev/null +++ b/queue-4.9/scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch @@ -0,0 +1,475 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:21 +0000 +Subject: [PATCH v2 for-4.9 08/40] scsi: ibmvscsis: Synchronize cmds at tpg_enable_store time +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-8-alexander.levin@verizon.com> + +From: Michael Cyr + +[ 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 +Signed-off-by: Bryant G. Ly +Tested-by: Steven Royer +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 224 +++++-------------------------- + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h | 2 + 2 files changed, 38 insertions(+), 188 deletions(-) + +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +@@ -62,8 +62,6 @@ static long ibmvscsis_parse_command(stru + + static void ibmvscsis_adapter_idle(struct scsi_info *vscsi); + +-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state); +- + static void ibmvscsis_determine_resid(struct se_cmd *se_cmd, + struct srp_rsp *rsp) + { +@@ -418,7 +416,6 @@ static void ibmvscsis_disconnect(struct + proc_work); + u16 new_state; + bool wait_idle = false; +- long rc = ADAPT_SUCCESS; + + spin_lock_bh(&vscsi->intr_lock); + new_state = vscsi->new_state; +@@ -471,30 +468,12 @@ static void ibmvscsis_disconnect(struct + vscsi->state = new_state; + break; + +- /* +- * If this is a transition into an error state. +- * a client is attempting to establish a connection +- * and has violated the RPA protocol. +- * There can be nothing pending on the adapter although +- * there can be requests in the command queue. +- */ + case WAIT_ENABLED: +- case PART_UP_WAIT_ENAB: + switch (new_state) { ++ /* should never happen */ + case ERR_DISCONNECT: +- vscsi->flags |= RESPONSE_Q_DOWN; +- vscsi->state = new_state; +- vscsi->flags &= ~(SCHEDULE_DISCONNECT | +- DISCONNECT_SCHEDULED); +- ibmvscsis_free_command_q(vscsi); +- break; + case ERR_DISCONNECT_RECONNECT: +- ibmvscsis_reset_queue(vscsi, WAIT_ENABLED); +- break; +- +- /* should never happen */ + case WAIT_IDLE: +- rc = ERROR; + dev_err(&vscsi->dev, "disconnect: invalid state %d for WAIT_IDLE\n", + vscsi->state); + break; +@@ -631,7 +610,6 @@ static void ibmvscsis_post_disconnect(st + break; + + case WAIT_ENABLED: +- case PART_UP_WAIT_ENAB: + case WAIT_IDLE: + case WAIT_CONNECTION: + case CONNECTED: +@@ -676,7 +654,6 @@ static long ibmvscsis_handle_init_compl_ + case SRP_PROCESSING: + case CONNECTED: + case WAIT_ENABLED: +- case PART_UP_WAIT_ENAB: + default: + rc = ERROR; + dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n", +@@ -699,10 +676,6 @@ static long ibmvscsis_handle_init_msg(st + long rc = ADAPT_SUCCESS; + + switch (vscsi->state) { +- case WAIT_ENABLED: +- vscsi->state = PART_UP_WAIT_ENAB; +- break; +- + case WAIT_CONNECTION: + rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG); + switch (rc) { +@@ -738,7 +711,7 @@ static long ibmvscsis_handle_init_msg(st + case UNCONFIGURING: + break; + +- case PART_UP_WAIT_ENAB: ++ case WAIT_ENABLED: + case CONNECTED: + case SRP_PROCESSING: + case WAIT_IDLE: +@@ -801,11 +774,10 @@ static long ibmvscsis_init_msg(struct sc + /** + * ibmvscsis_establish_new_q() - Establish new CRQ queue + * @vscsi: Pointer to our adapter structure +- * @new_state: New state being established after resetting the queue + * + * Must be called with interrupt lock held. + */ +-static long ibmvscsis_establish_new_q(struct scsi_info *vscsi, uint new_state) ++static long ibmvscsis_establish_new_q(struct scsi_info *vscsi) + { + long rc = ADAPT_SUCCESS; + uint format; +@@ -817,19 +789,19 @@ static long ibmvscsis_establish_new_q(st + + rc = vio_enable_interrupts(vscsi->dma_dev); + if (rc) { +- pr_warn("reset_queue: failed to enable interrupts, rc %ld\n", ++ pr_warn("establish_new_q: failed to enable interrupts, rc %ld\n", + rc); + return rc; + } + + rc = ibmvscsis_check_init_msg(vscsi, &format); + if (rc) { +- dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n", ++ dev_err(&vscsi->dev, "establish_new_q: check_init_msg failed, rc %ld\n", + rc); + return rc; + } + +- if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) { ++ if (format == UNUSED_FORMAT) { + rc = ibmvscsis_send_init_message(vscsi, INIT_MSG); + switch (rc) { + case H_SUCCESS: +@@ -847,6 +819,8 @@ static long ibmvscsis_establish_new_q(st + rc = H_HARDWARE; + break; + } ++ } else if (format == INIT_MSG) { ++ rc = ibmvscsis_handle_init_msg(vscsi); + } + + return rc; +@@ -855,7 +829,6 @@ static long ibmvscsis_establish_new_q(st + /** + * ibmvscsis_reset_queue() - Reset CRQ Queue + * @vscsi: Pointer to our adapter structure +- * @new_state: New state to establish after resetting the queue + * + * This function calls h_free_q and then calls h_reg_q and does all + * of the bookkeeping to get us back to where we can communicate. +@@ -872,7 +845,7 @@ static long ibmvscsis_establish_new_q(st + * EXECUTION ENVIRONMENT: + * Process environment, called with interrupt lock held + */ +-static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state) ++static void ibmvscsis_reset_queue(struct scsi_info *vscsi) + { + int bytes; + long rc = ADAPT_SUCCESS; +@@ -885,19 +858,18 @@ static void ibmvscsis_reset_queue(struct + vscsi->rsp_q_timer.timer_pops = 0; + vscsi->debit = 0; + vscsi->credit = 0; +- vscsi->state = new_state; ++ vscsi->state = WAIT_CONNECTION; + vio_enable_interrupts(vscsi->dma_dev); + } else { + rc = ibmvscsis_free_command_q(vscsi); + if (rc == ADAPT_SUCCESS) { +- vscsi->state = new_state; ++ vscsi->state = WAIT_CONNECTION; + + bytes = vscsi->cmd_q.size * PAGE_SIZE; + rc = h_reg_crq(vscsi->dds.unit_id, + vscsi->cmd_q.crq_token, bytes); + if (rc == H_CLOSED || rc == H_SUCCESS) { +- rc = ibmvscsis_establish_new_q(vscsi, +- new_state); ++ rc = ibmvscsis_establish_new_q(vscsi); + } + + if (rc != ADAPT_SUCCESS) { +@@ -1016,10 +988,6 @@ static long ibmvscsis_trans_event(struct + TRANS_EVENT)); + break; + +- case PART_UP_WAIT_ENAB: +- vscsi->state = WAIT_ENABLED; +- break; +- + case SRP_PROCESSING: + if ((vscsi->debit > 0) || + !list_empty(&vscsi->schedule_q) || +@@ -1220,15 +1188,18 @@ static void ibmvscsis_adapter_idle(struc + + switch (vscsi->state) { + case ERR_DISCONNECT_RECONNECT: +- ibmvscsis_reset_queue(vscsi, WAIT_CONNECTION); ++ ibmvscsis_reset_queue(vscsi); + pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags); + break; + + case ERR_DISCONNECT: + ibmvscsis_free_command_q(vscsi); +- vscsi->flags &= ~DISCONNECT_SCHEDULED; ++ vscsi->flags &= ~(SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED); + vscsi->flags |= RESPONSE_Q_DOWN; +- vscsi->state = ERR_DISCONNECTED; ++ if (vscsi->tport.enabled) ++ vscsi->state = ERR_DISCONNECTED; ++ else ++ vscsi->state = WAIT_ENABLED; + pr_debug("adapter_idle, disc: flags 0x%x, state 0x%hx\n", + vscsi->flags, vscsi->state); + break; +@@ -1773,8 +1744,8 @@ static void ibmvscsis_send_messages(stru + be64_to_cpu(msg_hi), + be64_to_cpu(cmd->rsp.tag)); + +- pr_debug("send_messages: tag 0x%llx, rc %ld\n", +- be64_to_cpu(cmd->rsp.tag), rc); ++ pr_debug("send_messages: cmd %p, tag 0x%llx, rc %ld\n", ++ cmd, be64_to_cpu(cmd->rsp.tag), rc); + + /* if all ok free up the command element resources */ + if (rc == H_SUCCESS) { +@@ -2788,36 +2759,6 @@ static irqreturn_t ibmvscsis_interrupt(i + } + + /** +- * ibmvscsis_check_q() - Helper function to Check Init Message Valid +- * @vscsi: Pointer to our adapter structure +- * +- * Checks if a initialize message was queued by the initiatior +- * while the timing window was open. This function is called from +- * probe after the CRQ is created and interrupts are enabled. +- * It would only be used by adapters who wait for some event before +- * completing the init handshake with the client. For ibmvscsi, this +- * event is waiting for the port to be enabled. +- * +- * EXECUTION ENVIRONMENT: +- * Process level only, interrupt lock held +- */ +-static long ibmvscsis_check_q(struct scsi_info *vscsi) +-{ +- uint format; +- long rc; +- +- rc = ibmvscsis_check_init_msg(vscsi, &format); +- if (rc) +- ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0); +- else if (format == UNUSED_FORMAT) +- vscsi->state = WAIT_ENABLED; +- else +- vscsi->state = PART_UP_WAIT_ENAB; +- +- return rc; +-} +- +-/** + * ibmvscsis_enable_change_state() - Set new state based on enabled status + * @vscsi: Pointer to our adapter structure + * +@@ -2828,77 +2769,19 @@ static long ibmvscsis_check_q(struct scs + */ + static long ibmvscsis_enable_change_state(struct scsi_info *vscsi) + { ++ int bytes; + long rc = ADAPT_SUCCESS; + +-handle_state_change: +- switch (vscsi->state) { +- case WAIT_ENABLED: +- rc = ibmvscsis_send_init_message(vscsi, INIT_MSG); +- switch (rc) { +- case H_SUCCESS: +- case H_DROPPED: +- case H_CLOSED: +- vscsi->state = WAIT_CONNECTION; +- rc = ADAPT_SUCCESS; +- break; +- +- case H_PARAMETER: +- break; +- +- case H_HARDWARE: +- break; +- +- default: +- vscsi->state = UNDEFINED; +- rc = H_HARDWARE; +- break; +- } +- break; +- case PART_UP_WAIT_ENAB: +- rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG); +- switch (rc) { +- case H_SUCCESS: +- vscsi->state = CONNECTED; +- rc = ADAPT_SUCCESS; +- break; +- +- case H_DROPPED: +- case H_CLOSED: +- vscsi->state = WAIT_ENABLED; +- goto handle_state_change; +- +- case H_PARAMETER: +- break; +- +- case H_HARDWARE: +- break; +- +- default: +- rc = H_HARDWARE; +- break; +- } +- break; +- +- case WAIT_CONNECTION: +- case WAIT_IDLE: +- case SRP_PROCESSING: +- case CONNECTED: +- rc = ADAPT_SUCCESS; +- break; +- /* should not be able to get here */ +- case UNCONFIGURING: +- rc = ERROR; +- vscsi->state = UNDEFINED; +- break; ++ bytes = vscsi->cmd_q.size * PAGE_SIZE; ++ rc = h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, bytes); ++ if (rc == H_CLOSED || rc == H_SUCCESS) { ++ vscsi->state = WAIT_CONNECTION; ++ rc = ibmvscsis_establish_new_q(vscsi); ++ } + +- /* driver should never allow this to happen */ +- case ERR_DISCONNECT: +- case ERR_DISCONNECT_RECONNECT: +- default: +- dev_err(&vscsi->dev, "in invalid state %d during enable_change_state\n", +- vscsi->state); +- rc = ADAPT_SUCCESS; +- break; ++ if (rc != ADAPT_SUCCESS) { ++ vscsi->state = ERR_DISCONNECTED; ++ vscsi->flags |= RESPONSE_Q_DOWN; + } + + return rc; +@@ -2918,7 +2801,6 @@ handle_state_change: + */ + static long ibmvscsis_create_command_q(struct scsi_info *vscsi, int num_cmds) + { +- long rc = 0; + int pages; + struct vio_dev *vdev = vscsi->dma_dev; + +@@ -2942,22 +2824,7 @@ static long ibmvscsis_create_command_q(s + return -ENOMEM; + } + +- rc = h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, PAGE_SIZE); +- if (rc) { +- if (rc == H_CLOSED) { +- vscsi->state = WAIT_ENABLED; +- rc = 0; +- } else { +- dma_unmap_single(&vdev->dev, vscsi->cmd_q.crq_token, +- PAGE_SIZE, DMA_BIDIRECTIONAL); +- free_page((unsigned long)vscsi->cmd_q.base_addr); +- rc = -ENODEV; +- } +- } else { +- vscsi->state = WAIT_ENABLED; +- } +- +- return rc; ++ return 0; + } + + /** +@@ -3491,31 +3358,12 @@ static int ibmvscsis_probe(struct vio_de + goto destroy_WQ; + } + +- spin_lock_bh(&vscsi->intr_lock); +- vio_enable_interrupts(vdev); +- if (rc) { +- dev_err(&vscsi->dev, "enabling interrupts failed, rc %d\n", rc); +- rc = -ENODEV; +- spin_unlock_bh(&vscsi->intr_lock); +- goto free_irq; +- } +- +- if (ibmvscsis_check_q(vscsi)) { +- rc = ERROR; +- dev_err(&vscsi->dev, "probe: check_q failed, rc %d\n", rc); +- spin_unlock_bh(&vscsi->intr_lock); +- goto disable_interrupt; +- } +- spin_unlock_bh(&vscsi->intr_lock); ++ vscsi->state = WAIT_ENABLED; + + dev_set_drvdata(&vdev->dev, vscsi); + + return 0; + +-disable_interrupt: +- vio_disable_interrupts(vdev); +-free_irq: +- free_irq(vdev->irq, vscsi); + destroy_WQ: + destroy_workqueue(vscsi->work_q); + unmap_buf: +@@ -3909,18 +3757,22 @@ static ssize_t ibmvscsis_tpg_enable_stor + } + + if (tmp) { +- tport->enabled = true; + spin_lock_bh(&vscsi->intr_lock); ++ tport->enabled = true; + lrc = ibmvscsis_enable_change_state(vscsi); + if (lrc) + pr_err("enable_change_state failed, rc %ld state %d\n", + lrc, vscsi->state); + spin_unlock_bh(&vscsi->intr_lock); + } else { ++ spin_lock_bh(&vscsi->intr_lock); + tport->enabled = false; ++ /* This simulates the server going down */ ++ ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0); ++ spin_unlock_bh(&vscsi->intr_lock); + } + +- pr_debug("tpg_enable_store, state %d\n", vscsi->state); ++ pr_debug("tpg_enable_store, tmp %ld, state %d\n", tmp, vscsi->state); + + return count; + } +--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h ++++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +@@ -204,8 +204,6 @@ struct scsi_info { + struct list_head waiting_rsp; + #define NO_QUEUE 0x00 + #define WAIT_ENABLED 0X01 +- /* driver has received an initialize command */ +-#define PART_UP_WAIT_ENAB 0x02 + #define WAIT_CONNECTION 0x04 + /* have established a connection */ + #define CONNECTED 0x08 diff --git a/queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch b/queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch new file mode 100644 index 00000000000..36ba139f45e --- /dev/null +++ b/queue-4.9/serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch @@ -0,0 +1,108 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:32 +0000 +Subject: [PATCH v2 for-4.9 37/40] serial: 8250_pci: Detach low-level driver during PCI error recovery +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-37-alexander.levin@verizon.com> + +From: Gabriel Krisman Bertazi + +[ 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 for valuable input on +this one over one year ago. + +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 = { diff --git a/queue-4.9/series b/queue-4.9/series index 599fe307cc1..847391f3822 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -40,3 +40,42 @@ bpf-fix-state-equivalence.patch bpf-fix-regression-on-verifier-pruning-wrt-map-lookups.patch bpf-fix-mark_reg_unknown_value-for-spilled-regs-on-map-value-marking.patch dmaengine-iota-ioat_alloc_chan_resources-should-not-perform-sleeping-allocations.patch +xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch +igb-workaround-for-igb-i210-firmware-issue.patch +igb-add-i211-to-i210-phy-workaround.patch +scsi-ibmvscsis-issues-from-dan-carpenter-smatch.patch +scsi-ibmvscsis-return-correct-partition-name-to-client.patch +scsi-ibmvscsis-clean-up-properly-if-target_submit_cmd-tmr-fails.patch +scsi-ibmvscsis-rearrange-functions-for-future-patches.patch +scsi-ibmvscsis-synchronize-cmds-at-tpg_enable_store-time.patch +scsi-ibmvscsis-synchronize-cmds-at-remove-time.patch +x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch +pci-separate-vf-bar-updates-from-standard-bar-updates.patch +pci-remove-pci_resource_bar-and-pci_iov_resource_bar.patch +pci-add-comments-about-rom-bar-updating.patch +pci-decouple-ioresource_rom_enable-and-pci_rom_address_enable.patch +pci-don-t-update-vf-bars-while-vf-memory-space-is-enabled.patch +pci-update-bars-using-property-bits-appropriate-for-type.patch +pci-ignore-bar-updates-on-virtual-functions.patch +pci-do-any-vf-bar-updates-before-enabling-the-bars.patch +ibmveth-calculate-gso_segs-for-large-packets.patch +drivers-hv-ring_buffer-count-on-wrap-around-mappings-in-get_next_pkt_raw-v2.patch +vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch +powerpc-iommu-pass-mm_struct-to-init-cleanup-helpers.patch +powerpc-iommu-stop-using-current-in-mm_iommu_xxx.patch +vfio-spapr-reference-mm-in-tce_container.patch +powerpc-mm-iommu-vfio-spapr-put-pages-on-vfio-container-shutdown.patch +vfio-spapr-add-a-helper-to-create-default-dma-window.patch +vfio-spapr-postpone-default-window-creation.patch +drm-nouveau-disp-gp102-fix-cursor-overlay-immediate-channel-indices.patch +drm-nouveau-disp-nv50-split-chid-into-chid.ctrl-and-chid.user.patch +drm-nouveau-disp-nv50-specify-ctrl-user-separately-when-constructing-classes.patch +block-allow-write_same-commands-with-the-sg_io-ioctl.patch +s390-zcrypt-introduce-cex6-toleration.patch +uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch +slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch +acpi-blacklist-add-_rev-quirks-for-dell-precision-5520-and-3520.patch +acpi-blacklist-make-dell-latitude-3350-ethernet-work.patch +serial-8250_pci-detach-low-level-driver-during-pci-error-recovery.patch +usb-gadget-udc-atmel-remove-memory-leak.patch +powerpc-mm-fix-build-break-when-cma-n-spapr_tce_iommu-y.patch diff --git a/queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch b/queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch new file mode 100644 index 00000000000..5d144666528 --- /dev/null +++ b/queue-4.9/slub-move-synchronize_sched-out-of-slab_mutex-on-shrink.patch @@ -0,0 +1,179 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:31 +0000 +Subject: [PATCH v2 for-4.9 34/40] slub: move synchronize_sched out of slab_mutex on shrink +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-34-alexander.levin@verizon.com> + +From: Vladimir Davydov + +[ 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 +Reported-by: Doug Smythies +Acked-by: Joonsoo Kim +Cc: Christoph Lameter +Cc: David Rientjes +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Pekka Enberg +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/slab.c | 4 ++-- + mm/slab.h | 2 +- + mm/slab_common.c | 27 +++++++++++++++++++++++++-- + mm/slob.c | 2 +- + mm/slub.c | 19 ++----------------- + 5 files changed, 31 insertions(+), 23 deletions(-) + +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -2332,7 +2332,7 @@ out: + return nr_freed; + } + +-int __kmem_cache_shrink(struct kmem_cache *cachep, bool deactivate) ++int __kmem_cache_shrink(struct kmem_cache *cachep) + { + int ret = 0; + int node; +@@ -2352,7 +2352,7 @@ int __kmem_cache_shrink(struct kmem_cach + + int __kmem_cache_shutdown(struct kmem_cache *cachep) + { +- return __kmem_cache_shrink(cachep, false); ++ return __kmem_cache_shrink(cachep); + } + + void __kmem_cache_release(struct kmem_cache *cachep) +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -146,7 +146,7 @@ static inline unsigned long kmem_cache_f + + int __kmem_cache_shutdown(struct kmem_cache *); + void __kmem_cache_release(struct kmem_cache *); +-int __kmem_cache_shrink(struct kmem_cache *, bool); ++int __kmem_cache_shrink(struct kmem_cache *); + void slab_kmem_cache_release(struct kmem_cache *); + + struct seq_file; +--- a/mm/slab_common.c ++++ b/mm/slab_common.c +@@ -573,6 +573,29 @@ void memcg_deactivate_kmem_caches(struct + get_online_cpus(); + get_online_mems(); + ++#ifdef CONFIG_SLUB ++ /* ++ * In case of SLUB, we need to disable empty slab caching to ++ * avoid pinning the offline memory cgroup by freeable kmem ++ * pages charged to it. SLAB doesn't need this, as it ++ * periodically purges unused slabs. ++ */ ++ mutex_lock(&slab_mutex); ++ list_for_each_entry(s, &slab_caches, list) { ++ c = is_root_cache(s) ? cache_from_memcg_idx(s, idx) : NULL; ++ if (c) { ++ c->cpu_partial = 0; ++ c->min_partial = 0; ++ } ++ } ++ mutex_unlock(&slab_mutex); ++ /* ++ * kmem_cache->cpu_partial is checked locklessly (see ++ * put_cpu_partial()). Make sure the change is visible. ++ */ ++ synchronize_sched(); ++#endif ++ + mutex_lock(&slab_mutex); + list_for_each_entry(s, &slab_caches, list) { + if (!is_root_cache(s)) +@@ -584,7 +607,7 @@ void memcg_deactivate_kmem_caches(struct + if (!c) + continue; + +- __kmem_cache_shrink(c, true); ++ __kmem_cache_shrink(c); + arr->entries[idx] = NULL; + } + mutex_unlock(&slab_mutex); +@@ -755,7 +778,7 @@ int kmem_cache_shrink(struct kmem_cache + get_online_cpus(); + get_online_mems(); + kasan_cache_shrink(cachep); +- ret = __kmem_cache_shrink(cachep, false); ++ ret = __kmem_cache_shrink(cachep); + put_online_mems(); + put_online_cpus(); + return ret; +--- a/mm/slob.c ++++ b/mm/slob.c +@@ -634,7 +634,7 @@ void __kmem_cache_release(struct kmem_ca + { + } + +-int __kmem_cache_shrink(struct kmem_cache *d, bool deactivate) ++int __kmem_cache_shrink(struct kmem_cache *d) + { + return 0; + } +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -3887,7 +3887,7 @@ EXPORT_SYMBOL(kfree); + * being allocated from last increasing the chance that the last objects + * are freed in them. + */ +-int __kmem_cache_shrink(struct kmem_cache *s, bool deactivate) ++int __kmem_cache_shrink(struct kmem_cache *s) + { + int node; + int i; +@@ -3899,21 +3899,6 @@ int __kmem_cache_shrink(struct kmem_cach + unsigned long flags; + int ret = 0; + +- if (deactivate) { +- /* +- * Disable empty slabs caching. Used to avoid pinning offline +- * memory cgroups by kmem pages that can be freed. +- */ +- s->cpu_partial = 0; +- s->min_partial = 0; +- +- /* +- * s->cpu_partial is checked locklessly (see put_cpu_partial), +- * so we have to make sure the change is visible. +- */ +- synchronize_sched(); +- } +- + flush_all(s); + for_each_kmem_cache_node(s, node, n) { + INIT_LIST_HEAD(&discard); +@@ -3970,7 +3955,7 @@ static int slab_mem_going_offline_callba + + mutex_lock(&slab_mutex); + list_for_each_entry(s, &slab_caches, list) +- __kmem_cache_shrink(s, false); ++ __kmem_cache_shrink(s); + mutex_unlock(&slab_mutex); + + return 0; diff --git a/queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch b/queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch new file mode 100644 index 00000000000..05ef20cd3c0 --- /dev/null +++ b/queue-4.9/usb-gadget-udc-atmel-remove-memory-leak.patch @@ -0,0 +1,48 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:33 +0000 +Subject: [PATCH v2 for-4.9 39/40] usb: gadget: udc: atmel: remove memory leak +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-39-alexander.levin@verizon.com> + +From: Alexandre Belloni + +[ 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 +Signed-off-by: Felipe Balbi +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/udc/atmel_usba_udc.c | 3 ++- + drivers/usb/gadget/udc/atmel_usba_udc.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/gadget/udc/atmel_usba_udc.c ++++ b/drivers/usb/gadget/udc/atmel_usba_udc.c +@@ -1978,7 +1978,8 @@ static struct usba_ep * atmel_udc_of_ini + dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); + goto err; + } +- ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index); ++ sprintf(ep->name, "ep%d", ep->index); ++ ep->ep.name = ep->name; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); +--- a/drivers/usb/gadget/udc/atmel_usba_udc.h ++++ b/drivers/usb/gadget/udc/atmel_usba_udc.h +@@ -280,6 +280,7 @@ struct usba_ep { + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; ++ char name[8]; + struct usb_ep ep; + struct usba_udc *udc; + diff --git a/queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch b/queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch new file mode 100644 index 00000000000..f2ef85ea6b9 --- /dev/null +++ b/queue-4.9/uvcvideo-uvc_scan_fallback-for-webcams-with-broken-chain.patch @@ -0,0 +1,174 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:31 +0000 +Subject: [PATCH v2 for-4.9 33/40] [media] uvcvideo: uvc_scan_fallback() for webcams with broken chain +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-33-alexander.levin@verizon.com> + +From: Henrik Ingo + +[ 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 +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/usb/uvc/uvc_driver.c | 118 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 112 insertions(+), 6 deletions(-) + +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -1595,6 +1595,114 @@ static const char *uvc_print_chain(struc + return buffer; + } + ++static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev) ++{ ++ struct uvc_video_chain *chain; ++ ++ chain = kzalloc(sizeof(*chain), GFP_KERNEL); ++ if (chain == NULL) ++ return NULL; ++ ++ INIT_LIST_HEAD(&chain->entities); ++ mutex_init(&chain->ctrl_mutex); ++ chain->dev = dev; ++ v4l2_prio_init(&chain->prio); ++ ++ return chain; ++} ++ ++/* ++ * Fallback heuristic for devices that don't connect units and terminals in a ++ * valid chain. ++ * ++ * Some devices have invalid baSourceID references, causing uvc_scan_chain() ++ * to fail, but if we just take the entities we can find and put them together ++ * in the most sensible chain we can think of, turns out they do work anyway. ++ * Note: This heuristic assumes there is a single chain. ++ * ++ * At the time of writing, devices known to have such a broken chain are ++ * - Acer Integrated Camera (5986:055a) ++ * - Realtek rtl157a7 (0bda:57a7) ++ */ ++static int uvc_scan_fallback(struct uvc_device *dev) ++{ ++ struct uvc_video_chain *chain; ++ struct uvc_entity *iterm = NULL; ++ struct uvc_entity *oterm = NULL; ++ struct uvc_entity *entity; ++ struct uvc_entity *prev; ++ ++ /* ++ * Start by locating the input and output terminals. We only support ++ * devices with exactly one of each for now. ++ */ ++ list_for_each_entry(entity, &dev->entities, list) { ++ if (UVC_ENTITY_IS_ITERM(entity)) { ++ if (iterm) ++ return -EINVAL; ++ iterm = entity; ++ } ++ ++ if (UVC_ENTITY_IS_OTERM(entity)) { ++ if (oterm) ++ return -EINVAL; ++ oterm = entity; ++ } ++ } ++ ++ if (iterm == NULL || oterm == NULL) ++ return -EINVAL; ++ ++ /* Allocate the chain and fill it. */ ++ chain = uvc_alloc_chain(dev); ++ if (chain == NULL) ++ return -ENOMEM; ++ ++ if (uvc_scan_chain_entity(chain, oterm) < 0) ++ goto error; ++ ++ prev = oterm; ++ ++ /* ++ * Add all Processing and Extension Units with two pads. The order ++ * doesn't matter much, use reverse list traversal to connect units in ++ * UVC descriptor order as we build the chain from output to input. This ++ * leads to units appearing in the order meant by the manufacturer for ++ * the cameras known to require this heuristic. ++ */ ++ list_for_each_entry_reverse(entity, &dev->entities, list) { ++ if (entity->type != UVC_VC_PROCESSING_UNIT && ++ entity->type != UVC_VC_EXTENSION_UNIT) ++ continue; ++ ++ if (entity->num_pads != 2) ++ continue; ++ ++ if (uvc_scan_chain_entity(chain, entity) < 0) ++ goto error; ++ ++ prev->baSourceID[0] = entity->id; ++ prev = entity; ++ } ++ ++ if (uvc_scan_chain_entity(chain, iterm) < 0) ++ goto error; ++ ++ prev->baSourceID[0] = iterm->id; ++ ++ list_add_tail(&chain->list, &dev->chains); ++ ++ uvc_trace(UVC_TRACE_PROBE, ++ "Found a video chain by fallback heuristic (%s).\n", ++ uvc_print_chain(chain)); ++ ++ return 0; ++ ++error: ++ kfree(chain); ++ return -EINVAL; ++} ++ + /* + * Scan the device for video chains and register video devices. + * +@@ -1617,15 +1725,10 @@ static int uvc_scan_device(struct uvc_de + if (term->chain.next || term->chain.prev) + continue; + +- chain = kzalloc(sizeof(*chain), GFP_KERNEL); ++ chain = uvc_alloc_chain(dev); + if (chain == NULL) + return -ENOMEM; + +- INIT_LIST_HEAD(&chain->entities); +- mutex_init(&chain->ctrl_mutex); +- chain->dev = dev; +- v4l2_prio_init(&chain->prio); +- + term->flags |= UVC_ENTITY_FLAG_DEFAULT; + + if (uvc_scan_chain(chain, term) < 0) { +@@ -1639,6 +1742,9 @@ static int uvc_scan_device(struct uvc_de + list_add_tail(&chain->list, &dev->chains); + } + ++ if (list_empty(&dev->chains)) ++ uvc_scan_fallback(dev); ++ + if (list_empty(&dev->chains)) { + uvc_printk(KERN_INFO, "No valid video chain found.\n"); + return -1; diff --git a/queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch b/queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch new file mode 100644 index 00000000000..83901e32386 --- /dev/null +++ b/queue-4.9/vfio-spapr-add-a-helper-to-create-default-dma-window.patch @@ -0,0 +1,167 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:28 +0000 +Subject: [PATCH v2 for-4.9 26/40] vfio/spapr: Add a helper to create default DMA window +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-26-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: David Gibson +Acked-by: Alex Williamson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vfio/vfio_iommu_spapr_tce.c | 87 +++++++++++++++++------------------- + 1 file changed, 42 insertions(+), 45 deletions(-) + +--- a/drivers/vfio/vfio_iommu_spapr_tce.c ++++ b/drivers/vfio/vfio_iommu_spapr_tce.c +@@ -784,6 +784,29 @@ static long tce_iommu_remove_window(stru + return 0; + } + ++static long tce_iommu_create_default_window(struct tce_container *container) ++{ ++ long ret; ++ __u64 start_addr = 0; ++ struct tce_iommu_group *tcegrp; ++ struct iommu_table_group *table_group; ++ ++ if (!tce_groups_attached(container)) ++ return -ENODEV; ++ ++ tcegrp = list_first_entry(&container->group_list, ++ struct tce_iommu_group, next); ++ table_group = iommu_group_get_iommudata(tcegrp->grp); ++ if (!table_group) ++ return -ENODEV; ++ ++ ret = tce_iommu_create_window(container, IOMMU_PAGE_SHIFT_4K, ++ table_group->tce32_size, 1, &start_addr); ++ WARN_ON_ONCE(!ret && start_addr); ++ ++ return ret; ++} ++ + static long tce_iommu_ioctl(void *iommu_data, + unsigned int cmd, unsigned long arg) + { +@@ -1199,9 +1222,6 @@ static void tce_iommu_release_ownership_ + static long tce_iommu_take_ownership_ddw(struct tce_container *container, + struct iommu_table_group *table_group) + { +- long i, ret = 0; +- struct iommu_table *tbl = NULL; +- + if (!table_group->ops->create_table || !table_group->ops->set_window || + !table_group->ops->release_ownership) { + WARN_ON_ONCE(1); +@@ -1210,47 +1230,7 @@ static long tce_iommu_take_ownership_ddw + + table_group->ops->take_ownership(table_group); + +- /* +- * If it the first group attached, check if there is +- * a default DMA window and create one if none as +- * the userspace expects it to exist. +- */ +- if (!tce_groups_attached(container) && !container->tables[0]) { +- ret = tce_iommu_create_table(container, +- table_group, +- 0, /* window number */ +- IOMMU_PAGE_SHIFT_4K, +- table_group->tce32_size, +- 1, /* default levels */ +- &tbl); +- if (ret) +- goto release_exit; +- else +- container->tables[0] = tbl; +- } +- +- /* Set all windows to the new group */ +- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { +- tbl = container->tables[i]; +- +- if (!tbl) +- continue; +- +- /* Set the default window to a new group */ +- ret = table_group->ops->set_window(table_group, i, tbl); +- if (ret) +- goto release_exit; +- } +- + return 0; +- +-release_exit: +- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) +- table_group->ops->unset_window(table_group, i); +- +- table_group->ops->release_ownership(table_group); +- +- return ret; + } + + static int tce_iommu_attach_group(void *iommu_data, +@@ -1260,6 +1240,7 @@ static int tce_iommu_attach_group(void * + struct tce_container *container = iommu_data; + struct iommu_table_group *table_group; + struct tce_iommu_group *tcegrp = NULL; ++ bool create_default_window = false; + + mutex_lock(&container->lock); + +@@ -1302,14 +1283,30 @@ static int tce_iommu_attach_group(void * + } + + if (!table_group->ops || !table_group->ops->take_ownership || +- !table_group->ops->release_ownership) ++ !table_group->ops->release_ownership) { + ret = tce_iommu_take_ownership(container, table_group); +- else ++ } else { + ret = tce_iommu_take_ownership_ddw(container, table_group); ++ if (!tce_groups_attached(container) && !container->tables[0]) ++ create_default_window = true; ++ } + + if (!ret) { + tcegrp->grp = iommu_group; + list_add(&tcegrp->next, &container->group_list); ++ /* ++ * If it the first group attached, check if there is ++ * a default DMA window and create one if none as ++ * the userspace expects it to exist. ++ */ ++ if (create_default_window) { ++ ret = tce_iommu_create_default_window(container); ++ if (ret) { ++ list_del(&tcegrp->next); ++ tce_iommu_release_ownership_ddw(container, ++ table_group); ++ } ++ } + } + + unlock_exit: diff --git a/queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch b/queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch new file mode 100644 index 00000000000..1d6c42ad3df --- /dev/null +++ b/queue-4.9/vfio-spapr-postpone-allocation-of-userspace-version-of-tce-table.patch @@ -0,0 +1,80 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:26 +0000 +Subject: [PATCH v2 for-4.9 21/40] vfio/spapr: Postpone allocation of userspace version of TCE table +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-21-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: David Gibson +Acked-by: Alex Williamson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vfio/vfio_iommu_spapr_tce.c | 20 +++++++------------- + 1 file changed, 7 insertions(+), 13 deletions(-) + +--- a/drivers/vfio/vfio_iommu_spapr_tce.c ++++ b/drivers/vfio/vfio_iommu_spapr_tce.c +@@ -509,6 +509,12 @@ static long tce_iommu_build_v2(struct tc + unsigned long hpa; + enum dma_data_direction dirtmp; + ++ if (!tbl->it_userspace) { ++ ret = tce_iommu_userspace_view_alloc(tbl); ++ if (ret) ++ return ret; ++ } ++ + for (i = 0; i < pages; ++i) { + struct mm_iommu_table_group_mem_t *mem = NULL; + unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, +@@ -582,15 +588,6 @@ static long tce_iommu_create_table(struc + WARN_ON(!ret && !(*ptbl)->it_ops->free); + WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size)); + +- if (!ret && container->v2) { +- ret = tce_iommu_userspace_view_alloc(*ptbl); +- if (ret) +- (*ptbl)->it_ops->free(*ptbl); +- } +- +- if (ret) +- decrement_locked_vm(table_size >> PAGE_SHIFT); +- + return ret; + } + +@@ -1062,10 +1059,7 @@ static int tce_iommu_take_ownership(stru + if (!tbl || !tbl->it_map) + continue; + +- rc = tce_iommu_userspace_view_alloc(tbl); +- if (!rc) +- rc = iommu_take_ownership(tbl); +- ++ rc = iommu_take_ownership(tbl); + if (rc) { + for (j = 0; j < i; ++j) + iommu_release_ownership( diff --git a/queue-4.9/vfio-spapr-postpone-default-window-creation.patch b/queue-4.9/vfio-spapr-postpone-default-window-creation.patch new file mode 100644 index 00000000000..9cd8888c781 --- /dev/null +++ b/queue-4.9/vfio-spapr-postpone-default-window-creation.patch @@ -0,0 +1,150 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:29 +0000 +Subject: [PATCH v2 for-4.9 27/40] vfio/spapr: Postpone default window creation +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-27-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Reviewed-by: David Gibson +Acked-by: Alex Williamson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vfio/vfio_iommu_spapr_tce.c | 40 ++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 15 deletions(-) + +--- a/drivers/vfio/vfio_iommu_spapr_tce.c ++++ b/drivers/vfio/vfio_iommu_spapr_tce.c +@@ -106,6 +106,7 @@ struct tce_container { + struct mutex lock; + bool enabled; + bool v2; ++ bool def_window_pending; + unsigned long locked_pages; + struct mm_struct *mm; + struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; +@@ -791,6 +792,9 @@ static long tce_iommu_create_default_win + struct tce_iommu_group *tcegrp; + struct iommu_table_group *table_group; + ++ if (!container->def_window_pending) ++ return 0; ++ + if (!tce_groups_attached(container)) + return -ENODEV; + +@@ -804,6 +808,9 @@ static long tce_iommu_create_default_win + table_group->tce32_size, 1, &start_addr); + WARN_ON_ONCE(!ret && start_addr); + ++ if (!ret) ++ container->def_window_pending = false; ++ + return ret; + } + +@@ -907,6 +914,10 @@ static long tce_iommu_ioctl(void *iommu_ + VFIO_DMA_MAP_FLAG_WRITE)) + return -EINVAL; + ++ ret = tce_iommu_create_default_window(container); ++ if (ret) ++ return ret; ++ + num = tce_iommu_find_table(container, param.iova, &tbl); + if (num < 0) + return -ENXIO; +@@ -970,6 +981,10 @@ static long tce_iommu_ioctl(void *iommu_ + if (param.flags) + return -EINVAL; + ++ ret = tce_iommu_create_default_window(container); ++ if (ret) ++ return ret; ++ + num = tce_iommu_find_table(container, param.iova, &tbl); + if (num < 0) + return -ENXIO; +@@ -1107,6 +1122,10 @@ static long tce_iommu_ioctl(void *iommu_ + + mutex_lock(&container->lock); + ++ ret = tce_iommu_create_default_window(container); ++ if (ret) ++ return ret; ++ + ret = tce_iommu_create_window(container, create.page_shift, + create.window_size, create.levels, + &create.start_addr); +@@ -1143,6 +1162,11 @@ static long tce_iommu_ioctl(void *iommu_ + if (remove.flags) + return -EINVAL; + ++ if (container->def_window_pending && !remove.start_addr) { ++ container->def_window_pending = false; ++ return 0; ++ } ++ + mutex_lock(&container->lock); + + ret = tce_iommu_remove_window(container, remove.start_addr); +@@ -1240,7 +1264,6 @@ static int tce_iommu_attach_group(void * + struct tce_container *container = iommu_data; + struct iommu_table_group *table_group; + struct tce_iommu_group *tcegrp = NULL; +- bool create_default_window = false; + + mutex_lock(&container->lock); + +@@ -1288,25 +1311,12 @@ static int tce_iommu_attach_group(void * + } else { + ret = tce_iommu_take_ownership_ddw(container, table_group); + if (!tce_groups_attached(container) && !container->tables[0]) +- create_default_window = true; ++ container->def_window_pending = true; + } + + if (!ret) { + tcegrp->grp = iommu_group; + list_add(&tcegrp->next, &container->group_list); +- /* +- * If it the first group attached, check if there is +- * a default DMA window and create one if none as +- * the userspace expects it to exist. +- */ +- if (create_default_window) { +- ret = tce_iommu_create_default_window(container); +- if (ret) { +- list_del(&tcegrp->next); +- tce_iommu_release_ownership_ddw(container, +- table_group); +- } +- } + } + + unlock_exit: diff --git a/queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch b/queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch new file mode 100644 index 00000000000..39feb9bea2b --- /dev/null +++ b/queue-4.9/vfio-spapr-reference-mm-in-tce_container.patch @@ -0,0 +1,485 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:27 +0000 +Subject: [PATCH v2 for-4.9 24/40] vfio/spapr: Reference mm in tce_container +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-24-alexander.levin@verizon.com> + +From: Alexey Kardashevskiy + +[ 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 +Acked-by: Alex Williamson +Reviewed-by: David Gibson +Signed-off-by: Michael Ellerman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); + diff --git a/queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch b/queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch new file mode 100644 index 00000000000..6e1624c72b8 --- /dev/null +++ b/queue-4.9/x86-hyperv-handle-unknown-nmis-on-one-cpu-when-unknown_nmi_panic.patch @@ -0,0 +1,124 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:22 +0000 +Subject: [PATCH v2 for-4.9 10/40] x86/hyperv: Handle unknown NMIs on one CPU when unknown_nmi_panic +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-10-alexander.levin@verizon.com> + +From: Vitaly Kuznetsov + +[ 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 +Acked-by: K. Y. Srinivasan +Cc: devel@linuxdriverproject.org +Cc: Haiyang Zhang +Link: http://lkml.kernel.org/r/20161202100720.28121-1-vkuznets@redhat.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Ingo Molnar +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + + struct ms_hyperv_info ms_hyperv; + EXPORT_SYMBOL_GPL(ms_hyperv); +@@ -158,6 +159,26 @@ static unsigned char hv_get_nmi_reason(v + return 0; + } + ++#ifdef CONFIG_X86_LOCAL_APIC ++/* ++ * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes ++ * it dificult to process CHANNELMSG_UNLOAD in case of crash. Handle ++ * unknown NMI on the first CPU which gets it. ++ */ ++static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs) ++{ ++ static atomic_t nmi_cpu = ATOMIC_INIT(-1); ++ ++ if (!unknown_nmi_panic) ++ return NMI_DONE; ++ ++ if (atomic_cmpxchg(&nmi_cpu, -1, raw_smp_processor_id()) != -1) ++ return NMI_HANDLED; ++ ++ return NMI_DONE; ++} ++#endif ++ + static void __init ms_hyperv_init_platform(void) + { + /* +@@ -183,6 +204,9 @@ static void __init ms_hyperv_init_platfo + pr_info("HyperV: LAPIC Timer Frequency: %#x\n", + lapic_timer_frequency); + } ++ ++ register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST, ++ "hv_nmi_unknown"); + #endif + + if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) diff --git a/queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch b/queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch new file mode 100644 index 00000000000..fcb021f95c6 --- /dev/null +++ b/queue-4.9/xen-do-not-re-use-pirq-number-cached-in-pci-device-msi-msg-data.patch @@ -0,0 +1,85 @@ +From foo@baz Mon Mar 20 11:41:01 CET 2017 +From: alexander.levin@verizon.com +Date: Fri, 17 Mar 2017 00:48:18 +0000 +Subject: [PATCH v2 for-4.9 01/40] xen: do not re-use pirq number cached in pci device msi msg data +To: "gregkh@linuxfoundation.org" +Cc: "stable@vger.kernel.org" +Message-ID: <20170317004812.26960-1-alexander.levin@verizon.com> + +From: Dan Streetman + +[ 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 +Reviewed-by: Stefano Stabellini +Acked-by: Konrad Rzeszutek Wilk +Signed-off-by: Boris Ostrovsky +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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) ? -- 2.47.3