]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'rdma/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 01:03:04 +0000 (12:03 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 01:03:04 +0000 (12:03 +1100)
Initial roundup of 4.4 merge window candidates

- "Checksum offload support in user space" enablement
- Misc cxgb4 fixes, add T6 support
- Misc usnic fixes
- 32 bit build warning fixes
- Misc ocrdma fixes
- Multicast loopback prevention extension
- Extend the GID cache to store and return attributes of GIDs
- Misc iSER updates
- iSER clustering update
- Network NameSpace support for rdma CM
- Work Request cleanup series
- New Memory Registration API

19 files changed:
1  2 
MAINTAINERS
drivers/infiniband/hw/mlx5/main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
include/linux/mlx4/device.h
include/linux/sunrpc/svc_rdma.h
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_send.c
net/rds/iw_rdma.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h

diff --combined MAINTAINERS
index ec706603f4f65a6fe20c6db127244cefa912b8bf,2ac939e35169e046dd4554379a075bdef80547a0..728dcec6f29495ea11f3d9f72cc3d2d313e2b1a0
@@@ -240,12 -240,6 +240,12 @@@ L:       lm-sensors@lm-sensors.or
  S:    Maintained
  F:    drivers/hwmon/abituguru3.c
  
 +ACCES 104-IDIO-16 GPIO DRIVER
 +M:    "William Breathitt Gray" <vilhelm.gray@gmail.com>
 +L:    linux-gpio@vger.kernel.org
 +S:    Maintained
 +F:    drivers/gpio/gpio-104-idio-16.c
 +
  ACENIC DRIVER
  M:    Jes Sorensen <jes@trained-monkey.org>
  L:    linux-acenic@sunsite.dk
@@@ -660,6 -654,11 +660,6 @@@ F:        drivers/gpu/drm/radeon/radeon_kfd.
  F:    drivers/gpu/drm/radeon/radeon_kfd.h
  F:    include/uapi/linux/kfd_ioctl.h
  
 -AMD MICROCODE UPDATE SUPPORT
 -M:    Borislav Petkov <bp@alien8.de>
 -S:    Maintained
 -F:    arch/x86/kernel/cpu/microcode/amd*
 -
  AMD XGBE DRIVER
  M:    Tom Lendacky <thomas.lendacky@amd.com>
  L:    netdev@vger.kernel.org
@@@ -789,11 -788,6 +789,11 @@@ S:       Maintaine
  F:    drivers/net/appletalk/
  F:    net/appletalk/
  
 +APPLIED MICRO (APM) X-GENE DEVICE TREE SUPPORT
 +M:    Duc Dang <dhdang@apm.com>
 +S:    Supported
 +F:    arch/arm64/boot/dts/apm/
 +
  APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
  M:    Iyappan Subramanian <isubramanian@apm.com>
  M:    Keyur Chudgar <kchudgar@apm.com>
@@@ -828,13 -822,12 +828,13 @@@ F:      arch/arm/include/asm/floppy.
  
  ARM PMU PROFILING AND DEBUGGING
  M:    Will Deacon <will.deacon@arm.com>
 +R:    Mark Rutland <mark.rutland@arm.com>
  S:    Maintained
 -F:    arch/arm/kernel/perf_*
 +F:    arch/arm*/kernel/perf_*
  F:    arch/arm/oprofile/common.c
 -F:    arch/arm/kernel/hw_breakpoint.c
 -F:    arch/arm/include/asm/hw_breakpoint.h
 -F:    arch/arm/include/asm/perf_event.h
 +F:    arch/arm*/kernel/hw_breakpoint.c
 +F:    arch/arm*/include/asm/hw_breakpoint.h
 +F:    arch/arm*/include/asm/perf_event.h
  F:    drivers/perf/arm_pmu.c
  F:    include/linux/perf/arm_pmu.h
  
@@@ -901,12 -894,11 +901,12 @@@ M:      Lennert Buytenhek <kernel@wantstofly
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  
 -ARM/Allwinner A1X SoC support
 +ARM/Allwinner sunXi SoC support
  M:    Maxime Ripard <maxime.ripard@free-electrons.com>
 +M:    Chen-Yu Tsai <wens@csie.org>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
 -N:    sun[x4567]i
 +N:    sun[x456789]i
  
  ARM/Allwinner SoC Clock Support
  M:    Emilio López <emilio@elopez.com.ar>
@@@ -925,7 -917,7 +925,7 @@@ M: Tsahee Zidenberg <tsahee@annapurnala
  S:    Maintained
  F:    arch/arm/mach-alpine/
  
 -ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
 +ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
  M:    Nicolas Ferre <nicolas.ferre@atmel.com>
  M:    Alexandre Belloni <alexandre.belloni@free-electrons.com>
  M:    Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
@@@ -1238,13 -1230,6 +1238,13 @@@ ARM/LPC18XX ARCHITECTUR
  M:    Joachim Eastwood <manabian@gmail.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
 +F:    arch/arm/boot/dts/lpc43*
 +F:    drivers/clk/nxp/clk-lpc18xx*
 +F:    drivers/clocksource/time-lpc32xx.c
 +F:    drivers/i2c/busses/i2c-lpc2k.c
 +F:    drivers/memory/pl172.c
 +F:    drivers/mtd/spi-nor/nxp-spifi.c
 +F:    drivers/rtc/rtc-lpc24xx.c
  N:    lpc18xx
  
  ARM/MAGICIAN MACHINE SUPPORT
@@@ -1459,12 -1444,7 +1459,12 @@@ F:    arch/arm/mach-exynos*
  F:    drivers/*/*s3c2410*
  F:    drivers/*/*/*s3c2410*
  F:    drivers/spi/spi-s3c*
 +F:    drivers/soc/samsung/*
  F:    sound/soc/samsung/*
 +F:    Documentation/arm/Samsung/
 +F:    Documentation/devicetree/bindings/arm/samsung/
 +F:    Documentation/devicetree/bindings/sram/samsung-sram.txt
 +F:    Documentation/devicetree/bindings/power/pd-samsung.txt
  N:    exynos
  
  ARM/SAMSUNG MOBILE MACHINE SUPPORT
@@@ -1499,14 -1479,6 +1499,14 @@@ L:    linux-media@vger.kernel.or
  S:    Maintained
  F:    drivers/media/platform/s5p-tv/
  
 +ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
 +M:    Andrzej Pietrasiewicz <andrzej.p@samsung.com>
 +M:    Jacek Anaszewski <j.anaszewski@samsung.com>
 +L:    linux-arm-kernel@lists.infradead.org
 +L:    linux-media@vger.kernel.org
 +S:    Maintained
 +F:    drivers/media/platform/s5p-jpeg/
 +
  ARM/SHMOBILE ARM ARCHITECTURE
  M:    Simon Horman <horms@verge.net.au>
  M:    Magnus Damm <magnus.damm@gmail.com>
@@@ -1519,6 -1491,8 +1519,6 @@@ F:      arch/arm/boot/dts/emev2
  F:    arch/arm/boot/dts/r7s*
  F:    arch/arm/boot/dts/r8a*
  F:    arch/arm/boot/dts/sh*
 -F:    arch/arm/configs/bockw_defconfig
 -F:    arch/arm/configs/marzen_defconfig
  F:    arch/arm/configs/shmobile_defconfig
  F:    arch/arm/include/debug/renesas-scif.S
  F:    arch/arm/mach-shmobile/
@@@ -1553,7 -1527,6 +1553,7 @@@ W:      http://www.stlinux.co
  S:    Maintained
  F:    arch/arm/mach-sti/
  F:    arch/arm/boot/dts/sti*
 +F:    drivers/char/hw_random/st-rng.c
  F:    drivers/clocksource/arm_global_timer.c
  F:    drivers/clocksource/clksrc_st_lpc.c
  F:    drivers/i2c/busses/i2c-st.c
@@@ -1633,10 -1606,7 +1633,10 @@@ M:    Masahiro Yamada <yamada.masahiro@soc
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  F:    arch/arm/boot/dts/uniphier*
 +F:    arch/arm/include/asm/hardware/cache-uniphier.h
  F:    arch/arm/mach-uniphier/
 +F:    arch/arm/mm/cache-uniphier.c
 +F:    drivers/i2c/busses/i2c-uniphier*
  F:    drivers/pinctrl/uniphier/
  F:    drivers/tty/serial/8250/8250_uniphier.c
  N:    uniphier
@@@ -1809,14 -1779,6 +1809,14 @@@ S:    Supporte
  F:    Documentation/aoe/
  F:    drivers/block/aoe/
  
 +ATHEROS 71XX/9XXX GPIO DRIVER
 +M:    Alban Bedel <albeu@free.fr>
 +W:    https://github.com/AlbanBedel/linux
 +T:    git git://github.com/AlbanBedel/linux
 +S:    Maintained
 +F:    drivers/gpio/gpio-ath79.c
 +F:    Documentation/devicetree/bindings/gpio/gpio-ath79.txt
 +
  ATHEROS ATH GENERIC UTILITIES
  M:    "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
  L:    linux-wireless@vger.kernel.org
@@@ -2398,27 -2360,19 +2398,27 @@@ L:   linux-scsi@vger.kernel.or
  S:    Supported
  F:    drivers/scsi/bnx2i/
  
 -BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
 +BROADCOM IPROC ARM ARCHITECTURE
  M:    Ray Jui <rjui@broadcom.com>
  M:    Scott Branden <sbranden@broadcom.com>
 +M:    Jon Mason <jonmason@broadcom.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    bcm-kernel-feedback-list@broadcom.com
  T:    git git://github.com/broadcom/cygnus-linux.git
  S:    Maintained
  N:    iproc
  N:    cygnus
 +N:    nsp
  N:    bcm9113*
  N:    bcm9583*
 -N:    bcm583*
 +N:    bcm9585*
 +N:    bcm9586*
 +N:    bcm988312
  N:    bcm113*
 +N:    bcm583*
 +N:    bcm585*
 +N:    bcm586*
 +N:    bcm88312
  
  BROADCOM BRCMSTB GPIO DRIVER
  M:    Gregory Fong <gregory.0xf0@gmail.com>
@@@ -2776,9 -2730,10 +2776,10 @@@ S:    Supporte
  F:    drivers/net/ethernet/cisco/enic/
  
  CISCO VIC LOW LATENCY NIC DRIVER
- M:    Upinder Malhi <umalhi@cisco.com>
+ M:    Christian Benvenuti <benve@cisco.com>
+ M:    Dave Goodell <dgoodell@cisco.com>
  S:    Supported
- F:    drivers/infiniband/hw/usnic
+ F:    drivers/infiniband/hw/usnic/
  
  CIRRUS LOGIC EP93XX ETHERNET DRIVER
  M:    Hartley Sweeten <hsweeten@visionengravers.com>
@@@ -3413,7 -3368,6 +3414,7 @@@ M:      Support Opensource <support.opensour
  W:    http://www.dialog-semiconductor.com/products
  S:    Supported
  F:    Documentation/hwmon/da90??
 +F:    Documentation/devicetree/bindings/sound/da[79]*.txt
  F:    drivers/gpio/gpio-da90??.c
  F:    drivers/hwmon/da90??-hwmon.c
  F:    drivers/iio/adc/da91??-*.c
@@@ -3638,13 -3592,6 +3639,13 @@@ F:    drivers/gpu/drm/i915
  F:    include/drm/i915*
  F:    include/uapi/drm/i915*
  
 +DRM DRIVERS FOR ATMEL HLCDC
 +M:    Boris Brezillon <boris.brezillon@free-electrons.com>
 +L:    dri-devel@lists.freedesktop.org
 +S:    Supported
 +F:    drivers/gpu/drm/atmel-hlcdc/
 +F:    Documentation/devicetree/bindings/drm/atmel/
 +
  DRM DRIVERS FOR EXYNOS
  M:    Inki Dae <inki.dae@samsung.com>
  M:    Joonyoung Shim <jy0922.shim@samsung.com>
@@@ -3673,14 -3620,6 +3674,14 @@@ S:    Maintaine
  F:    drivers/gpu/drm/imx/
  F:    Documentation/devicetree/bindings/drm/imx/
  
 +DRM DRIVERS FOR GMA500 (Poulsbo, Moorestown and derivative chipsets)
 +M:    Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
 +L:    dri-devel@lists.freedesktop.org
 +T:    git git://github.com/patjak/drm-gma500
 +S:    Maintained
 +F:    drivers/gpu/drm/gma500
 +F:    include/drm/gma500*
 +
  DRM DRIVERS FOR NVIDIA TEGRA
  M:    Thierry Reding <thierry.reding@gmail.com>
  M:    Terje Bergström <tbergstrom@nvidia.com>
@@@ -4065,7 -4004,7 +4066,7 @@@ S:      Maintaine
  F:    sound/usb/misc/ua101.c
  
  EXTENSIBLE FIRMWARE INTERFACE (EFI)
 -M:    Matt Fleming <matt.fleming@intel.com>
 +M:    Matt Fleming <matt@codeblueprint.co.uk>
  L:    linux-efi@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git
  S:    Maintained
@@@ -4080,7 -4019,7 +4081,7 @@@ F:      include/linux/efi*.
  EFI VARIABLE FILESYSTEM
  M:    Matthew Garrett <matthew.garrett@nebula.com>
  M:    Jeremy Kerr <jk@ozlabs.org>
 -M:    Matt Fleming <matt.fleming@intel.com>
 +M:    Matt Fleming <matt@codeblueprint.co.uk>
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git
  L:    linux-efi@vger.kernel.org
  S:    Maintained
@@@ -4474,14 -4413,6 +4475,14 @@@ L:    linuxppc-dev@lists.ozlabs.or
  S:    Maintained
  F:    drivers/net/ethernet/freescale/ucc_geth*
  
 +FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
 +M:    Claudiu Manoil <claudiu.manoil@freescale.com>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    drivers/net/ethernet/freescale/gianfar*
 +X:    drivers/net/ethernet/freescale/gianfar_ptp.c
 +F:    Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
 +
  FREESCALE QUICC ENGINE UCC UART DRIVER
  M:    Timur Tabi <timur@tabi.org>
  L:    linuxppc-dev@lists.ozlabs.org
@@@ -5159,7 -5090,6 +5160,7 @@@ S:      Maintaine
  F:    Documentation/devicetree/bindings/i2c/
  F:    Documentation/i2c/
  F:    drivers/i2c/
 +F:    drivers/i2c/*/
  F:    include/linux/i2c.h
  F:    include/linux/i2c-*.h
  F:    include/uapi/linux/i2c.h
@@@ -5501,6 -5431,12 +5502,6 @@@ W:     https://01.org/linux-acp
  S:    Supported
  F:    drivers/platform/x86/intel_menlow.c
  
 -INTEL IA32 MICROCODE UPDATE SUPPORT
 -M:    Borislav Petkov <bp@alien8.de>
 -S:    Maintained
 -F:    arch/x86/kernel/cpu/microcode/core*
 -F:    arch/x86/kernel/cpu/microcode/intel*
 -
  INTEL I/OAT DMA DRIVER
  M:    Dave Jiang <dave.jiang@intel.com>
  R:    Dan Williams <dan.j.williams@intel.com>
@@@ -5611,7 -5547,7 +5612,7 @@@ F:      drivers/net/wireless/iwlegacy
  INTEL WIRELESS WIFI LINK (iwlwifi)
  M:    Johannes Berg <johannes.berg@intel.com>
  M:    Emmanuel Grumbach <emmanuel.grumbach@intel.com>
 -M:    Intel Linux Wireless <ilw@linux.intel.com>
 +M:    Intel Linux Wireless <linuxwifi@intel.com>
  L:    linux-wireless@vger.kernel.org
  W:    http://intellinuxwireless.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
@@@ -6022,7 -5958,7 +6023,7 @@@ F:      virt/kvm
  KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V
  M:    Joerg Roedel <joro@8bytes.org>
  L:    kvm@vger.kernel.org
 -W:    http://kvm.qumranet.com
 +W:    http://www.linux-kvm.org/
  S:    Maintained
  F:    arch/x86/include/asm/svm.h
  F:    arch/x86/kvm/svm.c
  KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
  M:    Alexander Graf <agraf@suse.com>
  L:    kvm-ppc@vger.kernel.org
 -W:    http://kvm.qumranet.com
 +W:    http://www.linux-kvm.org/
  T:    git git://github.com/agraf/linux-2.6.git
  S:    Supported
  F:    arch/powerpc/include/asm/kvm*
@@@ -6158,13 -6094,6 +6159,13 @@@ F:    Documentation/auxdisplay/ks010
  F:    drivers/auxdisplay/ks0108.c
  F:    include/linux/ks0108.h
  
 +L3MDEV
 +M:    David Ahern <dsa@cumulusnetworks.com>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    net/l3mdev
 +F:    include/net/l3mdev.h
 +
  LAPB module
  L:    linux-x25@vger.kernel.org
  S:    Orphan
@@@ -6632,13 -6561,6 +6633,13 @@@ M:    Guenter Roeck <linux@roeck-us.net
  S:    Maintained
  F:    drivers/net/dsa/mv88e6352.c
  
 +MARVELL CRYPTO DRIVER
 +M:    Boris Brezillon <boris.brezillon@free-electrons.com>
 +M:    Arnaud Ebalard <arno@natisbad.org>
 +F:    drivers/crypto/marvell/
 +S:    Maintained
 +L:    linux-crypto@vger.kernel.org
 +
  MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
  M:    Mirko Lindner <mlindner@marvell.com>
  M:    Stephen Hemminger <stephen@networkplumber.org>
@@@ -6857,6 -6779,7 +6858,6 @@@ F:      drivers/scsi/megaraid
  
  MELLANOX ETHERNET DRIVER (mlx4_en)
  M:    Amir Vadai <amirv@mellanox.com>
 -M:    Ido Shamay <idos@mellanox.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
@@@ -7049,7 -6972,6 +7050,7 @@@ M:      Alan Ott <alan@signal11.us
  L:    linux-wpan@vger.kernel.org
  S:    Maintained
  F:    drivers/net/ieee802154/mrf24j40.c
 +F:    Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
  
  MSI LAPTOP SUPPORT
  M:    "Lee, Chun-Yi" <jlee@suse.com>
@@@ -7384,6 -7306,7 +7385,6 @@@ S:      Odd Fixe
  F:    drivers/net/
  F:    include/linux/if_*
  F:    include/linux/netdevice.h
 -F:    include/linux/arcdevice.h
  F:    include/linux/etherdevice.h
  F:    include/linux/fcdevice.h
  F:    include/linux/fddidevice.h
@@@ -8021,14 -7944,6 +8022,14 @@@ F:    include/linux/pci
  F:    arch/x86/pci/
  F:    arch/x86/kernel/quirks.c
  
 +PCI DRIVER FOR ALTERA PCIE IP
 +M:    Ley Foon Tan <lftan@altera.com>
 +L:    rfi@lists.rocketboards.org (moderated for non-subscribers)
 +L:    linux-pci@vger.kernel.org
 +S:    Supported
 +F:    Documentation/devicetree/bindings/pci/altera-pcie.txt
 +F:    drivers/pci/host/pcie-altera.c
 +
  PCI DRIVER FOR ARM VERSATILE PLATFORM
  M:    Rob Herring <robh@kernel.org>
  L:    linux-pci@vger.kernel.org
@@@ -8130,14 -8045,6 +8131,14 @@@ L:    linux-pci@vger.kernel.or
  S:    Maintained
  F:    drivers/pci/host/*spear*
  
 +PCI MSI DRIVER FOR ALTERA MSI IP
 +M:    Ley Foon Tan <lftan@altera.com>
 +L:    rfi@lists.rocketboards.org (moderated for non-subscribers)
 +L:    linux-pci@vger.kernel.org
 +S:    Supported
 +F:    Documentation/devicetree/bindings/pci/altera-pcie-msi.txt
 +F:    drivers/pci/host/pcie-altera-msi.c
 +
  PCI MSI DRIVER FOR APPLIEDMICRO XGENE
  M:    Duc Dang <dhdang@apm.com>
  L:    linux-pci@vger.kernel.org
@@@ -8146,13 -8053,6 +8147,13 @@@ S:    Maintaine
  F:    Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
  F:    drivers/pci/host/pci-xgene-msi.c
  
 +PCIE DRIVER FOR HISILICON
 +M:    Zhou Wang <wangzhou1@hisilicon.com>
 +L:    linux-pci@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
 +F:    drivers/pci/host/pcie-hisi.c
 +
  PCMCIA SUBSYSTEM
  P:    Linux PCMCIA Team
  L:    linux-pcmcia@lists.infradead.org
@@@ -8259,13 -8159,6 +8260,13 @@@ L:    linux-arm-kernel@lists.infradead.or
  S:    Maintained
  F:    drivers/pinctrl/pinctrl-at91.*
  
 +PIN CONTROLLER - ATMEL AT91 PIO4
 +M:    Ludovic Desroches <ludovic.desroches@atmel.com>
 +L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 +L:    linux-gpio@vger.kernel.org
 +S:    Supported
 +F:    drivers/pinctrl/pinctrl-at91-pio4.*
 +
  PIN CONTROLLER - INTEL
  M:    Mika Westerberg <mika.westerberg@linux.intel.com>
  M:    Heikki Krogerus <heikki.krogerus@linux.intel.com>
@@@ -8369,6 -8262,12 +8370,6 @@@ M:     "Rafael J. Wysocki" <rafael.j.wysock
  S:    Maintained
  F:    drivers/pnp/
  
 -PNXxxxx I2C DRIVER
 -M:    Vitaly Wool <vitalywool@gmail.com>
 -L:    linux-i2c@vger.kernel.org
 -S:    Maintained
 -F:    drivers/i2c/busses/i2c-pnx.c
 -
  PPP PROTOCOL DRIVERS AND COMPRESSORS
  M:    Paul Mackerras <paulus@samba.org>
  L:    linux-ppp@vger.kernel.org
@@@ -8621,16 -8520,6 +8622,16 @@@ L:    netdev@vger.kernel.or
  S:    Supported
  F:    drivers/net/ethernet/qlogic/qlge/
  
 +QLOGIC QL4xxx ETHERNET DRIVER
 +M:    Yuval Mintz <Yuval.Mintz@qlogic.com>
 +M:    Ariel Elior <Ariel.Elior@qlogic.com>
 +M:    everest-linux-l2@qlogic.com
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +F:    drivers/net/ethernet/qlogic/qed/
 +F:    include/linux/qed/
 +F:    drivers/net/ethernet/qlogic/qede/
 +
  QNX4 FILESYSTEM
  M:    Anders Larsen <al@alarsen.net>
  W:    http://www.alarsen.net/linux/qnx4fs/
@@@ -8982,13 -8871,6 +8983,13 @@@ S:    Maintaine
  F:    drivers/net/wireless/rtlwifi/
  F:    drivers/net/wireless/rtlwifi/rtl8192ce/
  
 +RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
 +M:    Jes Sorensen <Jes.Sorensen@redhat.com>
 +L:    linux-wireless@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
 +S:    Maintained
 +F:    drivers/net/wireless/realtek/rtl8xxxu/
 +
  S3 SAVAGE FRAMEBUFFER DRIVER
  M:    Antonino Daplas <adaplas@gmail.com>
  L:    linux-fbdev@vger.kernel.org
@@@ -9220,15 -9102,6 +9221,15 @@@ S: Supporte
  F: Documentation/devicetree/bindings/net/snps,dwc-qos-ethernet.txt
  F: drivers/net/ethernet/synopsys/dwc_eth_qos.c
  
 +SYNOPSYS DESIGNWARE I2C DRIVER
 +M:    Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 +M:    Jarkko Nikula <jarkko.nikula@linux.intel.com>
 +M:    Mika Westerberg <mika.westerberg@linux.intel.com>
 +L:    linux-i2c@vger.kernel.org
 +S:    Maintained
 +F:    drivers/i2c/busses/i2c-designware-*
 +F:    include/linux/platform_data/i2c-designware.h
 +
  SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
  M:    Seungwon Jeon <tgih.jun@samsung.com>
  M:    Jaehoon Chung <jh80.chung@samsung.com>
@@@ -9281,16 -9154,6 +9282,16 @@@ W:    http://www.sunplus.co
  S:    Supported
  F:    arch/score/
  
 +SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers
 +M:    Sudeep Holla <sudeep.holla@arm.com>
 +L:    linux-arm-kernel@lists.infradead.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/arm/arm,scpi.txt
 +F:    drivers/clk/clk-scpi.c
 +F:    drivers/cpufreq/scpi-cpufreq.c
 +F:    drivers/firmware/arm_scpi.c
 +F:    include/linux/scpi_protocol.h
 +
  SCSI CDROM DRIVER
  M:    Jens Axboe <axboe@kernel.dk>
  L:    linux-scsi@vger.kernel.org
@@@ -10052,6 -9915,7 +10053,6 @@@ S:    Maintaine
  F:    drivers/staging/lustre
  
  STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
 -M:    Julian Andres Klode <jak@jak-linux.org>
  M:    Marc Dietrich <marvin24@gmx.de>
  L:    ac100@lists.launchpad.net (moderated for non-subscribers)
  L:    linux-tegra@vger.kernel.org
@@@ -10206,7 -10070,6 +10207,7 @@@ F:   include/net/switchdev.
  
  SYNOPSYS ARC ARCHITECTURE
  M:    Vineet Gupta <vgupta@synopsys.com>
 +L:    linux-snps-arc@lists.infraded.org
  S:    Supported
  F:    arch/arc/
  F:    Documentation/devicetree/bindings/arc/*
@@@ -11238,12 -11101,6 +11239,12 @@@ S: Maintaine
  F:    drivers/media/v4l2-core/videobuf2-*
  F:    include/media/videobuf2-*
  
 +VIRTUAL SERIO DEVICE DRIVER
 +M:    Stephen Chandler Paul <thatslyude@gmail.com>
 +S:    Maintained
 +F:    drivers/input/serio/userio.c
 +F:    include/uapi/linux/userio.h
 +
  VIRTIO CONSOLE DRIVER
  M:    Amit Shah <amit.shah@redhat.com>
  L:    virtualization@lists.linux-foundation.org
@@@ -11409,6 -11266,7 +11410,6 @@@ M:   Shrijeet Mukherjee <shm@cumulusnetwo
  L:    netdev@vger.kernel.org
  S:    Maintained
  F:    drivers/net/vrf.c
 -F:    include/net/vrf.h
  F:    Documentation/networking/vrf.txt
  
  VT1211 HARDWARE MONITOR DRIVER
@@@ -11521,6 -11379,15 +11522,6 @@@ W:  http://oops.ghostprotocols.net:81/bl
  S:    Maintained
  F:    drivers/net/wireless/wl3501*
  
 -WM97XX TOUCHSCREEN DRIVERS
 -M:    Mark Brown <broonie@kernel.org>
 -M:    Liam Girdwood <lrg@slimlogic.co.uk>
 -L:    linux-input@vger.kernel.org
 -W:    https://github.com/CirrusLogic/linux-drivers/wiki
 -S:    Supported
 -F:    drivers/input/touchscreen/*wm97*
 -F:    include/linux/wm97xx.h
 -
  WOLFSON MICROELECTRONICS DRIVERS
  L:    patches@opensource.wolfsonmicro.com
  T:    git https://github.com/CirrusLogic/linux-drivers.git
@@@ -11595,11 -11462,6 +11596,11 @@@ L: linux-edac@vger.kernel.or
  S:    Maintained
  F:    arch/x86/kernel/cpu/mcheck/*
  
 +X86 MICROCODE UPDATE SUPPORT
 +M:    Borislav Petkov <bp@alien8.de>
 +S:    Maintained
 +F:    arch/x86/kernel/cpu/microcode/*
 +
  X86 VDSO
  M:    Andy Lutomirski <luto@amacapital.net>
  L:    linux-kernel@vger.kernel.org
@@@ -11800,7 -11662,6 +11801,7 @@@ F:   drivers/tty/serial/zs.
  ZSMALLOC COMPRESSED SLAB MEMORY ALLOCATOR
  M:    Minchan Kim <minchan@kernel.org>
  M:    Nitin Gupta <ngupta@vflare.org>
 +R:    Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
  L:    linux-mm@kvack.org
  S:    Maintained
  F:    mm/zsmalloc.c
index 68508d528ba0ecd9ff18768df885aa1b4741ab04,bdd60a69be2d2025fb79d424c1d4b21facfab1f1..7e97cb55a6bfa9517a726b9be897d17563272a5d
@@@ -30,7 -30,7 +30,7 @@@
   * SOFTWARE.
   */
  
 -#include <asm-generic/kmap_types.h>
 +#include <linux/highmem.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/errno.h>
@@@ -1425,8 -1425,7 +1425,7 @@@ static void *mlx5_ib_add(struct mlx5_co
        dev->ib_dev.detach_mcast        = mlx5_ib_mcg_detach;
        dev->ib_dev.process_mad         = mlx5_ib_process_mad;
        dev->ib_dev.alloc_mr            = mlx5_ib_alloc_mr;
-       dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list;
-       dev->ib_dev.free_fast_reg_page_list  = mlx5_ib_free_fast_reg_page_list;
+       dev->ib_dev.map_mr_sg           = mlx5_ib_map_mr_sg;
        dev->ib_dev.check_mr_status     = mlx5_ib_check_mr_status;
        dev->ib_dev.get_port_immutable  = mlx5_port_immutable;
  
index 634e50c8c5ef766ae144a2c51344294751902dea,11045ec8d94ce295c19c5a52ee5fe8774ccc9bd3..6f268518b37f0ec160d0fe6998942b6042823489
@@@ -47,8 -47,8 +47,9 @@@
  #include <linux/timer.h>
  #include <linux/vmalloc.h>
  #include <linux/etherdevice.h>
 +#include <linux/net_tstamp.h>
  #include <asm/io.h>
+ #include "t4_chip_type.h"
  #include "cxgb4_uld.h"
  
  #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
@@@ -291,31 -291,6 +292,6 @@@ struct pci_params 
        unsigned char width;
  };
  
- #define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
- #define CHELSIO_CHIP_FPGA          0x100
- #define CHELSIO_CHIP_VERSION(code) (((code) >> 4) & 0xf)
- #define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
- #define CHELSIO_T4            0x4
- #define CHELSIO_T5            0x5
- #define CHELSIO_T6            0x6
- enum chip_type {
-       T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
-       T4_A2 = CHELSIO_CHIP_CODE(CHELSIO_T4, 2),
-       T4_FIRST_REV    = T4_A1,
-       T4_LAST_REV     = T4_A2,
-       T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
-       T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
-       T5_FIRST_REV    = T5_A0,
-       T5_LAST_REV     = T5_A1,
-       T6_A0 = CHELSIO_CHIP_CODE(CHELSIO_T6, 0),
-       T6_FIRST_REV    = T6_A0,
-       T6_LAST_REV     = T6_A0,
- };
  struct devlog_params {
        u32 memtype;                    /* which memory (EDC0, EDC1, MC) */
        u32 start;                      /* start of log in firmware memory */
@@@ -479,8 -454,6 +455,8 @@@ struct port_info 
  #ifdef CONFIG_CHELSIO_T4_FCOE
        struct cxgb_fcoe fcoe;
  #endif /* CONFIG_CHELSIO_T4_FCOE */
 +      bool rxtstamp;  /* Enable TS */
 +      struct hwtstamp_config tstamp_config;
  };
  
  struct dentry;
@@@ -520,7 -493,6 +496,7 @@@ struct sge_fl {                     /* 
  
  /* A packet gather list */
  struct pkt_gl {
 +      u64 sgetstamp;              /* SGE Time Stamp for Ingress Packet */
        struct page_frag frags[MAX_SKB_FRAGS];
        void *va;                         /* virtual address of first byte */
        unsigned int nfrags;              /* # of fragments */
@@@ -909,21 -881,6 +885,6 @@@ static inline int is_offload(const stru
        return adap->params.offload;
  }
  
- static inline int is_t6(enum chip_type chip)
- {
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T6;
- }
- static inline int is_t5(enum chip_type chip)
- {
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T5;
- }
- static inline int is_t4(enum chip_type chip)
- {
-       return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4;
- }
  static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr)
  {
        return readl(adap->regs + reg_addr);
index 2cf81857a2971b280005715992c0842e4f21385f,aeeb21ff0de2cb50fab523699ebc197ae8341b91..0d147610a06f13819bd1425984f6ec6b3c34e81a
@@@ -83,7 -83,7 +83,7 @@@ char cxgb4_driver_name[] = KBUILD_MODNA
  #endif
  #define DRV_VERSION "2.0.0-ko"
  const char cxgb4_driver_version[] = DRV_VERSION;
 -#define DRV_DESC "Chelsio T4/T5 Network Driver"
 +#define DRV_DESC "Chelsio T4/T5/T6 Network Driver"
  
  /* Host shadow copy of ingress filter entry.  This is in host native format
   * and doesn't match the ordering or bit order, etc. of the hardware of the
@@@ -151,7 -151,6 +151,7 @@@ MODULE_VERSION(DRV_VERSION)
  MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl);
  MODULE_FIRMWARE(FW4_FNAME);
  MODULE_FIRMWARE(FW5_FNAME);
 +MODULE_FIRMWARE(FW6_FNAME);
  
  /*
   * Normally we're willing to become the firmware's Master PF but will be happy
@@@ -276,7 -275,7 +276,7 @@@ static void link_report(struct net_devi
        else {
                static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" };
  
 -              const char *s = "10Mbps";
 +              const char *s;
                const struct port_info *p = netdev_priv(dev);
  
                switch (p->link_cfg.speed) {
                case 40000:
                        s = "40Gbps";
                        break;
 +              default:
 +                      pr_info("%s: unsupported speed: %d\n",
 +                              dev->name, p->link_cfg.speed);
 +                      return;
                }
  
                netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
@@@ -1940,6 -1935,28 +1940,28 @@@ unsigned int cxgb4_best_aligned_mtu(con
  }
  EXPORT_SYMBOL(cxgb4_best_aligned_mtu);
  
+ /**
+  *    cxgb4_tp_smt_idx - Get the Source Mac Table index for this VI
+  *    @chip: chip type
+  *    @viid: VI id of the given port
+  *
+  *    Return the SMT index for this VI.
+  */
+ unsigned int cxgb4_tp_smt_idx(enum chip_type chip, unsigned int viid)
+ {
+       /* In T4/T5, SMT contains 256 SMAC entries organized in
+        * 128 rows of 2 entries each.
+        * In T6, SMT contains 256 SMAC entries in 256 rows.
+        * TODO: The below code needs to be updated when we add support
+        * for 256 VFs.
+        */
+       if (CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5)
+               return ((viid & 0x7f) << 1);
+       else
+               return (viid & 0x7f);
+ }
+ EXPORT_SYMBOL(cxgb4_tp_smt_idx);
  /**
   *    cxgb4_port_chan - get the HW channel of a port
   *    @dev: the net device for the port
@@@ -2964,30 -2981,6 +2986,30 @@@ static int cxgb_ioctl(struct net_devic
                        ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad,
                                         data->reg_num, data->val_in);
                break;
 +      case SIOCGHWTSTAMP:
 +              return copy_to_user(req->ifr_data, &pi->tstamp_config,
 +                                  sizeof(pi->tstamp_config)) ?
 +                      -EFAULT : 0;
 +      case SIOCSHWTSTAMP:
 +              if (copy_from_user(&pi->tstamp_config, req->ifr_data,
 +                                 sizeof(pi->tstamp_config)))
 +                      return -EFAULT;
 +
 +              switch (pi->tstamp_config.rx_filter) {
 +              case HWTSTAMP_FILTER_NONE:
 +                      pi->rxtstamp = false;
 +                      break;
 +              case HWTSTAMP_FILTER_ALL:
 +                      pi->rxtstamp = true;
 +                      break;
 +              default:
 +                      pi->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
 +                      return -ERANGE;
 +              }
 +
 +              return copy_to_user(req->ifr_data, &pi->tstamp_config,
 +                                  sizeof(pi->tstamp_config)) ?
 +                      -EFAULT : 0;
        default:
                return -EOPNOTSUPP;
        }
@@@ -3699,7 -3692,7 +3721,7 @@@ static int adap_init0(struct adapter *a
        t4_get_tp_version(adap, &adap->params.tp_vers);
        ret = t4_check_fw_version(adap);
        /* If firmware is too old (not supported by driver) force an update. */
 -      if (ret == -EFAULT)
 +      if (ret)
                state = DEV_STATE_UNINIT;
        if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
                struct fw_info *fw_info;
@@@ -4486,10 -4479,6 +4508,10 @@@ static int enable_msix(struct adapter *
        }
        for (i = 0; i < allocated; ++i)
                adap->msix_info[i].vec = entries[i].vector;
 +      dev_info(adap->pdev_dev, "%d MSI-X vectors allocated, "
 +               "nic %d iscsi %d rdma cpl %d rdma ciq %d\n",
 +               allocated, s->max_ethqsets, s->ofldqsets, s->rdmaqs,
 +               s->rdmaciqs);
  
        kfree(entries);
        return 0;
index f13a4d7bbf9597535e5f6271dea3769389bc90b6,b3be3a06031162ba3b5ade040f50ee4a462b6b08..90db94e83fdeef52023a542539a5a396c2a9a80c
@@@ -155,6 -155,8 +155,8 @@@ static void dump_dev_cap_flags2(struct 
                [27] = "Port beacon support",
                [28] = "RX-ALL support",
                [29] = "802.1ad offload support",
+               [31] = "Modifying loopback source checks using UPDATE_QP support",
+               [32] = "Loopback source checks support",
        };
        int i;
  
@@@ -964,6 -966,10 +966,10 @@@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev 
        MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
        if (field32 & (1 << 16))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
+       if (field32 & (1 << 18))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB;
+       if (field32 & (1 << 19))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK;
        if (field32 & (1 << 26))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
        if (field32 & (1 << 20))
@@@ -2840,19 -2846,3 +2846,19 @@@ int set_phv_bit(struct mlx4_dev *dev, u
        return -EOPNOTSUPP;
  }
  EXPORT_SYMBOL(set_phv_bit);
 +
 +void mlx4_replace_zero_macs(struct mlx4_dev *dev)
 +{
 +      int i;
 +      u8 mac_addr[ETH_ALEN];
 +
 +      dev->port_random_macs = 0;
 +      for (i = 1; i <= dev->caps.num_ports; ++i)
 +              if (!dev->caps.def_mac[i] &&
 +                  dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) {
 +                      eth_random_addr(mac_addr);
 +                      dev->port_random_macs |= 1 << i;
 +                      dev->caps.def_mac[i] = mlx4_mac_to_u64(mac_addr);
 +              }
 +}
 +EXPORT_SYMBOL_GPL(mlx4_replace_zero_macs);
index 3311f35d08e0719381a6e267e8cdf0acf9198b4d,b16249577aa281c51c1bb4c9febe2f886c5efd6b..168823dde79f3dd48596bdad5a4ea72a95ed0404
@@@ -422,20 -422,37 +422,37 @@@ int mlx4_update_qp(struct mlx4_dev *dev
        u64 qp_mask = 0;
        int err = 0;
  
 +      if (!attr || (attr & ~MLX4_UPDATE_QP_SUPPORTED_ATTRS))
 +              return -EINVAL;
 +
        mailbox = mlx4_alloc_cmd_mailbox(dev);
        if (IS_ERR(mailbox))
                return PTR_ERR(mailbox);
  
        cmd = (struct mlx4_update_qp_context *)mailbox->buf;
  
 -      if (!attr || (attr & ~MLX4_UPDATE_QP_SUPPORTED_ATTRS))
 -              return -EINVAL;
 -
        if (attr & MLX4_UPDATE_QP_SMAC) {
                pri_addr_path_mask |= 1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX;
                cmd->qp_context.pri_path.grh_mylmc = params->smac_index;
        }
  
+       if (attr & MLX4_UPDATE_QP_ETH_SRC_CHECK_MC_LB) {
+               if (!(dev->caps.flags2
+                     & MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
+                       mlx4_warn(dev,
+                                 "Trying to set src check LB, but it isn't supported\n");
+                       err = -ENOTSUPP;
+                       goto out;
+               }
+               pri_addr_path_mask |=
+                       1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB;
+               if (params->flags &
+                   MLX4_UPDATE_QP_PARAMS_FLAGS_ETH_CHECK_MC_LB) {
+                       cmd->qp_context.pri_path.fl |=
+                               MLX4_FL_ETH_SRC_CHECK_MC_LB;
+               }
+       }
        if (attr & MLX4_UPDATE_QP_VSD) {
                qp_mask |= 1ULL << MLX4_UPD_QP_MASK_VSD;
                if (params->flags & MLX4_UPDATE_QP_PARAMS_FLAGS_VSD_ENABLE)
        err = mlx4_cmd(dev, mailbox->dma, qpn & 0xffffff, 0,
                       MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A,
                       MLX4_CMD_NATIVE);
+ out:
        mlx4_free_cmd_mailbox(dev, mailbox);
        return err;
  }
index ac4b99ab1f851c41d1fa108dcbe104f4c307cf48,502f3350088e547c0fe792171642853277b3549a..9813d34f3e5b78e0b3d4a99e253b710278bc7171
@@@ -770,9 -770,12 +770,12 @@@ static int update_vport_qp_param(struc
                        }
                }
  
+               /* preserve IF_COUNTER flag */
+               qpc->pri_path.vlan_control &=
+                       MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
                if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
                    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
                } else if (0 != vp_oper->state.default_vlan) {
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
                } else { /* priority tagged */
-                       qpc->pri_path.vlan_control =
+                       qpc->pri_path.vlan_control |=
                                MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
                                MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
                }
@@@ -1238,10 -1241,8 +1241,10 @@@ static int add_res_range(struct mlx4_de
        return 0;
  
  undo:
 -      for (--i; i >= base; --i)
 +      for (--i; i >= 0; --i) {
                rb_erase(&res_arr[i]->node, root);
 +              list_del_init(&res_arr[i]->list);
 +      }
  
        spin_unlock_irq(mlx4_tlock(dev));
  
@@@ -3764,9 -3765,6 +3767,6 @@@ int mlx4_INIT2RTR_QP_wrapper(struct mlx
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
        orig_sched_queue = qpc->pri_path.sched_queue;
-       err = update_vport_qp_param(dev, inbox, slave, qpn);
-       if (err)
-               return err;
  
        err = get_res(dev, slave, qpn, RES_QP, &qp);
        if (err)
                goto out;
        }
  
+       err = update_vport_qp_param(dev, inbox, slave, qpn);
+       if (err)
+               goto out;
        err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
  out:
        /* if no error, save sched queue value passed in by VF. This is
@@@ -4210,7 -4212,9 +4214,9 @@@ static int add_eth_header(struct mlx4_d
  
  }
  
- #define MLX4_UPD_QP_PATH_MASK_SUPPORTED (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)
+ #define MLX4_UPD_QP_PATH_MASK_SUPPORTED      (                                \
+       1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX                     |\
+       1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)
  int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
                           struct mlx4_vhcr *vhcr,
                           struct mlx4_cmd_mailbox *inbox,
            (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED))
                return -EPERM;
  
+       if ((pri_addr_path_mask &
+            (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) &&
+               !(dev->caps.flags2 &
+                 MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
+                       mlx4_warn(dev,
+                                 "Src check LB for slave %d isn't supported\n",
+                                  slave);
+               return -ENOTSUPP;
+       }
        /* Just change the smac for the QP */
        err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
index 5a8677bafe0408bad140320471e38c100e4bf33a,dac6872dbaea0a0d69f6cd5e657bc5dbeac0513d..7501626ab5293414c29df692edb6fa7122871c84
@@@ -214,6 -214,8 +214,8 @@@ enum 
        MLX4_DEV_CAP_FLAG2_IGNORE_FCS           = 1LL <<  28,
        MLX4_DEV_CAP_FLAG2_PHV_EN               = 1LL <<  29,
        MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN      = 1LL <<  30,
+       MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB = 1ULL << 31,
+       MLX4_DEV_CAP_FLAG2_LB_SRC_CHK           = 1ULL << 32,
  };
  
  enum {
@@@ -833,7 -835,6 +835,7 @@@ struct mlx4_dev 
        struct mlx4_quotas      quotas;
        struct radix_tree_root  qp_table_tree;
        u8                      rev_id;
 +      u8                      port_random_macs;
        char                    board_id[MLX4_BOARD_ID_LEN];
        int                     numa_node;
        int                     oper_log_mgm_entry_size;
index fb4013edcf5732cf3b777b5bc2ac29b0ac8d1bba,1e4438ea2380dd07e79f3d8011445900edea7437..f869807a0d0e2ca93629a7d25092f268dbc8f520
@@@ -105,11 -105,9 +105,9 @@@ struct svc_rdma_chunk_sge 
  };
  struct svc_rdma_fastreg_mr {
        struct ib_mr *mr;
-       void *kva;
-       struct ib_fast_reg_page_list *page_list;
-       int page_list_len;
+       struct scatterlist *sg;
+       int sg_nents;
        unsigned long access_flags;
-       unsigned long map_len;
        enum dma_data_direction direction;
        struct list_head frmr_list;
  };
@@@ -228,13 -226,9 +226,13 @@@ extern void svc_rdma_put_frmr(struct sv
                              struct svc_rdma_fastreg_mr *);
  extern void svc_sq_reap(struct svcxprt_rdma *);
  extern void svc_rq_reap(struct svcxprt_rdma *);
 -extern struct svc_xprt_class svc_rdma_class;
  extern void svc_rdma_prep_reply_hdr(struct svc_rqst *);
  
 +extern struct svc_xprt_class svc_rdma_class;
 +#ifdef CONFIG_SUNRPC_BACKCHANNEL
 +extern struct svc_xprt_class svc_rdma_bc_class;
 +#endif
 +
  /* svc_rdma.c */
  extern int svc_rdma_init(void);
  extern void svc_rdma_cleanup(void);
diff --combined net/rds/ib.c
index a833ab7898fe7306968e4ac20553afbee6955f8b,cd64ef9a47487e4dd30eebb7c4c83928c911061b..f222885ac0c7397ed08c26106e68157d91267ff6
  #include "rds.h"
  #include "ib.h"
  
 -static unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
 -unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */
 +unsigned int rds_ib_fmr_1m_pool_size = RDS_FMR_1M_POOL_SIZE;
 +unsigned int rds_ib_fmr_8k_pool_size = RDS_FMR_8K_POOL_SIZE;
  unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
  
 -module_param(fmr_pool_size, int, 0444);
 -MODULE_PARM_DESC(fmr_pool_size, " Max number of fmr per HCA");
 -module_param(fmr_message_size, int, 0444);
 -MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
 +module_param(rds_ib_fmr_1m_pool_size, int, 0444);
 +MODULE_PARM_DESC(rds_ib_fmr_1m_pool_size, " Max number of 1M fmr per HCA");
 +module_param(rds_ib_fmr_8k_pool_size, int, 0444);
 +MODULE_PARM_DESC(rds_ib_fmr_8k_pool_size, " Max number of 8K fmr per HCA");
  module_param(rds_ib_retry_count, int, 0444);
  MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
  
@@@ -97,10 -97,8 +97,10 @@@ static void rds_ib_dev_free(struct work
        struct rds_ib_device *rds_ibdev = container_of(work,
                                        struct rds_ib_device, free_work);
  
 -      if (rds_ibdev->mr_pool)
 -              rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
 +      if (rds_ibdev->mr_8k_pool)
 +              rds_ib_destroy_mr_pool(rds_ibdev->mr_8k_pool);
 +      if (rds_ibdev->mr_1m_pool)
 +              rds_ib_destroy_mr_pool(rds_ibdev->mr_1m_pool);
        if (rds_ibdev->pd)
                ib_dealloc_pd(rds_ibdev->pd);
  
@@@ -150,13 -148,9 +150,13 @@@ static void rds_ib_add_one(struct ib_de
        rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
  
        rds_ibdev->fmr_max_remaps = dev_attr->max_map_per_fmr?: 32;
 -      rds_ibdev->max_fmrs = dev_attr->max_fmr ?
 -                      min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) :
 -                      fmr_pool_size;
 +      rds_ibdev->max_1m_fmrs = dev_attr->max_mr ?
 +              min_t(unsigned int, (dev_attr->max_mr / 2),
 +                    rds_ib_fmr_1m_pool_size) : rds_ib_fmr_1m_pool_size;
 +
 +      rds_ibdev->max_8k_fmrs = dev_attr->max_mr ?
 +              min_t(unsigned int, ((dev_attr->max_mr / 2) * RDS_MR_8K_SCALE),
 +                    rds_ib_fmr_8k_pool_size) : rds_ib_fmr_8k_pool_size;
  
        rds_ibdev->max_initiator_depth = dev_attr->max_qp_init_rd_atom;
        rds_ibdev->max_responder_resources = dev_attr->max_qp_rd_atom;
                goto put_dev;
        }
  
 -      rds_ibdev->mr_pool = rds_ib_create_mr_pool(rds_ibdev);
 -      if (IS_ERR(rds_ibdev->mr_pool)) {
 -              rds_ibdev->mr_pool = NULL;
 +      rds_ibdev->mr_1m_pool =
 +              rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_1M_POOL);
 +      if (IS_ERR(rds_ibdev->mr_1m_pool)) {
 +              rds_ibdev->mr_1m_pool = NULL;
                goto put_dev;
        }
  
 +      rds_ibdev->mr_8k_pool =
 +              rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_8K_POOL);
 +      if (IS_ERR(rds_ibdev->mr_8k_pool)) {
 +              rds_ibdev->mr_8k_pool = NULL;
 +              goto put_dev;
 +      }
 +
 +      rdsdebug("RDS/IB: max_mr = %d, max_wrs = %d, max_sge = %d, fmr_max_remaps = %d, max_1m_fmrs = %d, max_8k_fmrs = %d\n",
 +               dev_attr->max_fmr, rds_ibdev->max_wrs, rds_ibdev->max_sge,
 +               rds_ibdev->fmr_max_remaps, rds_ibdev->max_1m_fmrs,
 +               rds_ibdev->max_8k_fmrs);
 +
        INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
        INIT_LIST_HEAD(&rds_ibdev->conn_list);
  
@@@ -336,7 -317,7 +336,7 @@@ static int rds_ib_laddr_check(struct ne
        /* Create a CMA ID and try to bind it. This catches both
         * IB and iWARP capable NICs.
         */
-       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
+       cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(cm_id))
                return PTR_ERR(cm_id);
  
diff --combined net/rds/ib.h
index f17d095678907b588c717b48e3d4602cab401199,301c483851668aaf4cbefc7fbb0fb485cbfc1e9d..b3fdebb57460392ae9a751bfaae2e218ff9b6e17
@@@ -9,11 -9,8 +9,11 @@@
  #include "rds.h"
  #include "rdma_transport.h"
  
 -#define RDS_FMR_SIZE                  256
 -#define RDS_FMR_POOL_SIZE             8192
 +#define RDS_FMR_1M_POOL_SIZE          (8192 / 2)
 +#define RDS_FMR_1M_MSG_SIZE           256
 +#define RDS_FMR_8K_MSG_SIZE           2
 +#define RDS_MR_8K_SCALE                       (256 / (RDS_FMR_8K_MSG_SIZE + 1))
 +#define RDS_FMR_8K_POOL_SIZE          (RDS_MR_8K_SCALE * (8192 / 2))
  
  #define RDS_IB_MAX_SGE                        8
  #define RDS_IB_RECV_SGE               2
@@@ -27,9 -24,6 +27,9 @@@
  
  #define RDS_IB_RECYCLE_BATCH_COUNT    32
  
 +#define RDS_IB_WC_MAX                 32
 +#define RDS_IB_SEND_OP                        BIT_ULL(63)
 +
  extern struct rw_semaphore rds_ib_devices_lock;
  extern struct list_head rds_ib_devices;
  
@@@ -75,7 -69,11 +75,11 @@@ struct rds_ib_connect_private 
  
  struct rds_ib_send_work {
        void                    *s_op;
-       struct ib_send_wr       s_wr;
+       union {
+               struct ib_send_wr       s_wr;
+               struct ib_rdma_wr       s_rdma_wr;
+               struct ib_atomic_wr     s_atomic_wr;
+       };
        struct ib_sge           s_sge[RDS_IB_MAX_SGE];
        unsigned long           s_queued;
  };
@@@ -95,20 -93,6 +99,20 @@@ struct rds_ib_work_ring 
        atomic_t        w_free_ctr;
  };
  
 +/* Rings are posted with all the allocations they'll need to queue the
 + * incoming message to the receiving socket so this can't fail.
 + * All fragments start with a header, so we can make sure we're not receiving
 + * garbage, and we can tell a small 8 byte fragment from an ACK frame.
 + */
 +struct rds_ib_ack_state {
 +      u64             ack_next;
 +      u64             ack_recv;
 +      unsigned int    ack_required:1;
 +      unsigned int    ack_next_valid:1;
 +      unsigned int    ack_recv_valid:1;
 +};
 +
 +
  struct rds_ib_device;
  
  struct rds_ib_connection {
        struct ib_pd            *i_pd;
        struct ib_cq            *i_send_cq;
        struct ib_cq            *i_recv_cq;
 +      struct ib_wc            i_send_wc[RDS_IB_WC_MAX];
 +      struct ib_wc            i_recv_wc[RDS_IB_WC_MAX];
 +
 +      /* interrupt handling */
 +      struct tasklet_struct   i_send_tasklet;
 +      struct tasklet_struct   i_recv_tasklet;
  
        /* tx */
        struct rds_ib_work_ring i_send_ring;
        atomic_t                i_signaled_sends;
  
        /* rx */
 -      struct tasklet_struct   i_recv_tasklet;
        struct mutex            i_recv_mutex;
        struct rds_ib_work_ring i_recv_ring;
        struct rds_ib_incoming  *i_ibinc;
  struct rds_ib_ipaddr {
        struct list_head        list;
        __be32                  ipaddr;
 +      struct rcu_head         rcu;
 +};
 +
 +enum {
 +      RDS_IB_MR_8K_POOL,
 +      RDS_IB_MR_1M_POOL,
  };
  
  struct rds_ib_device {
        struct list_head        conn_list;
        struct ib_device        *dev;
        struct ib_pd            *pd;
 -      struct rds_ib_mr_pool   *mr_pool;
 -      unsigned int            fmr_max_remaps;
        unsigned int            max_fmrs;
 +      struct rds_ib_mr_pool   *mr_1m_pool;
 +      struct rds_ib_mr_pool   *mr_8k_pool;
 +      unsigned int            fmr_max_remaps;
 +      unsigned int            max_8k_fmrs;
 +      unsigned int            max_1m_fmrs;
        int                     max_sge;
        unsigned int            max_wrs;
        unsigned int            max_initiator_depth;
  struct rds_ib_statistics {
        uint64_t        s_ib_connect_raced;
        uint64_t        s_ib_listen_closed_stale;
 -      uint64_t        s_ib_tx_cq_call;
 +      uint64_t        s_ib_evt_handler_call;
 +      uint64_t        s_ib_tasklet_call;
        uint64_t        s_ib_tx_cq_event;
        uint64_t        s_ib_tx_ring_full;
        uint64_t        s_ib_tx_throttle;
        uint64_t        s_ib_tx_sg_mapping_failure;
        uint64_t        s_ib_tx_stalled;
        uint64_t        s_ib_tx_credit_updates;
 -      uint64_t        s_ib_rx_cq_call;
        uint64_t        s_ib_rx_cq_event;
        uint64_t        s_ib_rx_ring_empty;
        uint64_t        s_ib_rx_refill_from_cq;
        uint64_t        s_ib_ack_send_delayed;
        uint64_t        s_ib_ack_send_piggybacked;
        uint64_t        s_ib_ack_received;
 -      uint64_t        s_ib_rdma_mr_alloc;
 -      uint64_t        s_ib_rdma_mr_free;
 -      uint64_t        s_ib_rdma_mr_used;
 -      uint64_t        s_ib_rdma_mr_pool_flush;
 -      uint64_t        s_ib_rdma_mr_pool_wait;
 -      uint64_t        s_ib_rdma_mr_pool_depleted;
 +      uint64_t        s_ib_rdma_mr_8k_alloc;
 +      uint64_t        s_ib_rdma_mr_8k_free;
 +      uint64_t        s_ib_rdma_mr_8k_used;
 +      uint64_t        s_ib_rdma_mr_8k_pool_flush;
 +      uint64_t        s_ib_rdma_mr_8k_pool_wait;
 +      uint64_t        s_ib_rdma_mr_8k_pool_depleted;
 +      uint64_t        s_ib_rdma_mr_1m_alloc;
 +      uint64_t        s_ib_rdma_mr_1m_free;
 +      uint64_t        s_ib_rdma_mr_1m_used;
 +      uint64_t        s_ib_rdma_mr_1m_pool_flush;
 +      uint64_t        s_ib_rdma_mr_1m_pool_wait;
 +      uint64_t        s_ib_rdma_mr_1m_pool_depleted;
        uint64_t        s_ib_atomic_cswp;
        uint64_t        s_ib_atomic_fadd;
  };
@@@ -313,8 -277,7 +317,8 @@@ struct rds_ib_device *rds_ib_get_client
  void rds_ib_dev_put(struct rds_ib_device *rds_ibdev);
  extern struct ib_client rds_ib_client;
  
 -extern unsigned int fmr_message_size;
 +extern unsigned int rds_ib_fmr_1m_pool_size;
 +extern unsigned int rds_ib_fmr_8k_pool_size;
  extern unsigned int rds_ib_retry_count;
  
  extern spinlock_t ib_nodev_conns_lock;
@@@ -344,8 -307,7 +348,8 @@@ int rds_ib_update_ipaddr(struct rds_ib_
  void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
  void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
  void rds_ib_destroy_nodev_conns(void);
 -struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *);
 +struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_dev,
 +                                           int npages);
  void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
  void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
  void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
@@@ -365,8 -327,7 +369,8 @@@ void rds_ib_recv_free_caches(struct rds
  void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp);
  void rds_ib_inc_free(struct rds_incoming *inc);
  int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iov_iter *to);
 -void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context);
 +void rds_ib_recv_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc,
 +                           struct rds_ib_ack_state *state);
  void rds_ib_recv_tasklet_fn(unsigned long data);
  void rds_ib_recv_init_ring(struct rds_ib_connection *ic);
  void rds_ib_recv_clear_ring(struct rds_ib_connection *ic);
@@@ -374,7 -335,6 +378,7 @@@ void rds_ib_recv_init_ack(struct rds_ib
  void rds_ib_attempt_ack(struct rds_ib_connection *ic);
  void rds_ib_ack_send_complete(struct rds_ib_connection *ic);
  u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic);
 +void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq, int ack_required);
  
  /* ib_ring.c */
  void rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr);
@@@ -392,7 -352,7 +396,7 @@@ extern wait_queue_head_t rds_ib_ring_em
  void rds_ib_xmit_complete(struct rds_connection *conn);
  int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
                unsigned int hdr_off, unsigned int sg, unsigned int off);
 -void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context);
 +void rds_ib_send_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc);
  void rds_ib_send_init_ring(struct rds_ib_connection *ic);
  void rds_ib_send_clear_ring(struct rds_ib_connection *ic);
  int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
diff --combined net/rds/ib_cm.c
index 2b2370e7f356f5db4d23df09356796d0649ee063,f5a98068faf07ddd6df72647dd9bd34876adc6d2..da5a7fb98c77abf0c43f0c4825657874eda89ba3
@@@ -216,96 -216,6 +216,96 @@@ static void rds_ib_cq_event_handler(str
                 event->event, ib_event_msg(event->event), data);
  }
  
 +/* Plucking the oldest entry from the ring can be done concurrently with
 + * the thread refilling the ring.  Each ring operation is protected by
 + * spinlocks and the transient state of refilling doesn't change the
 + * recording of which entry is oldest.
 + *
 + * This relies on IB only calling one cq comp_handler for each cq so that
 + * there will only be one caller of rds_recv_incoming() per RDS connection.
 + */
 +static void rds_ib_cq_comp_handler_recv(struct ib_cq *cq, void *context)
 +{
 +      struct rds_connection *conn = context;
 +      struct rds_ib_connection *ic = conn->c_transport_data;
 +
 +      rdsdebug("conn %p cq %p\n", conn, cq);
 +
 +      rds_ib_stats_inc(s_ib_evt_handler_call);
 +
 +      tasklet_schedule(&ic->i_recv_tasklet);
 +}
 +
 +static void poll_cq(struct rds_ib_connection *ic, struct ib_cq *cq,
 +                  struct ib_wc *wcs,
 +                  struct rds_ib_ack_state *ack_state)
 +{
 +      int nr;
 +      int i;
 +      struct ib_wc *wc;
 +
 +      while ((nr = ib_poll_cq(cq, RDS_IB_WC_MAX, wcs)) > 0) {
 +              for (i = 0; i < nr; i++) {
 +                      wc = wcs + i;
 +                      rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
 +                               (unsigned long long)wc->wr_id, wc->status,
 +                               wc->byte_len, be32_to_cpu(wc->ex.imm_data));
 +
 +                      if (wc->wr_id & RDS_IB_SEND_OP)
 +                              rds_ib_send_cqe_handler(ic, wc);
 +                      else
 +                              rds_ib_recv_cqe_handler(ic, wc, ack_state);
 +              }
 +      }
 +}
 +
 +static void rds_ib_tasklet_fn_send(unsigned long data)
 +{
 +      struct rds_ib_connection *ic = (struct rds_ib_connection *)data;
 +      struct rds_connection *conn = ic->conn;
 +      struct rds_ib_ack_state state;
 +
 +      rds_ib_stats_inc(s_ib_tasklet_call);
 +
 +      memset(&state, 0, sizeof(state));
 +      poll_cq(ic, ic->i_send_cq, ic->i_send_wc, &state);
 +      ib_req_notify_cq(ic->i_send_cq, IB_CQ_NEXT_COMP);
 +      poll_cq(ic, ic->i_send_cq, ic->i_send_wc, &state);
 +
 +      if (rds_conn_up(conn) &&
 +          (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
 +          test_bit(0, &conn->c_map_queued)))
 +              rds_send_xmit(ic->conn);
 +}
 +
 +static void rds_ib_tasklet_fn_recv(unsigned long data)
 +{
 +      struct rds_ib_connection *ic = (struct rds_ib_connection *)data;
 +      struct rds_connection *conn = ic->conn;
 +      struct rds_ib_device *rds_ibdev = ic->rds_ibdev;
 +      struct rds_ib_ack_state state;
 +
 +      if (!rds_ibdev)
 +              rds_conn_drop(conn);
 +
 +      rds_ib_stats_inc(s_ib_tasklet_call);
 +
 +      memset(&state, 0, sizeof(state));
 +      poll_cq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
 +      ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED);
 +      poll_cq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
 +
 +      if (state.ack_next_valid)
 +              rds_ib_set_ack(ic, state.ack_next, state.ack_required);
 +      if (state.ack_recv_valid && state.ack_recv > ic->i_ack_recv) {
 +              rds_send_drop_acked(conn, state.ack_recv, NULL);
 +              ic->i_ack_recv = state.ack_recv;
 +      }
 +
 +      if (rds_conn_up(conn))
 +              rds_ib_attempt_ack(ic);
 +}
 +
  static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
  {
        struct rds_connection *conn = data;
        }
  }
  
 +static void rds_ib_cq_comp_handler_send(struct ib_cq *cq, void *context)
 +{
 +      struct rds_connection *conn = context;
 +      struct rds_ib_connection *ic = conn->c_transport_data;
 +
 +      rdsdebug("conn %p cq %p\n", conn, cq);
 +
 +      rds_ib_stats_inc(s_ib_evt_handler_call);
 +
 +      tasklet_schedule(&ic->i_send_tasklet);
 +}
 +
  /*
   * This needs to be very careful to not leave IS_ERR pointers around for
   * cleanup to trip over.
@@@ -373,8 -271,7 +373,8 @@@ static int rds_ib_setup_qp(struct rds_c
        ic->i_pd = rds_ibdev->pd;
  
        cq_attr.cqe = ic->i_send_ring.w_nr + 1;
 -      ic->i_send_cq = ib_create_cq(dev, rds_ib_send_cq_comp_handler,
 +
 +      ic->i_send_cq = ib_create_cq(dev, rds_ib_cq_comp_handler_send,
                                     rds_ib_cq_event_handler, conn,
                                     &cq_attr);
        if (IS_ERR(ic->i_send_cq)) {
        }
  
        cq_attr.cqe = ic->i_recv_ring.w_nr;
 -      ic->i_recv_cq = ib_create_cq(dev, rds_ib_recv_cq_comp_handler,
 +      ic->i_recv_cq = ib_create_cq(dev, rds_ib_cq_comp_handler_recv,
                                     rds_ib_cq_event_handler, conn,
                                     &cq_attr);
        if (IS_ERR(ic->i_recv_cq)) {
@@@ -668,7 -565,7 +668,7 @@@ int rds_ib_conn_connect(struct rds_conn
  
        /* XXX I wonder what affect the port space has */
        /* delegate cm event handler to rdma_transport */
-       ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+       ic->i_cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, conn,
                                     RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(ic->i_cm_id)) {
                ret = PTR_ERR(ic->i_cm_id);
@@@ -740,7 -637,6 +740,7 @@@ void rds_ib_conn_shutdown(struct rds_co
                wait_event(rds_ib_ring_empty_wait,
                           rds_ib_ring_empty(&ic->i_recv_ring) &&
                           (atomic_read(&ic->i_signaled_sends) == 0));
 +              tasklet_kill(&ic->i_send_tasklet);
                tasklet_kill(&ic->i_recv_tasklet);
  
                /* first destroy the ib state that generates callbacks */
@@@ -847,10 -743,8 +847,10 @@@ int rds_ib_conn_alloc(struct rds_connec
        }
  
        INIT_LIST_HEAD(&ic->ib_node);
 -      tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn,
 -                   (unsigned long) ic);
 +      tasklet_init(&ic->i_send_tasklet, rds_ib_tasklet_fn_send,
 +                   (unsigned long)ic);
 +      tasklet_init(&ic->i_recv_tasklet, rds_ib_tasklet_fn_recv,
 +                   (unsigned long)ic);
        mutex_init(&ic->i_recv_mutex);
  #ifndef KERNEL_HAS_ATOMIC64
        spin_lock_init(&ic->i_ack_lock);
diff --combined net/rds/ib_send.c
index 670882c752e9470e6016fc51b0375006f4a94780,987386e9931b4e024d2880fe41a275d1cc662f7a..eac30bf486d747ce5a78f001de2d65cc5fc7d891
@@@ -195,7 -195,7 +195,7 @@@ void rds_ib_send_init_ring(struct rds_i
  
                send->s_op = NULL;
  
 -              send->s_wr.wr_id = i;
 +              send->s_wr.wr_id = i | RDS_IB_SEND_OP;
                send->s_wr.sg_list = send->s_sge;
                send->s_wr.ex.imm_data = 0;
  
@@@ -237,73 -237,81 +237,73 @@@ static void rds_ib_sub_signaled(struct 
   * unallocs the next free entry in the ring it doesn't alter which is
   * the next to be freed, which is what this is concerned with.
   */
 -void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
 +void rds_ib_send_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
  {
 -      struct rds_connection *conn = context;
 -      struct rds_ib_connection *ic = conn->c_transport_data;
        struct rds_message *rm = NULL;
 -      struct ib_wc wc;
 +      struct rds_connection *conn = ic->conn;
        struct rds_ib_send_work *send;
        u32 completed;
        u32 oldest;
        u32 i = 0;
 -      int ret;
        int nr_sig = 0;
  
 -      rdsdebug("cq %p conn %p\n", cq, conn);
 -      rds_ib_stats_inc(s_ib_tx_cq_call);
 -      ret = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
 -      if (ret)
 -              rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
 -
 -      while (ib_poll_cq(cq, 1, &wc) > 0) {
 -              rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
 -                       (unsigned long long)wc.wr_id, wc.status,
 -                       ib_wc_status_msg(wc.status), wc.byte_len,
 -                       be32_to_cpu(wc.ex.imm_data));
 -              rds_ib_stats_inc(s_ib_tx_cq_event);
 -
 -              if (wc.wr_id == RDS_IB_ACK_WR_ID) {
 -                      if (time_after(jiffies, ic->i_ack_queued + HZ/2))
 -                              rds_ib_stats_inc(s_ib_tx_stalled);
 -                      rds_ib_ack_send_complete(ic);
 -                      continue;
 -              }
  
 -              oldest = rds_ib_ring_oldest(&ic->i_send_ring);
 +      rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
 +               (unsigned long long)wc->wr_id, wc->status,
 +               ib_wc_status_msg(wc->status), wc->byte_len,
 +               be32_to_cpu(wc->ex.imm_data));
 +      rds_ib_stats_inc(s_ib_tx_cq_event);
  
 -              completed = rds_ib_ring_completed(&ic->i_send_ring, wc.wr_id, oldest);
 +      if (wc->wr_id == RDS_IB_ACK_WR_ID) {
 +              if (time_after(jiffies, ic->i_ack_queued + HZ / 2))
 +                      rds_ib_stats_inc(s_ib_tx_stalled);
 +              rds_ib_ack_send_complete(ic);
 +              return;
 +      }
  
 -              for (i = 0; i < completed; i++) {
 -                      send = &ic->i_sends[oldest];
 -                      if (send->s_wr.send_flags & IB_SEND_SIGNALED)
 -                              nr_sig++;
 +      oldest = rds_ib_ring_oldest(&ic->i_send_ring);
  
 -                      rm = rds_ib_send_unmap_op(ic, send, wc.status);
 +      completed = rds_ib_ring_completed(&ic->i_send_ring,
 +                                        (wc->wr_id & ~RDS_IB_SEND_OP),
 +                                        oldest);
  
 -                      if (time_after(jiffies, send->s_queued + HZ/2))
 -                              rds_ib_stats_inc(s_ib_tx_stalled);
 +      for (i = 0; i < completed; i++) {
 +              send = &ic->i_sends[oldest];
 +              if (send->s_wr.send_flags & IB_SEND_SIGNALED)
 +                      nr_sig++;
  
 -                      if (send->s_op) {
 -                              if (send->s_op == rm->m_final_op) {
 -                                      /* If anyone waited for this message to get flushed out, wake
 -                                       * them up now */
 -                                      rds_message_unmapped(rm);
 -                              }
 -                              rds_message_put(rm);
 -                              send->s_op = NULL;
 -                      }
 +              rm = rds_ib_send_unmap_op(ic, send, wc->status);
 +
 +              if (time_after(jiffies, send->s_queued + HZ / 2))
 +                      rds_ib_stats_inc(s_ib_tx_stalled);
  
 -                      oldest = (oldest + 1) % ic->i_send_ring.w_nr;
 +              if (send->s_op) {
 +                      if (send->s_op == rm->m_final_op) {
 +                              /* If anyone waited for this message to get
 +                               * flushed out, wake them up now
 +                               */
 +                              rds_message_unmapped(rm);
 +                      }
 +                      rds_message_put(rm);
 +                      send->s_op = NULL;
                }
  
 -              rds_ib_ring_free(&ic->i_send_ring, completed);
 -              rds_ib_sub_signaled(ic, nr_sig);
 -              nr_sig = 0;
 +              oldest = (oldest + 1) % ic->i_send_ring.w_nr;
 +      }
  
 -              if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
 -                  test_bit(0, &conn->c_map_queued))
 -                      queue_delayed_work(rds_wq, &conn->c_send_w, 0);
 +      rds_ib_ring_free(&ic->i_send_ring, completed);
 +      rds_ib_sub_signaled(ic, nr_sig);
 +      nr_sig = 0;
  
 -              /* We expect errors as the qp is drained during shutdown */
 -              if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
 -                      rds_ib_conn_error(conn, "send completion on %pI4 had status "
 -                                        "%u (%s), disconnecting and reconnecting\n",
 -                                        &conn->c_faddr, wc.status,
 -                                        ib_wc_status_msg(wc.status));
 -              }
 +      if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
 +          test_bit(0, &conn->c_map_queued))
 +              queue_delayed_work(rds_wq, &conn->c_send_w, 0);
 +
 +      /* We expect errors as the qp is drained during shutdown */
 +      if (wc->status != IB_WC_SUCCESS && rds_conn_up(conn)) {
 +              rds_ib_conn_error(conn, "send completion on %pI4 had status %u (%s), disconnecting and reconnecting\n",
 +                                &conn->c_faddr, wc->status,
 +                                ib_wc_status_msg(wc->status));
        }
  }
  
@@@ -777,23 -785,23 +777,23 @@@ int rds_ib_xmit_atomic(struct rds_conne
        send->s_queued = jiffies;
  
        if (op->op_type == RDS_ATOMIC_TYPE_CSWP) {
-               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
-               send->s_wr.wr.atomic.compare_add = op->op_m_cswp.compare;
-               send->s_wr.wr.atomic.swap = op->op_m_cswp.swap;
-               send->s_wr.wr.atomic.compare_add_mask = op->op_m_cswp.compare_mask;
-               send->s_wr.wr.atomic.swap_mask = op->op_m_cswp.swap_mask;
+               send->s_atomic_wr.wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
+               send->s_atomic_wr.compare_add = op->op_m_cswp.compare;
+               send->s_atomic_wr.swap = op->op_m_cswp.swap;
+               send->s_atomic_wr.compare_add_mask = op->op_m_cswp.compare_mask;
+               send->s_atomic_wr.swap_mask = op->op_m_cswp.swap_mask;
        } else { /* FADD */
-               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
-               send->s_wr.wr.atomic.compare_add = op->op_m_fadd.add;
-               send->s_wr.wr.atomic.swap = 0;
-               send->s_wr.wr.atomic.compare_add_mask = op->op_m_fadd.nocarry_mask;
-               send->s_wr.wr.atomic.swap_mask = 0;
+               send->s_atomic_wr.wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
+               send->s_atomic_wr.compare_add = op->op_m_fadd.add;
+               send->s_atomic_wr.swap = 0;
+               send->s_atomic_wr.compare_add_mask = op->op_m_fadd.nocarry_mask;
+               send->s_atomic_wr.swap_mask = 0;
        }
        nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify);
-       send->s_wr.num_sge = 1;
-       send->s_wr.next = NULL;
-       send->s_wr.wr.atomic.remote_addr = op->op_remote_addr;
-       send->s_wr.wr.atomic.rkey = op->op_rkey;
+       send->s_atomic_wr.wr.num_sge = 1;
+       send->s_atomic_wr.wr.next = NULL;
+       send->s_atomic_wr.remote_addr = op->op_remote_addr;
+       send->s_atomic_wr.rkey = op->op_rkey;
        send->s_op = op;
        rds_message_addref(container_of(send->s_op, struct rds_message, atomic));
  
        if (nr_sig)
                atomic_add(nr_sig, &ic->i_signaled_sends);
  
-       failed_wr = &send->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &send->s_wr, &failed_wr);
+       failed_wr = &send->s_atomic_wr.wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &send->s_atomic_wr.wr, &failed_wr);
        rdsdebug("ic %p send %p (wr %p) ret %d wr %p\n", ic,
-                send, &send->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &send->s_wr);
+                send, &send->s_atomic_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &send->s_atomic_wr.wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IB: atomic ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
                goto out;
        }
  
-       if (unlikely(failed_wr != &send->s_wr)) {
+       if (unlikely(failed_wr != &send->s_atomic_wr.wr)) {
                printk(KERN_WARNING "RDS/IB: atomic ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
-               BUG_ON(failed_wr != &send->s_wr);
+               BUG_ON(failed_wr != &send->s_atomic_wr.wr);
        }
  
  out:
@@@ -904,22 -912,23 +904,23 @@@ int rds_ib_xmit_rdma(struct rds_connect
                nr_sig += rds_ib_set_wr_signal_state(ic, send, op->op_notify);
  
                send->s_wr.opcode = op->op_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
-               send->s_wr.wr.rdma.remote_addr = remote_addr;
-               send->s_wr.wr.rdma.rkey = op->op_rkey;
+               send->s_rdma_wr.remote_addr = remote_addr;
+               send->s_rdma_wr.rkey = op->op_rkey;
  
                if (num_sge > max_sge) {
-                       send->s_wr.num_sge = max_sge;
+                       send->s_rdma_wr.wr.num_sge = max_sge;
                        num_sge -= max_sge;
                } else {
-                       send->s_wr.num_sge = num_sge;
+                       send->s_rdma_wr.wr.num_sge = num_sge;
                }
  
-               send->s_wr.next = NULL;
+               send->s_rdma_wr.wr.next = NULL;
  
                if (prev)
-                       prev->s_wr.next = &send->s_wr;
+                       prev->s_rdma_wr.wr.next = &send->s_rdma_wr.wr;
  
-               for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
+               for (j = 0; j < send->s_rdma_wr.wr.num_sge &&
+                    scat != &op->op_sg[op->op_count]; j++) {
                        len = ib_sg_dma_len(ic->i_cm_id->device, scat);
                        send->s_sge[j].addr =
                                 ib_sg_dma_address(ic->i_cm_id->device, scat);
                }
  
                rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                       &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+                       &send->s_rdma_wr.wr,
+                       send->s_rdma_wr.wr.num_sge,
+                       send->s_rdma_wr.wr.next);
  
                prev = send;
                if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
        if (nr_sig)
                atomic_add(nr_sig, &ic->i_signaled_sends);
  
-       failed_wr = &first->s_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       failed_wr = &first->s_rdma_wr.wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_rdma_wr.wr, &failed_wr);
        rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_wr);
+                first, &first->s_rdma_wr.wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_rdma_wr.wr);
        if (ret) {
                printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
                goto out;
        }
  
-       if (unlikely(failed_wr != &first->s_wr)) {
+       if (unlikely(failed_wr != &first->s_rdma_wr.wr)) {
                printk(KERN_WARNING "RDS/IB: ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
-               BUG_ON(failed_wr != &first->s_wr);
+               BUG_ON(failed_wr != &first->s_rdma_wr.wr);
        }
  
  
diff --combined net/rds/iw_rdma.c
index d3d4454ffc84c6603397976e8c027b62c3300fbe,47bd68451ff7417e267ff7a9812d03c954deb1eb..b09a40c1adceebf170617da3826c82002b04807a
@@@ -47,7 -47,6 +47,6 @@@ struct rds_iw_mr 
        struct rdma_cm_id       *cm_id;
  
        struct ib_mr    *mr;
-       struct ib_fast_reg_page_list *page_list;
  
        struct rds_iw_mapping   mapping;
        unsigned char           remap_count;
@@@ -75,10 -74,10 +74,10 @@@ struct rds_iw_mr_pool 
        int                     max_pages;
  };
  
 -static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all);
 +static void rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all);
  static void rds_iw_mr_pool_flush_worker(struct work_struct *work);
- static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
- static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
+ static int rds_iw_init_reg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
+ static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
                          struct rds_iw_mr *ibmr,
                          struct scatterlist *sg, unsigned int nents);
  static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
@@@ -258,19 -257,18 +257,18 @@@ static void rds_iw_set_scatterlist(stru
        sg->bytes = 0;
  }
  
- static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
-                       struct rds_iw_scatterlist *sg)
+ static int rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
+                                 struct rds_iw_scatterlist *sg)
  {
        struct ib_device *dev = rds_iwdev->dev;
-       u64 *dma_pages = NULL;
-       int i, j, ret;
+       int i, ret;
  
        WARN_ON(sg->dma_len);
  
        sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
        if (unlikely(!sg->dma_len)) {
                printk(KERN_WARNING "RDS/IW: dma_map_sg failed!\n");
-               return ERR_PTR(-EBUSY);
+               return -EBUSY;
        }
  
        sg->bytes = 0;
        if (sg->dma_npages > fastreg_message_size)
                goto out_unmap;
  
-       dma_pages = kmalloc(sizeof(u64) * sg->dma_npages, GFP_ATOMIC);
-       if (!dma_pages) {
-               ret = -ENOMEM;
-               goto out_unmap;
-       }
  
-       for (i = j = 0; i < sg->dma_len; ++i) {
-               unsigned int dma_len = ib_sg_dma_len(dev, &sg->list[i]);
-               u64 dma_addr = ib_sg_dma_address(dev, &sg->list[i]);
-               u64 end_addr;
  
-               end_addr = dma_addr + dma_len;
-               dma_addr &= ~PAGE_MASK;
-               for (; dma_addr < end_addr; dma_addr += PAGE_SIZE)
-                       dma_pages[j++] = dma_addr;
-               BUG_ON(j > sg->dma_npages);
-       }
-       return dma_pages;
+       return 0;
  
  out_unmap:
        ib_dma_unmap_sg(rds_iwdev->dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
        sg->dma_len = 0;
-       kfree(dma_pages);
-       return ERR_PTR(ret);
+       return ret;
  }
  
  
@@@ -440,7 -421,7 +421,7 @@@ static struct rds_iw_mr *rds_iw_alloc_m
        INIT_LIST_HEAD(&ibmr->mapping.m_list);
        ibmr->mapping.m_mr = ibmr;
  
-       err = rds_iw_init_fastreg(pool, ibmr);
+       err = rds_iw_init_reg(pool, ibmr);
        if (err)
                goto out_no_cigar;
  
@@@ -479,13 -460,14 +460,13 @@@ void rds_iw_sync_mr(void *trans_private
   * If the number of MRs allocated exceeds the limit, we also try
   * to free as many MRs as needed to get back to this limit.
   */
 -static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
 +static void rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
  {
        struct rds_iw_mr *ibmr, *next;
        LIST_HEAD(unmap_list);
        LIST_HEAD(kill_list);
        unsigned long flags;
        unsigned int nfreed = 0, ncleaned = 0, unpinned = 0;
 -      int ret = 0;
  
        rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
  
        atomic_sub(nfreed, &pool->item_count);
  
        mutex_unlock(&pool->flush_lock);
 -      return ret;
  }
  
  static void rds_iw_mr_pool_flush_worker(struct work_struct *work)
@@@ -620,7 -603,7 +601,7 @@@ void *rds_iw_get_mr(struct scatterlist 
        ibmr->cm_id = cm_id;
        ibmr->device = rds_iwdev;
  
-       ret = rds_iw_map_fastreg(rds_iwdev->mr_pool, ibmr, sg, nents);
+       ret = rds_iw_map_reg(rds_iwdev->mr_pool, ibmr, sg, nents);
        if (ret == 0)
                *key_ret = ibmr->mr->rkey;
        else
@@@ -636,7 -619,7 +617,7 @@@ out
  }
  
  /*
-  * iWARP fastreg handling
+  * iWARP reg handling
   *
   * The life cycle of a fastreg registration is a bit different from
   * FMRs.
   * This creates a bit of a problem for us, as we do not have the destination
   * IP in GET_MR, so the connection must be setup prior to the GET_MR call for
   * RDMA to be correctly setup.  If a fastreg request is present, rds_iw_xmit
-  * will try to queue a LOCAL_INV (if needed) and a FAST_REG_MR work request
+  * will try to queue a LOCAL_INV (if needed) and a REG_MR work request
   * before queuing the SEND. When completions for these arrive, they are
   * dispatched to the MR has a bit set showing that RDMa can be performed.
   *
   * The expectation there is that this invalidation step includes ALL
   * PREVIOUSLY FREED MRs.
   */
- static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool,
-                               struct rds_iw_mr *ibmr)
+ static int rds_iw_init_reg(struct rds_iw_mr_pool *pool,
+                          struct rds_iw_mr *ibmr)
  {
        struct rds_iw_device *rds_iwdev = pool->device;
-       struct ib_fast_reg_page_list *page_list = NULL;
        struct ib_mr *mr;
        int err;
  
                return err;
        }
  
-       /* FIXME - this is overkill, but mapping->m_sg.dma_len/mapping->m_sg.dma_npages
-        * is not filled in.
-        */
-       page_list = ib_alloc_fast_reg_page_list(rds_iwdev->dev, pool->max_message_size);
-       if (IS_ERR(page_list)) {
-               err = PTR_ERR(page_list);
-               printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_page_list failed (err=%d)\n", err);
-               ib_dereg_mr(mr);
-               return err;
-       }
-       ibmr->page_list = page_list;
        ibmr->mr = mr;
        return 0;
  }
  
- static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping)
+ static int rds_iw_rdma_reg_mr(struct rds_iw_mapping *mapping)
  {
        struct rds_iw_mr *ibmr = mapping->m_mr;
-       struct ib_send_wr f_wr, *failed_wr;
-       int ret;
+       struct rds_iw_scatterlist *m_sg = &mapping->m_sg;
+       struct ib_reg_wr reg_wr;
+       struct ib_send_wr *failed_wr;
+       int ret, n;
+       n = ib_map_mr_sg_zbva(ibmr->mr, m_sg->list, m_sg->len, PAGE_SIZE);
+       if (unlikely(n != m_sg->len))
+               return n < 0 ? n : -EINVAL;
+       reg_wr.wr.next = NULL;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = RDS_IW_REG_WR_ID;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = ibmr->mr;
+       reg_wr.key = mapping->m_rkey;
+       reg_wr.access = IB_ACCESS_LOCAL_WRITE |
+                       IB_ACCESS_REMOTE_READ |
+                       IB_ACCESS_REMOTE_WRITE;
  
        /*
-        * Perform a WR for the fast_reg_mr. Each individual page
+        * Perform a WR for the reg_mr. Each individual page
         * in the sg list is added to the fast reg page list and placed
-        * inside the fast_reg_mr WR.  The key used is a rolling 8bit
+        * inside the reg_mr WR.  The key used is a rolling 8bit
         * counter, which should guarantee uniqueness.
         */
        ib_update_fast_reg_key(ibmr->mr, ibmr->remap_count++);
        mapping->m_rkey = ibmr->mr->rkey;
  
-       memset(&f_wr, 0, sizeof(f_wr));
-       f_wr.wr_id = RDS_IW_FAST_REG_WR_ID;
-       f_wr.opcode = IB_WR_FAST_REG_MR;
-       f_wr.wr.fast_reg.length = mapping->m_sg.bytes;
-       f_wr.wr.fast_reg.rkey = mapping->m_rkey;
-       f_wr.wr.fast_reg.page_list = ibmr->page_list;
-       f_wr.wr.fast_reg.page_list_len = mapping->m_sg.dma_len;
-       f_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE |
-                               IB_ACCESS_REMOTE_READ |
-                               IB_ACCESS_REMOTE_WRITE;
-       f_wr.wr.fast_reg.iova_start = 0;
-       f_wr.send_flags = IB_SEND_SIGNALED;
-       failed_wr = &f_wr;
-       ret = ib_post_send(ibmr->cm_id->qp, &f_wr, &failed_wr);
-       BUG_ON(failed_wr != &f_wr);
+       failed_wr = &reg_wr.wr;
+       ret = ib_post_send(ibmr->cm_id->qp, &reg_wr.wr, &failed_wr);
+       BUG_ON(failed_wr != &reg_wr.wr);
        if (ret)
                printk_ratelimited(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
                        __func__, __LINE__, ret);
@@@ -754,21 -725,20 +723,20 @@@ out
        return ret;
  }
  
- static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
-                       struct rds_iw_mr *ibmr,
-                       struct scatterlist *sg,
-                       unsigned int sg_len)
+ static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
+                         struct rds_iw_mr *ibmr,
+                         struct scatterlist *sg,
+                         unsigned int sg_len)
  {
        struct rds_iw_device *rds_iwdev = pool->device;
        struct rds_iw_mapping *mapping = &ibmr->mapping;
        u64 *dma_pages;
-       int i, ret = 0;
+       int ret = 0;
  
        rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len);
  
-       dma_pages = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
-       if (IS_ERR(dma_pages)) {
-               ret = PTR_ERR(dma_pages);
+       ret = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
+       if (ret) {
                dma_pages = NULL;
                goto out;
        }
                goto out;
        }
  
-       for (i = 0; i < mapping->m_sg.dma_npages; ++i)
-               ibmr->page_list->page_list[i] = dma_pages[i];
-       ret = rds_iw_rdma_build_fastreg(mapping);
+       ret = rds_iw_rdma_reg_mr(mapping);
        if (ret)
                goto out;
  
@@@ -867,8 -834,6 +832,6 @@@ static unsigned int rds_iw_unmap_fastre
  static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool,
                struct rds_iw_mr *ibmr)
  {
-       if (ibmr->page_list)
-               ib_free_fast_reg_page_list(ibmr->page_list);
        if (ibmr->mr)
                ib_dereg_mr(ibmr->mr);
  }
index 0a362397e434fe9a126bcd94a3f2bba99b89ea2f,a1434447b0d6ae9a937a7d9d90c51660de8717b6..88cf9e7269c2bd0d626bc64448254be73f602940
@@@ -151,9 -151,13 +151,13 @@@ __frwr_init(struct rpcrdma_mw *r, struc
        f->fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth);
        if (IS_ERR(f->fr_mr))
                goto out_mr_err;
-       f->fr_pgl = ib_alloc_fast_reg_page_list(device, depth);
-       if (IS_ERR(f->fr_pgl))
+       f->sg = kcalloc(depth, sizeof(*f->sg), GFP_KERNEL);
+       if (!f->sg)
                goto out_list_err;
+       sg_init_table(f->sg, depth);
        return 0;
  
  out_mr_err:
        return rc;
  
  out_list_err:
-       rc = PTR_ERR(f->fr_pgl);
-       dprintk("RPC:       %s: ib_alloc_fast_reg_page_list status %i\n",
-               __func__, rc);
+       rc = -ENOMEM;
+       dprintk("RPC:       %s: sg allocation failure\n",
+               __func__);
        ib_dereg_mr(f->fr_mr);
        return rc;
  }
@@@ -179,7 -183,7 +183,7 @@@ __frwr_release(struct rpcrdma_mw *r
        if (rc)
                dprintk("RPC:       %s: ib_dereg_mr status %i\n",
                        __func__, rc);
-       ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
+       kfree(r->r.frmr.sg);
  }
  
  static int
@@@ -252,11 -256,8 +256,11 @@@ frwr_sendcompletion(struct ib_wc *wc
  
        /* WARNING: Only wr_id and status are reliable at this point */
        r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
 -      pr_warn("RPC:       %s: frmr %p flushed, status %s (%d)\n",
 -              __func__, r, ib_wc_status_msg(wc->status), wc->status);
 +      if (wc->status == IB_WC_WR_FLUSH_ERR)
 +              dprintk("RPC:       %s: frmr %p flushed\n", __func__, r);
 +      else
 +              pr_warn("RPC:       %s: frmr %p error, status %s (%d)\n",
 +                      __func__, r, ib_wc_status_msg(wc->status), wc->status);
        r->r.frmr.fr_state = FRMR_IS_STALE;
  }
  
@@@ -315,13 -316,10 +319,10 @@@ frwr_op_map(struct rpcrdma_xprt *r_xprt
        struct rpcrdma_mw *mw;
        struct rpcrdma_frmr *frmr;
        struct ib_mr *mr;
-       struct ib_send_wr fastreg_wr, *bad_wr;
+       struct ib_reg_wr reg_wr;
+       struct ib_send_wr *bad_wr;
+       int rc, i, n, dma_nents;
        u8 key;
-       int len, pageoff;
-       int i, rc;
-       int seg_len;
-       u64 pa;
-       int page_no;
  
        mw = seg1->rl_mw;
        seg1->rl_mw = NULL;
        } while (mw->r.frmr.fr_state != FRMR_IS_INVALID);
        frmr = &mw->r.frmr;
        frmr->fr_state = FRMR_IS_VALID;
+       mr = frmr->fr_mr;
  
-       pageoff = offset_in_page(seg1->mr_offset);
-       seg1->mr_offset -= pageoff;     /* start of page */
-       seg1->mr_len += pageoff;
-       len = -pageoff;
        if (nsegs > ia->ri_max_frmr_depth)
                nsegs = ia->ri_max_frmr_depth;
  
-       for (page_no = i = 0; i < nsegs;) {
-               rpcrdma_map_one(device, seg, direction);
-               pa = seg->mr_dma;
-               for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
-                       frmr->fr_pgl->page_list[page_no++] = pa;
-                       pa += PAGE_SIZE;
-               }
-               len += seg->mr_len;
+       for (i = 0; i < nsegs;) {
+               if (seg->mr_page)
+                       sg_set_page(&frmr->sg[i],
+                                   seg->mr_page,
+                                   seg->mr_len,
+                                   offset_in_page(seg->mr_offset));
+               else
+                       sg_set_buf(&frmr->sg[i], seg->mr_offset,
+                                  seg->mr_len);
                ++seg;
                ++i;
                /* Check for holes */
                if ((i < nsegs && offset_in_page(seg->mr_offset)) ||
                    offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
                        break;
        }
-       dprintk("RPC:       %s: Using frmr %p to map %d segments (%d bytes)\n",
-               __func__, mw, i, len);
-       memset(&fastreg_wr, 0, sizeof(fastreg_wr));
-       fastreg_wr.wr_id = (unsigned long)(void *)mw;
-       fastreg_wr.opcode = IB_WR_FAST_REG_MR;
-       fastreg_wr.wr.fast_reg.iova_start = seg1->mr_dma + pageoff;
-       fastreg_wr.wr.fast_reg.page_list = frmr->fr_pgl;
-       fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       fastreg_wr.wr.fast_reg.page_list_len = page_no;
-       fastreg_wr.wr.fast_reg.length = len;
-       fastreg_wr.wr.fast_reg.access_flags = writing ?
-                               IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
-                               IB_ACCESS_REMOTE_READ;
-       mr = frmr->fr_mr;
+       frmr->sg_nents = i;
+       dma_nents = ib_dma_map_sg(device, frmr->sg, frmr->sg_nents, direction);
+       if (!dma_nents) {
+               pr_err("RPC:       %s: failed to dma map sg %p sg_nents %u\n",
+                      __func__, frmr->sg, frmr->sg_nents);
+               return -ENOMEM;
+       }
+       n = ib_map_mr_sg(mr, frmr->sg, frmr->sg_nents, PAGE_SIZE);
+       if (unlikely(n != frmr->sg_nents)) {
+               pr_err("RPC:       %s: failed to map mr %p (%u/%u)\n",
+                      __func__, frmr->fr_mr, n, frmr->sg_nents);
+               rc = n < 0 ? n : -EINVAL;
+               goto out_senderr;
+       }
+       dprintk("RPC:       %s: Using frmr %p to map %u segments (%u bytes)\n",
+               __func__, mw, frmr->sg_nents, mr->length);
        key = (u8)(mr->rkey & 0x000000FF);
        ib_update_fast_reg_key(mr, ++key);
-       fastreg_wr.wr.fast_reg.rkey = mr->rkey;
+       reg_wr.wr.next = NULL;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = (uintptr_t)mw;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.wr.send_flags = 0;
+       reg_wr.mr = mr;
+       reg_wr.key = mr->rkey;
+       reg_wr.access = writing ?
+                       IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
+                       IB_ACCESS_REMOTE_READ;
  
        DECR_CQCOUNT(&r_xprt->rx_ep);
-       rc = ib_post_send(ia->ri_id->qp, &fastreg_wr, &bad_wr);
+       rc = ib_post_send(ia->ri_id->qp, &reg_wr.wr, &bad_wr);
        if (rc)
                goto out_senderr;
  
+       seg1->mr_dir = direction;
        seg1->rl_mw = mw;
        seg1->mr_rkey = mr->rkey;
-       seg1->mr_base = seg1->mr_dma + pageoff;
-       seg1->mr_nsegs = i;
-       seg1->mr_len = len;
-       return i;
+       seg1->mr_base = mr->iova;
+       seg1->mr_nsegs = frmr->sg_nents;
+       seg1->mr_len = mr->length;
+       return frmr->sg_nents;
  
  out_senderr:
        dprintk("RPC:       %s: ib_post_send status %i\n", __func__, rc);
-       while (i--)
-               rpcrdma_unmap_one(device, --seg);
+       ib_dma_unmap_sg(device, frmr->sg, dma_nents, direction);
        __frwr_queue_recovery(mw);
        return rc;
  }
@@@ -405,22 -419,22 +422,22 @@@ frwr_op_unmap(struct rpcrdma_xprt *r_xp
        struct rpcrdma_mr_seg *seg1 = seg;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        struct rpcrdma_mw *mw = seg1->rl_mw;
+       struct rpcrdma_frmr *frmr = &mw->r.frmr;
        struct ib_send_wr invalidate_wr, *bad_wr;
        int rc, nsegs = seg->mr_nsegs;
  
        dprintk("RPC:       %s: FRMR %p\n", __func__, mw);
  
        seg1->rl_mw = NULL;
-       mw->r.frmr.fr_state = FRMR_IS_INVALID;
+       frmr->fr_state = FRMR_IS_INVALID;
  
        memset(&invalidate_wr, 0, sizeof(invalidate_wr));
        invalidate_wr.wr_id = (unsigned long)(void *)mw;
        invalidate_wr.opcode = IB_WR_LOCAL_INV;
-       invalidate_wr.ex.invalidate_rkey = mw->r.frmr.fr_mr->rkey;
+       invalidate_wr.ex.invalidate_rkey = frmr->fr_mr->rkey;
        DECR_CQCOUNT(&r_xprt->rx_ep);
  
-       while (seg1->mr_nsegs--)
-               rpcrdma_unmap_one(ia->ri_device, seg++);
+       ib_dma_unmap_sg(ia->ri_device, frmr->sg, frmr->sg_nents, seg1->mr_dir);
        read_lock(&ia->ri_qplock);
        rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
        read_unlock(&ia->ri_qplock);
index f0c3ff67ca987427136baebf67034ad3bf58a27f,cb0991345816e4ab2c2c99c6242726bef7e6c98a..ff4f01e527ecc08a1480ecba8f00d41a90a76571
@@@ -126,7 -126,7 +126,7 @@@ int rdma_read_chunk_lcl(struct svcxprt_
                        u64 rs_offset,
                        bool last)
  {
-       struct ib_send_wr read_wr;
+       struct ib_rdma_wr read_wr;
        int pages_needed = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
        struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
        int ret, read, pno;
        ctxt->direction = DMA_FROM_DEVICE;
        ctxt->read_hdr = head;
        pages_needed = min_t(int, pages_needed, xprt->sc_max_sge_rd);
 -      read = min_t(int, pages_needed << PAGE_SHIFT, rs_length);
 +      read = min_t(int, (pages_needed << PAGE_SHIFT) - *page_offset,
 +                   rs_length);
  
        for (pno = 0; pno < pages_needed; pno++) {
                int len = min_t(int, rs_length, PAGE_SIZE - pg_off);
                clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
  
        memset(&read_wr, 0, sizeof(read_wr));
-       read_wr.wr_id = (unsigned long)ctxt;
-       read_wr.opcode = IB_WR_RDMA_READ;
-       ctxt->wr_op = read_wr.opcode;
-       read_wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.wr.rdma.rkey = rs_handle;
-       read_wr.wr.rdma.remote_addr = rs_offset;
-       read_wr.sg_list = ctxt->sge;
-       read_wr.num_sge = pages_needed;
-       ret = svc_rdma_send(xprt, &read_wr);
+       read_wr.wr.wr_id = (unsigned long)ctxt;
+       read_wr.wr.opcode = IB_WR_RDMA_READ;
+       ctxt->wr_op = read_wr.wr.opcode;
+       read_wr.wr.send_flags = IB_SEND_SIGNALED;
+       read_wr.rkey = rs_handle;
+       read_wr.remote_addr = rs_offset;
+       read_wr.wr.sg_list = ctxt->sge;
+       read_wr.wr.num_sge = pages_needed;
+       ret = svc_rdma_send(xprt, &read_wr.wr);
        if (ret) {
                pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
                set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@@ -219,14 -218,14 +219,14 @@@ int rdma_read_chunk_frmr(struct svcxprt
                         u64 rs_offset,
                         bool last)
  {
-       struct ib_send_wr read_wr;
+       struct ib_rdma_wr read_wr;
        struct ib_send_wr inv_wr;
-       struct ib_send_wr fastreg_wr;
+       struct ib_reg_wr reg_wr;
        u8 key;
-       int pages_needed = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
+       int nents = PAGE_ALIGN(*page_offset + rs_length) >> PAGE_SHIFT;
        struct svc_rdma_op_ctxt *ctxt = svc_rdma_get_context(xprt);
        struct svc_rdma_fastreg_mr *frmr = svc_rdma_get_frmr(xprt);
-       int ret, read, pno;
+       int ret, read, pno, dma_nents, n;
        u32 pg_off = *page_offset;
        u32 pg_no = *page_no;
  
  
        ctxt->direction = DMA_FROM_DEVICE;
        ctxt->frmr = frmr;
-       pages_needed = min_t(int, pages_needed, xprt->sc_frmr_pg_list_len);
-       read = min_t(int, (pages_needed << PAGE_SHIFT) - *page_offset,
-                    rs_length);
+       nents = min_t(unsigned int, nents, xprt->sc_frmr_pg_list_len);
 -      read = min_t(int, nents << PAGE_SHIFT, rs_length);
++      read = min_t(int, (nents << PAGE_SHIFT) - *page_offset, rs_length);
  
-       frmr->kva = page_address(rqstp->rq_arg.pages[pg_no]);
        frmr->direction = DMA_FROM_DEVICE;
        frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
-       frmr->map_len = pages_needed << PAGE_SHIFT;
-       frmr->page_list_len = pages_needed;
+       frmr->sg_nents = nents;
  
-       for (pno = 0; pno < pages_needed; pno++) {
+       for (pno = 0; pno < nents; pno++) {
                int len = min_t(int, rs_length, PAGE_SIZE - pg_off);
  
                head->arg.pages[pg_no] = rqstp->rq_arg.pages[pg_no];
                head->arg.len += len;
                if (!pg_off)
                        head->count++;
+               sg_set_page(&frmr->sg[pno], rqstp->rq_arg.pages[pg_no],
+                           len, pg_off);
                rqstp->rq_respages = &rqstp->rq_arg.pages[pg_no+1];
                rqstp->rq_next_page = rqstp->rq_respages + 1;
-               frmr->page_list->page_list[pno] =
-                       ib_dma_map_page(xprt->sc_cm_id->device,
-                                       head->arg.pages[pg_no], 0,
-                                       PAGE_SIZE, DMA_FROM_DEVICE);
-               ret = ib_dma_mapping_error(xprt->sc_cm_id->device,
-                                          frmr->page_list->page_list[pno]);
-               if (ret)
-                       goto err;
-               atomic_inc(&xprt->sc_dma_used);
  
                /* adjust offset and wrap to next page if needed */
                pg_off += len;
        else
                clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
  
+       dma_nents = ib_dma_map_sg(xprt->sc_cm_id->device,
+                                 frmr->sg, frmr->sg_nents,
+                                 frmr->direction);
+       if (!dma_nents) {
+               pr_err("svcrdma: failed to dma map sg %p\n",
+                      frmr->sg);
+               return -ENOMEM;
+       }
+       atomic_inc(&xprt->sc_dma_used);
+       n = ib_map_mr_sg(frmr->mr, frmr->sg, frmr->sg_nents, PAGE_SIZE);
+       if (unlikely(n != frmr->sg_nents)) {
+               pr_err("svcrdma: failed to map mr %p (%d/%d elements)\n",
+                      frmr->mr, n, frmr->sg_nents);
+               return n < 0 ? n : -EINVAL;
+       }
        /* Bump the key */
        key = (u8)(frmr->mr->lkey & 0x000000FF);
        ib_update_fast_reg_key(frmr->mr, ++key);
  
-       ctxt->sge[0].addr = (unsigned long)frmr->kva + *page_offset;
+       ctxt->sge[0].addr = frmr->mr->iova;
        ctxt->sge[0].lkey = frmr->mr->lkey;
-       ctxt->sge[0].length = read;
+       ctxt->sge[0].length = frmr->mr->length;
        ctxt->count = 1;
        ctxt->read_hdr = head;
  
-       /* Prepare FASTREG WR */
-       memset(&fastreg_wr, 0, sizeof(fastreg_wr));
-       fastreg_wr.opcode = IB_WR_FAST_REG_MR;
-       fastreg_wr.send_flags = IB_SEND_SIGNALED;
-       fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
-       fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
-       fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
-       fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       fastreg_wr.wr.fast_reg.length = frmr->map_len;
-       fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
-       fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
-       fastreg_wr.next = &read_wr;
+       /* Prepare REG WR */
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.wr_id = 0;
+       reg_wr.wr.send_flags = IB_SEND_SIGNALED;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = frmr->mr;
+       reg_wr.key = frmr->mr->lkey;
+       reg_wr.access = frmr->access_flags;
+       reg_wr.wr.next = &read_wr.wr;
  
        /* Prepare RDMA_READ */
        memset(&read_wr, 0, sizeof(read_wr));
-       read_wr.send_flags = IB_SEND_SIGNALED;
-       read_wr.wr.rdma.rkey = rs_handle;
-       read_wr.wr.rdma.remote_addr = rs_offset;
-       read_wr.sg_list = ctxt->sge;
-       read_wr.num_sge = 1;
+       read_wr.wr.send_flags = IB_SEND_SIGNALED;
+       read_wr.rkey = rs_handle;
+       read_wr.remote_addr = rs_offset;
+       read_wr.wr.sg_list = ctxt->sge;
+       read_wr.wr.num_sge = 1;
        if (xprt->sc_dev_caps & SVCRDMA_DEVCAP_READ_W_INV) {
-               read_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
-               read_wr.wr_id = (unsigned long)ctxt;
-               read_wr.ex.invalidate_rkey = ctxt->frmr->mr->lkey;
+               read_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
+               read_wr.wr.wr_id = (unsigned long)ctxt;
+               read_wr.wr.ex.invalidate_rkey = ctxt->frmr->mr->lkey;
        } else {
-               read_wr.opcode = IB_WR_RDMA_READ;
-               read_wr.next = &inv_wr;
+               read_wr.wr.opcode = IB_WR_RDMA_READ;
+               read_wr.wr.next = &inv_wr;
                /* Prepare invalidate */
                memset(&inv_wr, 0, sizeof(inv_wr));
                inv_wr.wr_id = (unsigned long)ctxt;
                inv_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_FENCE;
                inv_wr.ex.invalidate_rkey = frmr->mr->lkey;
        }
-       ctxt->wr_op = read_wr.opcode;
+       ctxt->wr_op = read_wr.wr.opcode;
  
        /* Post the chain */
-       ret = svc_rdma_send(xprt, &fastreg_wr);
+       ret = svc_rdma_send(xprt, &reg_wr.wr);
        if (ret) {
                pr_err("svcrdma: Error %d posting RDMA_READ\n", ret);
                set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
        atomic_inc(&rdma_stat_read);
        return ret;
   err:
-       svc_rdma_unmap_dma(ctxt);
+       ib_dma_unmap_sg(xprt->sc_cm_id->device,
+                       frmr->sg, frmr->sg_nents, frmr->direction);
        svc_rdma_put_context(ctxt, 0);
        svc_rdma_put_frmr(xprt, frmr);
        return ret;
@@@ -533,7 -539,7 +540,7 @@@ static int rdma_read_complete(struct sv
        rqstp->rq_arg.page_base = head->arg.page_base;
  
        /* rq_respages starts after the last arg page */
 -      rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
 +      rqstp->rq_respages = &rqstp->rq_pages[page_no];
        rqstp->rq_next_page = rqstp->rq_respages + 1;
  
        /* Rebuild rq_arg head and tail. */
index a133b1e5b5f62a0543a7ab0c2e2fb362b726a5bd,a266e870d870e8b2cf0d938c3009460b46fddc7b..b348b4adef29a48246709cc7f32cf576865753eb
@@@ -56,7 -56,6 +56,7 @@@
  
  #define RPCDBG_FACILITY       RPCDBG_SVCXPRT
  
 +static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *, int);
  static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
                                        struct net *net,
                                        struct sockaddr *sa, int salen,
@@@ -96,63 -95,6 +96,63 @@@ struct svc_xprt_class svc_rdma_class = 
        .xcl_ident = XPRT_TRANSPORT_RDMA,
  };
  
 +#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 +static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *, struct net *,
 +                                         struct sockaddr *, int, int);
 +static void svc_rdma_bc_detach(struct svc_xprt *);
 +static void svc_rdma_bc_free(struct svc_xprt *);
 +
 +static struct svc_xprt_ops svc_rdma_bc_ops = {
 +      .xpo_create = svc_rdma_bc_create,
 +      .xpo_detach = svc_rdma_bc_detach,
 +      .xpo_free = svc_rdma_bc_free,
 +      .xpo_prep_reply_hdr = svc_rdma_prep_reply_hdr,
 +      .xpo_secure_port = svc_rdma_secure_port,
 +};
 +
 +struct svc_xprt_class svc_rdma_bc_class = {
 +      .xcl_name = "rdma-bc",
 +      .xcl_owner = THIS_MODULE,
 +      .xcl_ops = &svc_rdma_bc_ops,
 +      .xcl_max_payload = (1024 - RPCRDMA_HDRLEN_MIN)
 +};
 +
 +static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *serv,
 +                                         struct net *net,
 +                                         struct sockaddr *sa, int salen,
 +                                         int flags)
 +{
 +      struct svcxprt_rdma *cma_xprt;
 +      struct svc_xprt *xprt;
 +
 +      cma_xprt = rdma_create_xprt(serv, 0);
 +      if (!cma_xprt)
 +              return ERR_PTR(-ENOMEM);
 +      xprt = &cma_xprt->sc_xprt;
 +
 +      svc_xprt_init(net, &svc_rdma_bc_class, xprt, serv);
 +      serv->sv_bc_xprt = xprt;
 +
 +      dprintk("svcrdma: %s(%p)\n", __func__, xprt);
 +      return xprt;
 +}
 +
 +static void svc_rdma_bc_detach(struct svc_xprt *xprt)
 +{
 +      dprintk("svcrdma: %s(%p)\n", __func__, xprt);
 +}
 +
 +static void svc_rdma_bc_free(struct svc_xprt *xprt)
 +{
 +      struct svcxprt_rdma *rdma =
 +              container_of(xprt, struct svcxprt_rdma, sc_xprt);
 +
 +      dprintk("svcrdma: %s(%p)\n", __func__, xprt);
 +      if (xprt)
 +              kfree(rdma);
 +}
 +#endif        /* CONFIG_SUNRPC_BACKCHANNEL */
 +
  struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
  {
        struct svc_rdma_op_ctxt *ctxt;
@@@ -750,8 -692,8 +750,8 @@@ static struct svc_xprt *svc_rdma_create
        if (!cma_xprt)
                return ERR_PTR(-ENOMEM);
  
-       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP,
-                                  IB_QPT_RC);
+       listen_id = rdma_create_id(&init_net, rdma_listen_handler, cma_xprt,
+                                  RDMA_PS_TCP, IB_QPT_RC);
        if (IS_ERR(listen_id)) {
                ret = PTR_ERR(listen_id);
                dprintk("svcrdma: rdma_create_id failed = %d\n", ret);
  static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
  {
        struct ib_mr *mr;
-       struct ib_fast_reg_page_list *pl;
+       struct scatterlist *sg;
        struct svc_rdma_fastreg_mr *frmr;
        u32 num_sg;
  
        if (IS_ERR(mr))
                goto err_free_frmr;
  
-       pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
-                                        num_sg);
-       if (IS_ERR(pl))
+       sg = kcalloc(RPCSVC_MAXPAGES, sizeof(*sg), GFP_KERNEL);
+       if (!sg)
                goto err_free_mr;
  
+       sg_init_table(sg, RPCSVC_MAXPAGES);
        frmr->mr = mr;
-       frmr->page_list = pl;
+       frmr->sg = sg;
        INIT_LIST_HEAD(&frmr->frmr_list);
        return frmr;
  
@@@ -829,8 -772,8 +830,8 @@@ static void rdma_dealloc_frmr_q(struct 
                frmr = list_entry(xprt->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
+               kfree(frmr->sg);
                ib_dereg_mr(frmr->mr);
-               ib_free_fast_reg_page_list(frmr->page_list);
                kfree(frmr);
        }
  }
@@@ -844,8 -787,7 +845,7 @@@ struct svc_rdma_fastreg_mr *svc_rdma_ge
                frmr = list_entry(rdma->sc_frmr_q.next,
                                  struct svc_rdma_fastreg_mr, frmr_list);
                list_del_init(&frmr->frmr_list);
-               frmr->map_len = 0;
-               frmr->page_list_len = 0;
+               frmr->sg_nents = 0;
        }
        spin_unlock_bh(&rdma->sc_frmr_q_lock);
        if (frmr)
        return rdma_alloc_frmr(rdma);
  }
  
- static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
-                          struct svc_rdma_fastreg_mr *frmr)
- {
-       int page_no;
-       for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
-               dma_addr_t addr = frmr->page_list->page_list[page_no];
-               if (ib_dma_mapping_error(frmr->mr->device, addr))
-                       continue;
-               atomic_dec(&xprt->sc_dma_used);
-               ib_dma_unmap_page(frmr->mr->device, addr, PAGE_SIZE,
-                                 frmr->direction);
-       }
- }
  void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
                       struct svc_rdma_fastreg_mr *frmr)
  {
        if (frmr) {
-               frmr_unmap_dma(rdma, frmr);
+               ib_dma_unmap_sg(rdma->sc_cm_id->device,
+                               frmr->sg, frmr->sg_nents, frmr->direction);
+               atomic_dec(&rdma->sc_dma_used);
                spin_lock_bh(&rdma->sc_frmr_q_lock);
                WARN_ON_ONCE(!list_empty(&frmr->frmr_list));
                list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
index 93883ffb86e0d0e6244f33d1558d11ac0f1d134b,6c06ba088feac757812cd84309b84b45be75e7bf..eadd1655145a3bc5b81bdefb7015792fb3be566a
   * internal functions
   */
  
 -/*
 - * handle replies in tasklet context, using a single, global list
 - * rdma tasklet function -- just turn around and call the func
 - * for all replies on the list
 - */
 -
 -static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
 -static LIST_HEAD(rpcrdma_tasklets_g);
 +static struct workqueue_struct *rpcrdma_receive_wq;
  
 -static void
 -rpcrdma_run_tasklet(unsigned long data)
 +int
 +rpcrdma_alloc_wq(void)
  {
 -      struct rpcrdma_rep *rep;
 -      unsigned long flags;
 -
 -      data = data;
 -      spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
 -      while (!list_empty(&rpcrdma_tasklets_g)) {
 -              rep = list_entry(rpcrdma_tasklets_g.next,
 -                               struct rpcrdma_rep, rr_list);
 -              list_del(&rep->rr_list);
 -              spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
 +      struct workqueue_struct *recv_wq;
  
 -              rpcrdma_reply_handler(rep);
 +      recv_wq = alloc_workqueue("xprtrdma_receive",
 +                                WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_HIGHPRI,
 +                                0);
 +      if (!recv_wq)
 +              return -ENOMEM;
  
 -              spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
 -      }
 -      spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
 +      rpcrdma_receive_wq = recv_wq;
 +      return 0;
  }
  
 -static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
 -
 -static void
 -rpcrdma_schedule_tasklet(struct list_head *sched_list)
 +void
 +rpcrdma_destroy_wq(void)
  {
 -      unsigned long flags;
 +      struct workqueue_struct *wq;
  
 -      spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
 -      list_splice_tail(sched_list, &rpcrdma_tasklets_g);
 -      spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
 -      tasklet_schedule(&rpcrdma_tasklet_g);
 +      if (rpcrdma_receive_wq) {
 +              wq = rpcrdma_receive_wq;
 +              rpcrdma_receive_wq = NULL;
 +              destroy_workqueue(wq);
 +      }
  }
  
  static void
@@@ -144,54 -158,63 +144,54 @@@ rpcrdma_sendcq_process_wc(struct ib_wc 
        }
  }
  
 -static int
 -rpcrdma_sendcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
 +/* The common case is a single send completion is waiting. By
 + * passing two WC entries to ib_poll_cq, a return code of 1
 + * means there is exactly one WC waiting and no more. We don't
 + * have to invoke ib_poll_cq again to know that the CQ has been
 + * properly drained.
 + */
 +static void
 +rpcrdma_sendcq_poll(struct ib_cq *cq)
  {
 -      struct ib_wc *wcs;
 -      int budget, count, rc;
 +      struct ib_wc *pos, wcs[2];
 +      int count, rc;
  
 -      budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
        do {
 -              wcs = ep->rep_send_wcs;
 +              pos = wcs;
  
 -              rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
 -              if (rc <= 0)
 -                      return rc;
 +              rc = ib_poll_cq(cq, ARRAY_SIZE(wcs), pos);
 +              if (rc < 0)
 +                      break;
  
                count = rc;
                while (count-- > 0)
 -                      rpcrdma_sendcq_process_wc(wcs++);
 -      } while (rc == RPCRDMA_POLLSIZE && --budget);
 -      return 0;
 +                      rpcrdma_sendcq_process_wc(pos++);
 +      } while (rc == ARRAY_SIZE(wcs));
 +      return;
  }
  
 -/*
 - * Handle send, fast_reg_mr, and local_inv completions.
 - *
 - * Send events are typically suppressed and thus do not result
 - * in an upcall. Occasionally one is signaled, however. This
 - * prevents the provider's completion queue from wrapping and
 - * losing a completion.
 +/* Handle provider send completion upcalls.
   */
  static void
  rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context)
  {
 -      struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
 -      int rc;
 -
 -      rc = rpcrdma_sendcq_poll(cq, ep);
 -      if (rc) {
 -              dprintk("RPC:       %s: ib_poll_cq failed: %i\n",
 -                      __func__, rc);
 -              return;
 -      }
 +      do {
 +              rpcrdma_sendcq_poll(cq);
 +      } while (ib_req_notify_cq(cq, IB_CQ_NEXT_COMP |
 +                                IB_CQ_REPORT_MISSED_EVENTS) > 0);
 +}
  
 -      rc = ib_req_notify_cq(cq,
 -                      IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
 -      if (rc == 0)
 -              return;
 -      if (rc < 0) {
 -              dprintk("RPC:       %s: ib_req_notify_cq failed: %i\n",
 -                      __func__, rc);
 -              return;
 -      }
 +static void
 +rpcrdma_receive_worker(struct work_struct *work)
 +{
 +      struct rpcrdma_rep *rep =
 +                      container_of(work, struct rpcrdma_rep, rr_work);
  
 -      rpcrdma_sendcq_poll(cq, ep);
 +      rpcrdma_reply_handler(rep);
  }
  
  static void
 -rpcrdma_recvcq_process_wc(struct ib_wc *wc, struct list_head *sched_list)
 +rpcrdma_recvcq_process_wc(struct ib_wc *wc)
  {
        struct rpcrdma_rep *rep =
                        (struct rpcrdma_rep *)(unsigned long)wc->wr_id;
        prefetch(rdmab_to_msg(rep->rr_rdmabuf));
  
  out_schedule:
 -      list_add_tail(&rep->rr_list, sched_list);
 +      queue_work(rpcrdma_receive_wq, &rep->rr_work);
        return;
 +
  out_fail:
        if (wc->status != IB_WC_WR_FLUSH_ERR)
                pr_err("RPC:       %s: rep %p: %s\n",
                       __func__, rep, ib_wc_status_msg(wc->status));
 -      rep->rr_len = ~0U;
 +      rep->rr_len = RPCRDMA_BAD_LEN;
        goto out_schedule;
  }
  
 -static int
 -rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
 +/* The wc array is on stack: automatic memory is always CPU-local.
 + *
 + * struct ib_wc is 64 bytes, making the poll array potentially
 + * large. But this is at the bottom of the call chain. Further
 + * substantial work is done in another thread.
 + */
 +static void
 +rpcrdma_recvcq_poll(struct ib_cq *cq)
  {
 -      struct list_head sched_list;
 -      struct ib_wc *wcs;
 -      int budget, count, rc;
 +      struct ib_wc *pos, wcs[4];
 +      int count, rc;
  
 -      INIT_LIST_HEAD(&sched_list);
 -      budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
        do {
 -              wcs = ep->rep_recv_wcs;
 +              pos = wcs;
  
 -              rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
 -              if (rc <= 0)
 -                      goto out_schedule;
 +              rc = ib_poll_cq(cq, ARRAY_SIZE(wcs), pos);
 +              if (rc < 0)
 +                      break;
  
                count = rc;
                while (count-- > 0)
 -                      rpcrdma_recvcq_process_wc(wcs++, &sched_list);
 -      } while (rc == RPCRDMA_POLLSIZE && --budget);
 -      rc = 0;
 -
 -out_schedule:
 -      rpcrdma_schedule_tasklet(&sched_list);
 -      return rc;
 +                      rpcrdma_recvcq_process_wc(pos++);
 +      } while (rc == ARRAY_SIZE(wcs));
  }
  
 -/*
 - * Handle receive completions.
 - *
 - * It is reentrant but processes single events in order to maintain
 - * ordering of receives to keep server credits.
 - *
 - * It is the responsibility of the scheduled tasklet to return
 - * recv buffers to the pool. NOTE: this affects synchronization of
 - * connection shutdown. That is, the structures required for
 - * the completion of the reply handler must remain intact until
 - * all memory has been reclaimed.
 +/* Handle provider receive completion upcalls.
   */
  static void
  rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context)
  {
 -      struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
 -      int rc;
 -
 -      rc = rpcrdma_recvcq_poll(cq, ep);
 -      if (rc) {
 -              dprintk("RPC:       %s: ib_poll_cq failed: %i\n",
 -                      __func__, rc);
 -              return;
 -      }
 -
 -      rc = ib_req_notify_cq(cq,
 -                      IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
 -      if (rc == 0)
 -              return;
 -      if (rc < 0) {
 -              dprintk("RPC:       %s: ib_req_notify_cq failed: %i\n",
 -                      __func__, rc);
 -              return;
 -      }
 -
 -      rpcrdma_recvcq_poll(cq, ep);
 +      do {
 +              rpcrdma_recvcq_poll(cq);
 +      } while (ib_req_notify_cq(cq, IB_CQ_NEXT_COMP |
 +                                IB_CQ_REPORT_MISSED_EVENTS) > 0);
  }
  
  static void
  rpcrdma_flush_cqs(struct rpcrdma_ep *ep)
  {
        struct ib_wc wc;
 -      LIST_HEAD(sched_list);
  
        while (ib_poll_cq(ep->rep_attr.recv_cq, 1, &wc) > 0)
 -              rpcrdma_recvcq_process_wc(&wc, &sched_list);
 -      if (!list_empty(&sched_list))
 -              rpcrdma_schedule_tasklet(&sched_list);
 +              rpcrdma_recvcq_process_wc(&wc);
        while (ib_poll_cq(ep->rep_attr.send_cq, 1, &wc) > 0)
                rpcrdma_sendcq_process_wc(&wc);
  }
@@@ -378,7 -432,8 +378,8 @@@ rpcrdma_create_id(struct rpcrdma_xprt *
  
        init_completion(&ia->ri_done);
  
-       id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
+       id = rdma_create_id(&init_net, rpcrdma_conn_upcall, xprt, RDMA_PS_TCP,
+                           IB_QPT_RC);
        if (IS_ERR(id)) {
                rc = PTR_ERR(id);
                dprintk("RPC:       %s: rdma_create_id() failed %i\n",
@@@ -568,7 -623,6 +569,7 @@@ rpcrdma_ep_create(struct rpcrdma_ep *ep
        struct ib_device_attr *devattr = &ia->ri_devattr;
        struct ib_cq *sendcq, *recvcq;
        struct ib_cq_init_attr cq_attr = {};
 +      unsigned int max_qp_wr;
        int rc, err;
  
        if (devattr->max_sge < RPCRDMA_MAX_IOVS) {
                return -ENOMEM;
        }
  
 +      if (devattr->max_qp_wr <= RPCRDMA_BACKWARD_WRS) {
 +              dprintk("RPC:       %s: insufficient wqe's available\n",
 +                      __func__);
 +              return -ENOMEM;
 +      }
 +      max_qp_wr = devattr->max_qp_wr - RPCRDMA_BACKWARD_WRS;
 +
        /* check provider's send/recv wr limits */
 -      if (cdata->max_requests > devattr->max_qp_wr)
 -              cdata->max_requests = devattr->max_qp_wr;
 +      if (cdata->max_requests > max_qp_wr)
 +              cdata->max_requests = max_qp_wr;
  
        ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
        ep->rep_attr.qp_context = ep;
        ep->rep_attr.srq = NULL;
        ep->rep_attr.cap.max_send_wr = cdata->max_requests;
 +      ep->rep_attr.cap.max_send_wr += RPCRDMA_BACKWARD_WRS;
        rc = ia->ri_ops->ro_open(ia, ep, cdata);
        if (rc)
                return rc;
        ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
 +      ep->rep_attr.cap.max_recv_wr += RPCRDMA_BACKWARD_WRS;
        ep->rep_attr.cap.max_send_sge = RPCRDMA_MAX_IOVS;
        ep->rep_attr.cap.max_recv_sge = 1;
        ep->rep_attr.cap.max_inline_data = 0;
  
        cq_attr.cqe = ep->rep_attr.cap.max_send_wr + 1;
        sendcq = ib_create_cq(ia->ri_device, rpcrdma_sendcq_upcall,
 -                            rpcrdma_cq_async_error_upcall, ep, &cq_attr);
 +                            rpcrdma_cq_async_error_upcall, NULL, &cq_attr);
        if (IS_ERR(sendcq)) {
                rc = PTR_ERR(sendcq);
                dprintk("RPC:       %s: failed to create send CQ: %i\n",
  
        cq_attr.cqe = ep->rep_attr.cap.max_recv_wr + 1;
        recvcq = ib_create_cq(ia->ri_device, rpcrdma_recvcq_upcall,
 -                            rpcrdma_cq_async_error_upcall, ep, &cq_attr);
 +                            rpcrdma_cq_async_error_upcall, NULL, &cq_attr);
        if (IS_ERR(recvcq)) {
                rc = PTR_ERR(recvcq);
                dprintk("RPC:       %s: failed to create recv CQ: %i\n",
@@@ -709,22 -754,19 +710,22 @@@ rpcrdma_ep_destroy(struct rpcrdma_ep *e
  
        cancel_delayed_work_sync(&ep->rep_connect_worker);
  
 -      if (ia->ri_id->qp) {
 +      if (ia->ri_id->qp)
                rpcrdma_ep_disconnect(ep, ia);
 +
 +      rpcrdma_clean_cq(ep->rep_attr.recv_cq);
 +      rpcrdma_clean_cq(ep->rep_attr.send_cq);
 +
 +      if (ia->ri_id->qp) {
                rdma_destroy_qp(ia->ri_id);
                ia->ri_id->qp = NULL;
        }
  
 -      rpcrdma_clean_cq(ep->rep_attr.recv_cq);
        rc = ib_destroy_cq(ep->rep_attr.recv_cq);
        if (rc)
                dprintk("RPC:       %s: ib_destroy_cq returned %i\n",
                        __func__, rc);
  
 -      rpcrdma_clean_cq(ep->rep_attr.send_cq);
        rc = ib_destroy_cq(ep->rep_attr.send_cq);
        if (rc)
                dprintk("RPC:       %s: ib_destroy_cq returned %i\n",
@@@ -841,21 -883,7 +842,21 @@@ retry
                }
                rc = ep->rep_connected;
        } else {
 +              struct rpcrdma_xprt *r_xprt;
 +              unsigned int extras;
 +
                dprintk("RPC:       %s: connected\n", __func__);
 +
 +              r_xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
 +              extras = r_xprt->rx_buf.rb_bc_srv_max_requests;
 +
 +              if (extras) {
 +                      rc = rpcrdma_ep_post_extra_recv(r_xprt, extras);
 +                      if (rc)
 +                              pr_warn("%s: rpcrdma_ep_post_extra_recv: %i\n",
 +                                      __func__, rc);
 +                              rc = 0;
 +              }
        }
  
  out:
@@@ -892,25 -920,20 +893,25 @@@ rpcrdma_ep_disconnect(struct rpcrdma_e
        }
  }
  
 -static struct rpcrdma_req *
 +struct rpcrdma_req *
  rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
  {
 +      struct rpcrdma_buffer *buffer = &r_xprt->rx_buf;
        struct rpcrdma_req *req;
  
        req = kzalloc(sizeof(*req), GFP_KERNEL);
        if (req == NULL)
                return ERR_PTR(-ENOMEM);
  
 +      INIT_LIST_HEAD(&req->rl_free);
 +      spin_lock(&buffer->rb_reqslock);
 +      list_add(&req->rl_all, &buffer->rb_allreqs);
 +      spin_unlock(&buffer->rb_reqslock);
        req->rl_buffer = &r_xprt->rx_buf;
        return req;
  }
  
 -static struct rpcrdma_rep *
 +struct rpcrdma_rep *
  rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
  {
        struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
  
        rep->rr_device = ia->ri_device;
        rep->rr_rxprt = r_xprt;
 +      INIT_WORK(&rep->rr_work, rpcrdma_receive_worker);
        return rep;
  
  out_free:
@@@ -946,21 -968,44 +947,21 @@@ rpcrdma_buffer_create(struct rpcrdma_xp
  {
        struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
 -      struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
 -      char *p;
 -      size_t len;
        int i, rc;
  
 -      buf->rb_max_requests = cdata->max_requests;
 +      buf->rb_max_requests = r_xprt->rx_data.max_requests;
 +      buf->rb_bc_srv_max_requests = 0;
        spin_lock_init(&buf->rb_lock);
  
 -      /* Need to allocate:
 -       *   1.  arrays for send and recv pointers
 -       *   2.  arrays of struct rpcrdma_req to fill in pointers
 -       *   3.  array of struct rpcrdma_rep for replies
 -       * Send/recv buffers in req/rep need to be registered
 -       */
 -      len = buf->rb_max_requests *
 -              (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
 -
 -      p = kzalloc(len, GFP_KERNEL);
 -      if (p == NULL) {
 -              dprintk("RPC:       %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
 -                      __func__, len);
 -              rc = -ENOMEM;
 -              goto out;
 -      }
 -      buf->rb_pool = p;       /* for freeing it later */
 -
 -      buf->rb_send_bufs = (struct rpcrdma_req **) p;
 -      p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
 -      buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
 -      p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
 -
        rc = ia->ri_ops->ro_init(r_xprt);
        if (rc)
                goto out;
  
 +      INIT_LIST_HEAD(&buf->rb_send_bufs);
 +      INIT_LIST_HEAD(&buf->rb_allreqs);
 +      spin_lock_init(&buf->rb_reqslock);
        for (i = 0; i < buf->rb_max_requests; i++) {
                struct rpcrdma_req *req;
 -              struct rpcrdma_rep *rep;
  
                req = rpcrdma_create_req(r_xprt);
                if (IS_ERR(req)) {
                        rc = PTR_ERR(req);
                        goto out;
                }
 -              buf->rb_send_bufs[i] = req;
 +              req->rl_backchannel = false;
 +              list_add(&req->rl_free, &buf->rb_send_bufs);
 +      }
 +
 +      INIT_LIST_HEAD(&buf->rb_recv_bufs);
 +      for (i = 0; i < buf->rb_max_requests + 2; i++) {
 +              struct rpcrdma_rep *rep;
  
                rep = rpcrdma_create_rep(r_xprt);
                if (IS_ERR(rep)) {
                        rc = PTR_ERR(rep);
                        goto out;
                }
 -              buf->rb_recv_bufs[i] = rep;
 +              list_add(&rep->rr_list, &buf->rb_recv_bufs);
        }
  
        return 0;
@@@ -993,38 -1032,22 +994,38 @@@ out
        return rc;
  }
  
 +static struct rpcrdma_req *
 +rpcrdma_buffer_get_req_locked(struct rpcrdma_buffer *buf)
 +{
 +      struct rpcrdma_req *req;
 +
 +      req = list_first_entry(&buf->rb_send_bufs,
 +                             struct rpcrdma_req, rl_free);
 +      list_del(&req->rl_free);
 +      return req;
 +}
 +
 +static struct rpcrdma_rep *
 +rpcrdma_buffer_get_rep_locked(struct rpcrdma_buffer *buf)
 +{
 +      struct rpcrdma_rep *rep;
 +
 +      rep = list_first_entry(&buf->rb_recv_bufs,
 +                             struct rpcrdma_rep, rr_list);
 +      list_del(&rep->rr_list);
 +      return rep;
 +}
 +
  static void
  rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
  {
 -      if (!rep)
 -              return;
 -
        rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
        kfree(rep);
  }
  
 -static void
 +void
  rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
  {
 -      if (!req)
 -              return;
 -
        rpcrdma_free_regbuf(ia, req->rl_sendbuf);
        rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
        kfree(req);
  rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
  {
        struct rpcrdma_ia *ia = rdmab_to_ia(buf);
 -      int i;
  
 -      /* clean up in reverse order from create
 -       *   1.  recv mr memory (mr free, then kfree)
 -       *   2.  send mr memory (mr free, then kfree)
 -       *   3.  MWs
 -       */
 -      dprintk("RPC:       %s: entering\n", __func__);
 +      while (!list_empty(&buf->rb_recv_bufs)) {
 +              struct rpcrdma_rep *rep;
  
 -      for (i = 0; i < buf->rb_max_requests; i++) {
 -              if (buf->rb_recv_bufs)
 -                      rpcrdma_destroy_rep(ia, buf->rb_recv_bufs[i]);
 -              if (buf->rb_send_bufs)
 -                      rpcrdma_destroy_req(ia, buf->rb_send_bufs[i]);
 +              rep = rpcrdma_buffer_get_rep_locked(buf);
 +              rpcrdma_destroy_rep(ia, rep);
        }
  
 -      ia->ri_ops->ro_destroy(buf);
 +      spin_lock(&buf->rb_reqslock);
 +      while (!list_empty(&buf->rb_allreqs)) {
 +              struct rpcrdma_req *req;
  
 -      kfree(buf->rb_pool);
 +              req = list_first_entry(&buf->rb_allreqs,
 +                                     struct rpcrdma_req, rl_all);
 +              list_del(&req->rl_all);
 +
 +              spin_unlock(&buf->rb_reqslock);
 +              rpcrdma_destroy_req(ia, req);
 +              spin_lock(&buf->rb_reqslock);
 +      }
 +      spin_unlock(&buf->rb_reqslock);
 +
 +      ia->ri_ops->ro_destroy(buf);
  }
  
  struct rpcrdma_mw *
@@@ -1088,34 -1107,53 +1089,34 @@@ rpcrdma_put_mw(struct rpcrdma_xprt *r_x
        spin_unlock(&buf->rb_mwlock);
  }
  
 -static void
 -rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
 -{
 -      buf->rb_send_bufs[--buf->rb_send_index] = req;
 -      req->rl_niovs = 0;
 -      if (req->rl_reply) {
 -              buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply;
 -              req->rl_reply = NULL;
 -      }
 -}
 -
  /*
   * Get a set of request/reply buffers.
   *
 - * Reply buffer (if needed) is attached to send buffer upon return.
 - * Rule:
 - *    rb_send_index and rb_recv_index MUST always be pointing to the
 - *    *next* available buffer (non-NULL). They are incremented after
 - *    removing buffers, and decremented *before* returning them.
 + * Reply buffer (if available) is attached to send buffer upon return.
   */
  struct rpcrdma_req *
  rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
  {
        struct rpcrdma_req *req;
 -      unsigned long flags;
 -
 -      spin_lock_irqsave(&buffers->rb_lock, flags);
 -
 -      if (buffers->rb_send_index == buffers->rb_max_requests) {
 -              spin_unlock_irqrestore(&buffers->rb_lock, flags);
 -              dprintk("RPC:       %s: out of request buffers\n", __func__);
 -              return ((struct rpcrdma_req *)NULL);
 -      }
  
 -      req = buffers->rb_send_bufs[buffers->rb_send_index];
 -      if (buffers->rb_send_index < buffers->rb_recv_index) {
 -              dprintk("RPC:       %s: %d extra receives outstanding (ok)\n",
 -                      __func__,
 -                      buffers->rb_recv_index - buffers->rb_send_index);
 -              req->rl_reply = NULL;
 -      } else {
 -              req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
 -              buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
 -      }
 -      buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
 +      spin_lock(&buffers->rb_lock);
 +      if (list_empty(&buffers->rb_send_bufs))
 +              goto out_reqbuf;
 +      req = rpcrdma_buffer_get_req_locked(buffers);
 +      if (list_empty(&buffers->rb_recv_bufs))
 +              goto out_repbuf;
 +      req->rl_reply = rpcrdma_buffer_get_rep_locked(buffers);
 +      spin_unlock(&buffers->rb_lock);
 +      return req;
  
 -      spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +out_reqbuf:
 +      spin_unlock(&buffers->rb_lock);
 +      pr_warn("RPC:       %s: out of request buffers\n", __func__);
 +      return NULL;
 +out_repbuf:
 +      spin_unlock(&buffers->rb_lock);
 +      pr_warn("RPC:       %s: out of reply buffers\n", __func__);
 +      req->rl_reply = NULL;
        return req;
  }
  
  rpcrdma_buffer_put(struct rpcrdma_req *req)
  {
        struct rpcrdma_buffer *buffers = req->rl_buffer;
 -      unsigned long flags;
 +      struct rpcrdma_rep *rep = req->rl_reply;
  
 -      spin_lock_irqsave(&buffers->rb_lock, flags);
 -      rpcrdma_buffer_put_sendbuf(req, buffers);
 -      spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +      req->rl_niovs = 0;
 +      req->rl_reply = NULL;
 +
 +      spin_lock(&buffers->rb_lock);
 +      list_add_tail(&req->rl_free, &buffers->rb_send_bufs);
 +      if (rep)
 +              list_add_tail(&rep->rr_list, &buffers->rb_recv_bufs);
 +      spin_unlock(&buffers->rb_lock);
  }
  
  /*
   * Recover reply buffers from pool.
 - * This happens when recovering from error conditions.
 - * Post-increment counter/array index.
 + * This happens when recovering from disconnect.
   */
  void
  rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
  {
        struct rpcrdma_buffer *buffers = req->rl_buffer;
 -      unsigned long flags;
  
 -      spin_lock_irqsave(&buffers->rb_lock, flags);
 -      if (buffers->rb_recv_index < buffers->rb_max_requests) {
 -              req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
 -              buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
 -      }
 -      spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +      spin_lock(&buffers->rb_lock);
 +      if (!list_empty(&buffers->rb_recv_bufs))
 +              req->rl_reply = rpcrdma_buffer_get_rep_locked(buffers);
 +      spin_unlock(&buffers->rb_lock);
  }
  
  /*
  rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
  {
        struct rpcrdma_buffer *buffers = &rep->rr_rxprt->rx_buf;
 -      unsigned long flags;
  
 -      spin_lock_irqsave(&buffers->rb_lock, flags);
 -      buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
 -      spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +      spin_lock(&buffers->rb_lock);
 +      list_add_tail(&rep->rr_list, &buffers->rb_recv_bufs);
 +      spin_unlock(&buffers->rb_lock);
  }
  
  /*
@@@ -1322,47 -1360,6 +1323,47 @@@ rpcrdma_ep_post_recv(struct rpcrdma_ia 
        return rc;
  }
  
 +/**
 + * rpcrdma_ep_post_extra_recv - Post buffers for incoming backchannel requests
 + * @r_xprt: transport associated with these backchannel resources
 + * @min_reqs: minimum number of incoming requests expected
 + *
 + * Returns zero if all requested buffers were posted, or a negative errno.
 + */
 +int
 +rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *r_xprt, unsigned int count)
 +{
 +      struct rpcrdma_buffer *buffers = &r_xprt->rx_buf;
 +      struct rpcrdma_ia *ia = &r_xprt->rx_ia;
 +      struct rpcrdma_ep *ep = &r_xprt->rx_ep;
 +      struct rpcrdma_rep *rep;
 +      unsigned long flags;
 +      int rc;
 +
 +      while (count--) {
 +              spin_lock_irqsave(&buffers->rb_lock, flags);
 +              if (list_empty(&buffers->rb_recv_bufs))
 +                      goto out_reqbuf;
 +              rep = rpcrdma_buffer_get_rep_locked(buffers);
 +              spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +
 +              rc = rpcrdma_ep_post_recv(ia, ep, rep);
 +              if (rc)
 +                      goto out_rc;
 +      }
 +
 +      return 0;
 +
 +out_reqbuf:
 +      spin_unlock_irqrestore(&buffers->rb_lock, flags);
 +      pr_warn("%s: no extra receive buffers\n", __func__);
 +      return -ENOMEM;
 +
 +out_rc:
 +      rpcrdma_recv_buffer_put(rep);
 +      return rc;
 +}
 +
  /* How many chunk list items fit within our inline buffers?
   */
  unsigned int
index f8dd17be9f43cefe89470cd2c9c9954f76a93ca0,c82abf44e39db9954cd7e27fab2595b9552c9668..ac7f8d4f632a9e923fdcf3fdbd8f628ad044d34b
@@@ -77,6 -77,9 +77,6 @@@ struct rpcrdma_ia 
   * RDMA Endpoint -- one per transport instance
   */
  
 -#define RPCRDMA_WC_BUDGET     (128)
 -#define RPCRDMA_POLLSIZE      (16)
 -
  struct rpcrdma_ep {
        atomic_t                rep_cqcount;
        int                     rep_cqinit;
@@@ -86,6 -89,8 +86,6 @@@
        struct rdma_conn_param  rep_remote_cma;
        struct sockaddr_storage rep_remote_addr;
        struct delayed_work     rep_connect_worker;
 -      struct ib_wc            rep_send_wcs[RPCRDMA_POLLSIZE];
 -      struct ib_wc            rep_recv_wcs[RPCRDMA_POLLSIZE];
  };
  
  /*
   */
  #define RPCRDMA_IGNORE_COMPLETION     (0ULL)
  
 +/* Pre-allocate extra Work Requests for handling backward receives
 + * and sends. This is a fixed value because the Work Queues are
 + * allocated when the forward channel is set up.
 + */
 +#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 +#define RPCRDMA_BACKWARD_WRS          (8)
 +#else
 +#define RPCRDMA_BACKWARD_WRS          (0)
 +#endif
 +
  /* Registered buffer -- registered kmalloc'd memory for RDMA SEND/RECV
   *
   * The below structure appears at the front of a large region of kmalloc'd
@@@ -174,13 -169,10 +174,13 @@@ struct rpcrdma_rep 
        unsigned int            rr_len;
        struct ib_device        *rr_device;
        struct rpcrdma_xprt     *rr_rxprt;
 +      struct work_struct      rr_work;
        struct list_head        rr_list;
        struct rpcrdma_regbuf   *rr_rdmabuf;
  };
  
 +#define RPCRDMA_BAD_LEN               (~0U)
 +
  /*
   * struct rpcrdma_mw - external memory region metadata
   *
@@@ -201,7 -193,8 +201,8 @@@ enum rpcrdma_frmr_state 
  };
  
  struct rpcrdma_frmr {
-       struct ib_fast_reg_page_list    *fr_pgl;
+       struct scatterlist              *sg;
+       int                             sg_nents;
        struct ib_mr                    *fr_mr;
        enum rpcrdma_frmr_state         fr_state;
        struct work_struct              fr_work;
@@@ -263,7 -256,6 +264,7 @@@ struct rpcrdma_mr_seg {            /* chunk descr
  #define RPCRDMA_MAX_IOVS      (2)
  
  struct rpcrdma_req {
 +      struct list_head        rl_free;
        unsigned int            rl_niovs;
        unsigned int            rl_nchunks;
        unsigned int            rl_connect_cookie;
        struct rpcrdma_regbuf   *rl_rdmabuf;
        struct rpcrdma_regbuf   *rl_sendbuf;
        struct rpcrdma_mr_seg   rl_segments[RPCRDMA_MAX_SEGS];
 +
 +      struct list_head        rl_all;
 +      bool                    rl_backchannel;
  };
  
  static inline struct rpcrdma_req *
@@@ -300,14 -289,12 +301,14 @@@ struct rpcrdma_buffer 
        struct list_head        rb_all;
        char                    *rb_pool;
  
 -      spinlock_t              rb_lock;        /* protect buf arrays */
 +      spinlock_t              rb_lock;        /* protect buf lists */
 +      struct list_head        rb_send_bufs;
 +      struct list_head        rb_recv_bufs;
        u32                     rb_max_requests;
 -      int                     rb_send_index;
 -      int                     rb_recv_index;
 -      struct rpcrdma_req      **rb_send_bufs;
 -      struct rpcrdma_rep      **rb_recv_bufs;
 +
 +      u32                     rb_bc_srv_max_requests;
 +      spinlock_t              rb_reqslock;    /* protect rb_allreqs */
 +      struct list_head        rb_allreqs;
  };
  #define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia)
  
@@@ -353,7 -340,6 +354,7 @@@ struct rpcrdma_stats 
        unsigned long           failed_marshal_count;
        unsigned long           bad_reply_count;
        unsigned long           nomsg_call_count;
 +      unsigned long           bcall_count;
  };
  
  /*
@@@ -429,9 -415,6 +430,9 @@@ int rpcrdma_ep_post_recv(struct rpcrdma
  /*
   * Buffer calls - xprtrdma/verbs.c
   */
 +struct rpcrdma_req *rpcrdma_create_req(struct rpcrdma_xprt *);
 +struct rpcrdma_rep *rpcrdma_create_rep(struct rpcrdma_xprt *);
 +void rpcrdma_destroy_req(struct rpcrdma_ia *, struct rpcrdma_req *);
  int rpcrdma_buffer_create(struct rpcrdma_xprt *);
  void rpcrdma_buffer_destroy(struct rpcrdma_buffer *);
  
@@@ -448,14 -431,10 +449,14 @@@ void rpcrdma_free_regbuf(struct rpcrdma
                         struct rpcrdma_regbuf *);
  
  unsigned int rpcrdma_max_segments(struct rpcrdma_xprt *);
 +int rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *, unsigned int);
  
  int frwr_alloc_recovery_wq(void);
  void frwr_destroy_recovery_wq(void);
  
 +int rpcrdma_alloc_wq(void);
 +void rpcrdma_destroy_wq(void);
 +
  /*
   * Wrappers for chunk registration, shared by read/write chunk code.
   */
@@@ -516,18 -495,6 +517,18 @@@ int rpcrdma_marshal_req(struct rpc_rqs
  int xprt_rdma_init(void);
  void xprt_rdma_cleanup(void);
  
 +/* Backchannel calls - xprtrdma/backchannel.c
 + */
 +#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 +int xprt_rdma_bc_setup(struct rpc_xprt *, unsigned int);
 +int xprt_rdma_bc_up(struct svc_serv *, struct net *);
 +int rpcrdma_bc_post_recv(struct rpcrdma_xprt *, unsigned int);
 +void rpcrdma_bc_receive_call(struct rpcrdma_xprt *, struct rpcrdma_rep *);
 +int rpcrdma_bc_marshal_reply(struct rpc_rqst *);
 +void xprt_rdma_bc_free_rqst(struct rpc_rqst *);
 +void xprt_rdma_bc_destroy(struct rpc_xprt *, unsigned int);
 +#endif        /* CONFIG_SUNRPC_BACKCHANNEL */
 +
  /* Temporary NFS request map cache. Created in svc_rdma.c  */
  extern struct kmem_cache *svc_rdma_map_cachep;
  /* WR context cache. Created in svc_rdma.c  */