Documentation
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dax
dca
devfreq
dio
dma
dma-buf
edac
eisa
extcon
firewire
firmware
fmc
fpga
gpio
gpu
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
ide
idle
iio
infiniband
core
hw
sw
rdmavt
rxe
Kconfig
Makefile
rxe.c
rxe.h
rxe_av.c
rxe_comp.c
rxe_cq.c
rxe_dma.c
rxe_hdr.h
rxe_icrc.c
rxe_loc.h
rxe_mcast.c
rxe_mmap.c
rxe_mr.c
rxe_net.c
rxe_net.h
rxe_opcode.c
rxe_opcode.h
rxe_param.h
rxe_pool.c
rxe_pool.h
rxe_qp.c
rxe_queue.c
rxe_queue.h
rxe_recv.c
rxe_req.c
rxe_resp.c
rxe_srq.c
rxe_sysfs.c
rxe_task.c
rxe_task.h
rxe_verbs.c
rxe_verbs.h
Makefile
ulp
Kconfig
Makefile
input
iommu
ipack
irqchip
isdn
leds
lguest
lightnvm
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
mtd
net
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
oprofile
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
sn
soc
spi
spmi
ssb
staging
target
tc
tee
thermal
thunderbolt
tty
uio
usb
uwb
vfio
vhost
video
virt
virtio
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
ndm
net
samples
scripts
security
sound
tools
usr
virt
.cocciconfig
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
build.config.aarch64
build.config.common
build.config.cuttlefish.aarch64
build.config.cuttlefish.x86_64
build.config.goldfish.arm
build.config.goldfish.arm64
build.config.goldfish.mips
build.config.goldfish.mips64
build.config.goldfish.x86
build.config.goldfish.x86_64
build.config.x86_64
localversion-ndm
verity_dev_keys.x509
Changes in 4.9.203 ax88172a: fix information leak on short answers slip: Fix memory leak in slip_open error path ALSA: usb-audio: Fix missing error check at mixer resolution test ALSA: usb-audio: not submit urb for stopped endpoint Input: ff-memless - kill timer in destroy() Input: synaptics-rmi4 - fix video buffer size Input: synaptics-rmi4 - clear IRQ enables for F54 Input: synaptics-rmi4 - destroy F54 poller workqueue when removing IB/hfi1: Ensure full Gen3 speed in a Gen4 system ecryptfs_lookup_interpose(): lower_dentry->d_inode is not stable ecryptfs_lookup_interpose(): lower_dentry->d_parent is not stable either iommu/vt-d: Fix QI_DEV_IOTLB_PFSID and QI_DEV_EIOTLB_PFSID macros mm: memcg: switch to css_tryget() in get_mem_cgroup_from_mm() mm: hugetlb: switch to css_tryget() in hugetlb_cgroup_charge_cgroup() mmc: sdhci-of-at91: fix quirk2 overwrite ath10k: fix kernel panic by moving pci flush after napi_disable iio: dac: mcp4922: fix error handling in mcp4922_write_raw ALSA: pcm: signedness bug in snd_pcm_plug_alloc() arm64: dts: tegra210-p2180: Correct sdmmc4 vqmmc-supply ARM: dts: at91/trivial: Fix USART1 definition for at91sam9g45 cfg80211: Avoid regulatory restore when COUNTRY_IE_IGNORE is set ALSA: seq: Do error checks at creating system ports ath9k: fix tx99 with monitor mode interface gfs2: Don't set GFS2_RDF_UPTODATE when the lvb is updated ASoC: dpcm: Properly initialise hw->rate_max MIPS: BCM47XX: Enable USB power on Netgear WNDR3400v3 ARM: dts: exynos: Fix sound in Snow-rev5 Chromebook ARM: dts: exynos: Fix regulators configuration on Peach Pi/Pit Chromebooks i40e: use correct length for strncpy i40e: hold the rtnl lock on clearing interrupt scheme i40e: Prevent deleting MAC address from VF when set by PF IB/rxe: fixes for rdma read retry iwlwifi: mvm: avoid sending too many BARs ARM: dts: pxa: fix power i2c base address rtl8187: Fix warning generated when strncpy() destination length matches the sixe argument net: lan78xx: Bail out if lan78xx_get_endpoints fails ASoC: sgtl5000: avoid division by zero if lo_vag is zero ARM: dts: exynos: Disable pull control for S5M8767 PMIC ath10k: wmi: disable softirq's while calling ieee80211_rx mips: txx9: fix iounmap related issue ASoC: Intel: hdac_hdmi: Limit sampling rates at dai creation of: make PowerMac cache node search conditional on CONFIG_PPC_PMAC ARM: dts: omap3-gta04: give spi_lcd node a label so that we can overwrite in other DTS files ARM: dts: omap3-gta04: fixes for tvout / venc ARM: dts: omap3-gta04: tvout: enable as display1 alias ARM: dts: omap3-gta04: fix touchscreen tsc2007 ARM: dts: omap3-gta04: make NAND partitions compatible with recent U-Boot ARM: dts: omap3-gta04: keep vpll2 always on dmaengine: dma-jz4780: Don't depend on MACH_JZ4780 dmaengine: dma-jz4780: Further residue status fix ath9k: add back support for using active monitor interfaces for tx99 signal: Always ignore SIGKILL and SIGSTOP sent to the global init signal: Properly deliver SIGILL from uprobes signal: Properly deliver SIGSEGV from x86 uprobes f2fs: fix memory leak of percpu counter in fill_super() scsi: sym53c8xx: fix NULL pointer dereference panic in sym_int_sir() ARM: imx6: register pm_power_off handler if "fsl,pmic-stby-poweroff" is set scsi: pm80xx: Corrected dma_unmap_sg() parameter scsi: pm80xx: Fixed system hang issue during kexec boot kprobes: Don't call BUG_ON() if there is a kprobe in use on free list nvmem: core: return error code instead of NULL from nvmem_device_get media: fix: media: pci: meye: validate offset to avoid arbitrary access media: dvb: fix compat ioctl translation ALSA: intel8x0m: Register irq handler after register initializations pinctrl: at91-pio4: fix has_config check in atmel_pctl_dt_subnode_to_map() llc: avoid blocking in llc_sap_close() ARM: dts: qcom: ipq4019: fix cpu0's qcom,saw2 reg value powerpc/vdso: Correct call frame information ARM: dts: socfpga: Fix I2C bus unit-address error pinctrl: at91: don't use the same irqchip with multiple gpiochips cxgb4: Fix endianness issue in t4_fwcache() power: supply: ab8500_fg: silence uninitialized variable warnings power: reset: at91-poweroff: do not procede if at91_shdwc is allocated power: supply: max8998-charger: Fix platform data retrieval component: fix loop condition to call unbind() if bind() fails kernfs: Fix range checks in kernfs_get_target_path ip_gre: fix parsing gre header in ipgre_err ARM: dts: rockchip: Fix erroneous SPI bus dtc warnings on rk3036 ath9k: Fix a locking bug in ath9k_add_interface() s390/qeth: invoke softirqs after napi_schedule() PCI/ACPI: Correct error message for ASPM disabling serial: mxs-auart: Fix potential infinite loop powerpc/iommu: Avoid derefence before pointer check powerpc/64s/hash: Fix stab_rr off by one initialization powerpc/pseries: Disable CPU hotplug across migrations RDMA/i40iw: Fix incorrect iterator type libfdt: Ensure INT_MAX is defined in libfdt_env.h power: supply: twl4030_charger: fix charging current out-of-bounds power: supply: twl4030_charger: disable eoc interrupt on linear charge net: toshiba: fix return type of ndo_start_xmit function net: xilinx: fix return type of ndo_start_xmit function net: broadcom: fix return type of ndo_start_xmit function net: amd: fix return type of ndo_start_xmit function usb: chipidea: imx: enable OTG overcurrent in case USB subsystem is already started usb: chipidea: Fix otg event handler mlxsw: spectrum: Init shaper for TCs 8..15 ARM: dts: am335x-evm: fix number of cpsw f2fs: fix to recover inode's uid/gid during POR ARM: dts: ux500: Correct SCU unit address ARM: dts: ux500: Fix LCDA clock line muxing ARM: dts: ste: Fix SPI controller node names spi: pic32: Use proper enum in dmaengine_prep_slave_rg cpufeature: avoid warning when compiling with clang ARM: dts: marvell: Fix SPI and I2C bus warnings bnx2x: Ignore bandwidth attention in single function mode net: micrel: fix return type of ndo_start_xmit function x86/CPU: Use correct macros for Cyrix calls MIPS: kexec: Relax memory restriction media: pci: ivtv: Fix a sleep-in-atomic-context bug in ivtv_yuv_init() media: au0828: Fix incorrect error messages media: davinci: Fix implicit enum conversion warning usb: gadget: uvc: configfs: Drop leaked references to config items usb: gadget: uvc: configfs: Prevent format changes after linking header phy: phy-twl4030-usb: fix denied runtime access usb: gadget: uvc: Factor out video USB request queueing usb: gadget: uvc: Only halt video streaming endpoint in bulk mode coresight: Fix handling of sinks coresight: etm4x: Configure EL2 exception level when kernel is running in HYP coresight: tmc: Fix byte-address alignment for RRP misc: kgdbts: Fix restrict error misc: genwqe: should return proper error value. vfio/pci: Fix potential memory leak in vfio_msi_cap_len vfio/pci: Mask buggy SR-IOV VF INTx support scsi: libsas: always unregister the old device if going to discover new ARM: dts: tegra30: fix xcvr-setup-use-fuses ARM: tegra: apalis_t30: fix mmc1 cmd pull-up ARM: dts: paz00: fix wakeup gpio keycode net: smsc: fix return type of ndo_start_xmit function EDAC: Raise the maximum number of memory controllers ARM: dts: realview: Fix SPI controller node names Bluetooth: L2CAP: Detect if remote is not able to use the whole MPS crypto: s5p-sss: Fix Fix argument list alignment crypto: fix a memory leak in rsa-kcs1pad's encryption mode scsi: NCR5380: Clear all unissued commands on host reset scsi: NCR5380: Use DRIVER_SENSE to indicate valid sense data scsi: NCR5380: Check for invalid reselection target scsi: NCR5380: Don't clear busy flag when abort fails scsi: NCR5380: Don't call dsprintk() following reselection interrupt scsi: NCR5380: Handle BUS FREE during reselection arm64: dts: amd: Fix SPI bus warnings arm64: dts: lg: Fix SPI controller node names ARM: dts: lpc32xx: Fix SPI controller node names usb: xhci-mtk: fix ISOC error when interval is zero fuse: use READ_ONCE on congestion_threshold and max_background IB/iser: Fix possible NULL deref at iser_inv_desc() memfd: Use radix_tree_deref_slot_protected to avoid the warning. slcan: Fix memory leak in error path net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size() x86/atomic: Fix smp_mb__{before,after}_atomic() kprobes/x86: Prohibit probing on exception masking instructions uprobes/x86: Prohibit probing on MOV SS instruction fbdev: Ditch fb_edid_add_monspecs block: introduce blk_rq_is_passthrough libata: have ata_scsi_rw_xlat() fail invalid passthrough requests net: ovs: fix return type of ndo_start_xmit function net: xen-netback: fix return type of ndo_start_xmit function ARM: dts: omap5: enable OTG role for DWC3 controller f2fs: return correct errno in f2fs_gc SUNRPC: Fix priority queue fairness kvm: arm/arm64: Fix stage2_flush_memslot for 4 level page table arm64/numa: Report correct memblock range for the dummy node ath10k: fix vdev-start timeout on error ata: ahci_brcm: Allow using driver or DSL SoCs ath9k: fix reporting calculated new FFT upper max usb: gadget: udc: fotg210-udc: Fix a sleep-in-atomic-context bug in fotg210_get_status() nl80211: Fix a GET_KEY reply attribute dmaengine: ep93xx: Return proper enum in ep93xx_dma_chan_direction dmaengine: timb_dma: Use proper enum in td_prep_slave_sg mei: samples: fix a signedness bug in amt_host_if_call() cxgb4: Use proper enum in cxgb4_dcb_handle_fw_update cxgb4: Use proper enum in IEEE_FAUX_SYNC powerpc/pseries: Fix DTL buffer registration powerpc/pseries: Fix how we iterate over the DTL entries mtd: rawnand: sh_flctl: Use proper enum for flctl_dma_fifo0_transfer ixgbe: Fix crash with VFs and flow director on interface flap IB/mthca: Fix error return code in __mthca_init_one() IB/mlx4: Avoid implicit enumerated type conversion ACPICA: Never run _REG on system_memory and system_IO ata: ep93xx: Use proper enums for directions media: pxa_camera: Fix check for pdev->dev.of_node ALSA: hda/sigmatel - Disable automute for Elo VuPoint KVM: PPC: Book3S PR: Exiting split hack mode needs to fixup both PC and LR USB: serial: cypress_m8: fix interrupt-out transfer length mtd: physmap_of: Release resources on error cpu/SMT: State SMT is disabled even with nosmt and without "=force" brcmfmac: reduce timeout for action frame scan brcmfmac: fix full timeout waiting for action frame on-channel tx clk: samsung: Use clk_hw API for calling clk framework from clk notifiers i2c: brcmstb: Allow enabling the driver on DSL SoCs NFSv4.x: fix lock recovery during delegation recall dmaengine: ioat: fix prototype of ioat_enumerate_channels Input: st1232 - set INPUT_PROP_DIRECT property Input: silead - try firmware reload after unsuccessful resume x86/olpc: Fix build error with CONFIG_MFD_CS5535=m crypto: mxs-dcp - Fix SHA null hashes and output length crypto: mxs-dcp - Fix AES issues ACPI / SBS: Fix rare oops when removing modules iwlwifi: mvm: don't send keys when entering D3 fbdev: sbuslib: use checked version of put_user() fbdev: sbuslib: integer overflow in sbusfb_ioctl_helper() reset: Fix potential use-after-free in __of_reset_control_get() bcache: recal cached_dev_sectors on detach s390/kasan: avoid vdso instrumentation proc/vmcore: Fix i386 build error of missing copy_oldmem_page_encrypted() backlight: lm3639: Unconditionally call led_classdev_unregister mfd: ti_am335x_tscadc: Keep ADC interface on if child is wakeup capable printk: Give error on attempt to set log buffer length to over 2G media: isif: fix a NULL pointer dereference bug GFS2: Flush the GFS2 delete workqueue before stopping the kernel threads media: cx231xx: fix potential sign-extension overflow on large shift x86/kexec: Correct KEXEC_BACKUP_SRC_END off-by-one error gpio: syscon: Fix possible NULL ptr usage spi: spidev: Fix OF tree warning logic ARM: 8802/1: Call syscall_trace_exit even when system call skipped orangefs: rate limit the client not running info message hwmon: (pwm-fan) Silence error on probe deferral hwmon: (ina3221) Fix INA3221_CONFIG_MODE macros misc: cxl: Fix possible null pointer dereference mac80211: minstrel: fix CCK rate group streams value spi: rockchip: initialize dma_slave_config properly ARM: dts: omap5: Fix dual-role mode on Super-Speed port arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault Linux 4.9.203 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
762 lines
18 KiB
C
762 lines
18 KiB
C
/*
|
|
* Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
|
|
* Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
|
|
*
|
|
* This software is available to you under a choice of one of two
|
|
* licenses. You may choose to be licensed under the terms of the GNU
|
|
* General Public License (GPL) Version 2, available from the file
|
|
* COPYING in the main directory of this source tree, or the
|
|
* OpenIB.org BSD license below:
|
|
*
|
|
* Redistribution and use in source and binary forms, with or
|
|
* without modification, are permitted provided that the following
|
|
* conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include "rxe.h"
|
|
#include "rxe_loc.h"
|
|
#include "rxe_queue.h"
|
|
#include "rxe_task.h"
|
|
|
|
enum comp_state {
|
|
COMPST_GET_ACK,
|
|
COMPST_GET_WQE,
|
|
COMPST_COMP_WQE,
|
|
COMPST_COMP_ACK,
|
|
COMPST_CHECK_PSN,
|
|
COMPST_CHECK_ACK,
|
|
COMPST_READ,
|
|
COMPST_ATOMIC,
|
|
COMPST_WRITE_SEND,
|
|
COMPST_UPDATE_COMP,
|
|
COMPST_ERROR_RETRY,
|
|
COMPST_RNR_RETRY,
|
|
COMPST_ERROR,
|
|
COMPST_EXIT, /* We have an issue, and we want to rerun the completer */
|
|
COMPST_DONE, /* The completer finished successflly */
|
|
};
|
|
|
|
static char *comp_state_name[] = {
|
|
[COMPST_GET_ACK] = "GET ACK",
|
|
[COMPST_GET_WQE] = "GET WQE",
|
|
[COMPST_COMP_WQE] = "COMP WQE",
|
|
[COMPST_COMP_ACK] = "COMP ACK",
|
|
[COMPST_CHECK_PSN] = "CHECK PSN",
|
|
[COMPST_CHECK_ACK] = "CHECK ACK",
|
|
[COMPST_READ] = "READ",
|
|
[COMPST_ATOMIC] = "ATOMIC",
|
|
[COMPST_WRITE_SEND] = "WRITE/SEND",
|
|
[COMPST_UPDATE_COMP] = "UPDATE COMP",
|
|
[COMPST_ERROR_RETRY] = "ERROR RETRY",
|
|
[COMPST_RNR_RETRY] = "RNR RETRY",
|
|
[COMPST_ERROR] = "ERROR",
|
|
[COMPST_EXIT] = "EXIT",
|
|
[COMPST_DONE] = "DONE",
|
|
};
|
|
|
|
static unsigned long rnrnak_usec[32] = {
|
|
[IB_RNR_TIMER_655_36] = 655360,
|
|
[IB_RNR_TIMER_000_01] = 10,
|
|
[IB_RNR_TIMER_000_02] = 20,
|
|
[IB_RNR_TIMER_000_03] = 30,
|
|
[IB_RNR_TIMER_000_04] = 40,
|
|
[IB_RNR_TIMER_000_06] = 60,
|
|
[IB_RNR_TIMER_000_08] = 80,
|
|
[IB_RNR_TIMER_000_12] = 120,
|
|
[IB_RNR_TIMER_000_16] = 160,
|
|
[IB_RNR_TIMER_000_24] = 240,
|
|
[IB_RNR_TIMER_000_32] = 320,
|
|
[IB_RNR_TIMER_000_48] = 480,
|
|
[IB_RNR_TIMER_000_64] = 640,
|
|
[IB_RNR_TIMER_000_96] = 960,
|
|
[IB_RNR_TIMER_001_28] = 1280,
|
|
[IB_RNR_TIMER_001_92] = 1920,
|
|
[IB_RNR_TIMER_002_56] = 2560,
|
|
[IB_RNR_TIMER_003_84] = 3840,
|
|
[IB_RNR_TIMER_005_12] = 5120,
|
|
[IB_RNR_TIMER_007_68] = 7680,
|
|
[IB_RNR_TIMER_010_24] = 10240,
|
|
[IB_RNR_TIMER_015_36] = 15360,
|
|
[IB_RNR_TIMER_020_48] = 20480,
|
|
[IB_RNR_TIMER_030_72] = 30720,
|
|
[IB_RNR_TIMER_040_96] = 40960,
|
|
[IB_RNR_TIMER_061_44] = 61410,
|
|
[IB_RNR_TIMER_081_92] = 81920,
|
|
[IB_RNR_TIMER_122_88] = 122880,
|
|
[IB_RNR_TIMER_163_84] = 163840,
|
|
[IB_RNR_TIMER_245_76] = 245760,
|
|
[IB_RNR_TIMER_327_68] = 327680,
|
|
[IB_RNR_TIMER_491_52] = 491520,
|
|
};
|
|
|
|
static inline unsigned long rnrnak_jiffies(u8 timeout)
|
|
{
|
|
return max_t(unsigned long,
|
|
usecs_to_jiffies(rnrnak_usec[timeout]), 1);
|
|
}
|
|
|
|
static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
|
|
{
|
|
switch (opcode) {
|
|
case IB_WR_RDMA_WRITE: return IB_WC_RDMA_WRITE;
|
|
case IB_WR_RDMA_WRITE_WITH_IMM: return IB_WC_RDMA_WRITE;
|
|
case IB_WR_SEND: return IB_WC_SEND;
|
|
case IB_WR_SEND_WITH_IMM: return IB_WC_SEND;
|
|
case IB_WR_RDMA_READ: return IB_WC_RDMA_READ;
|
|
case IB_WR_ATOMIC_CMP_AND_SWP: return IB_WC_COMP_SWAP;
|
|
case IB_WR_ATOMIC_FETCH_AND_ADD: return IB_WC_FETCH_ADD;
|
|
case IB_WR_LSO: return IB_WC_LSO;
|
|
case IB_WR_SEND_WITH_INV: return IB_WC_SEND;
|
|
case IB_WR_RDMA_READ_WITH_INV: return IB_WC_RDMA_READ;
|
|
case IB_WR_LOCAL_INV: return IB_WC_LOCAL_INV;
|
|
case IB_WR_REG_MR: return IB_WC_REG_MR;
|
|
|
|
default:
|
|
return 0xff;
|
|
}
|
|
}
|
|
|
|
void retransmit_timer(unsigned long data)
|
|
{
|
|
struct rxe_qp *qp = (struct rxe_qp *)data;
|
|
|
|
if (qp->valid) {
|
|
qp->comp.timeout = 1;
|
|
rxe_run_task(&qp->comp.task, 1);
|
|
}
|
|
}
|
|
|
|
void rxe_comp_queue_pkt(struct rxe_dev *rxe, struct rxe_qp *qp,
|
|
struct sk_buff *skb)
|
|
{
|
|
int must_sched;
|
|
|
|
skb_queue_tail(&qp->resp_pkts, skb);
|
|
|
|
must_sched = skb_queue_len(&qp->resp_pkts) > 1;
|
|
rxe_run_task(&qp->comp.task, must_sched);
|
|
}
|
|
|
|
static inline enum comp_state get_wqe(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe **wqe_p)
|
|
{
|
|
struct rxe_send_wqe *wqe;
|
|
|
|
/* we come here whether or not we found a response packet to see if
|
|
* there are any posted WQEs
|
|
*/
|
|
wqe = queue_head(qp->sq.queue);
|
|
*wqe_p = wqe;
|
|
|
|
/* no WQE or requester has not started it yet */
|
|
if (!wqe || wqe->state == wqe_state_posted)
|
|
return pkt ? COMPST_DONE : COMPST_EXIT;
|
|
|
|
/* WQE does not require an ack */
|
|
if (wqe->state == wqe_state_done)
|
|
return COMPST_COMP_WQE;
|
|
|
|
/* WQE caused an error */
|
|
if (wqe->state == wqe_state_error)
|
|
return COMPST_ERROR;
|
|
|
|
/* we have a WQE, if we also have an ack check its PSN */
|
|
return pkt ? COMPST_CHECK_PSN : COMPST_EXIT;
|
|
}
|
|
|
|
static inline void reset_retry_counters(struct rxe_qp *qp)
|
|
{
|
|
qp->comp.retry_cnt = qp->attr.retry_cnt;
|
|
qp->comp.rnr_retry = qp->attr.rnr_retry;
|
|
}
|
|
|
|
static inline enum comp_state check_psn(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
s32 diff;
|
|
|
|
/* check to see if response is past the oldest WQE. if it is, complete
|
|
* send/write or error read/atomic
|
|
*/
|
|
diff = psn_compare(pkt->psn, wqe->last_psn);
|
|
if (diff > 0) {
|
|
if (wqe->state == wqe_state_pending) {
|
|
if (wqe->mask & WR_ATOMIC_OR_READ_MASK)
|
|
return COMPST_ERROR_RETRY;
|
|
|
|
reset_retry_counters(qp);
|
|
return COMPST_COMP_WQE;
|
|
} else {
|
|
return COMPST_DONE;
|
|
}
|
|
}
|
|
|
|
/* compare response packet to expected response */
|
|
diff = psn_compare(pkt->psn, qp->comp.psn);
|
|
if (diff < 0) {
|
|
/* response is most likely a retried packet if it matches an
|
|
* uncompleted WQE go complete it else ignore it
|
|
*/
|
|
if (pkt->psn == wqe->last_psn)
|
|
return COMPST_COMP_ACK;
|
|
else
|
|
return COMPST_DONE;
|
|
} else if ((diff > 0) && (wqe->mask & WR_ATOMIC_OR_READ_MASK)) {
|
|
return COMPST_ERROR_RETRY;
|
|
} else {
|
|
return COMPST_CHECK_ACK;
|
|
}
|
|
}
|
|
|
|
static inline enum comp_state check_ack(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
unsigned int mask = pkt->mask;
|
|
u8 syn;
|
|
|
|
/* Check the sequence only */
|
|
switch (qp->comp.opcode) {
|
|
case -1:
|
|
/* Will catch all *_ONLY cases. */
|
|
if (!(mask & RXE_START_MASK))
|
|
return COMPST_ERROR;
|
|
|
|
break;
|
|
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
|
|
if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE &&
|
|
pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) {
|
|
/* read retries of partial data may restart from
|
|
* read response first or response only.
|
|
*/
|
|
if ((pkt->psn == wqe->first_psn &&
|
|
pkt->opcode ==
|
|
IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) ||
|
|
(wqe->first_psn == wqe->last_psn &&
|
|
pkt->opcode ==
|
|
IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY))
|
|
break;
|
|
|
|
return COMPST_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
WARN_ON(1);
|
|
}
|
|
|
|
/* Check operation validity. */
|
|
switch (pkt->opcode) {
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST:
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY:
|
|
syn = aeth_syn(pkt);
|
|
|
|
if ((syn & AETH_TYPE_MASK) != AETH_ACK)
|
|
return COMPST_ERROR;
|
|
|
|
/* Fall through (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE
|
|
* doesn't have an AETH)
|
|
*/
|
|
case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
|
|
if (wqe->wr.opcode != IB_WR_RDMA_READ &&
|
|
wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV) {
|
|
wqe->status = IB_WC_FATAL_ERR;
|
|
return COMPST_ERROR;
|
|
}
|
|
reset_retry_counters(qp);
|
|
return COMPST_READ;
|
|
|
|
case IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE:
|
|
syn = aeth_syn(pkt);
|
|
|
|
if ((syn & AETH_TYPE_MASK) != AETH_ACK)
|
|
return COMPST_ERROR;
|
|
|
|
if (wqe->wr.opcode != IB_WR_ATOMIC_CMP_AND_SWP &&
|
|
wqe->wr.opcode != IB_WR_ATOMIC_FETCH_AND_ADD)
|
|
return COMPST_ERROR;
|
|
reset_retry_counters(qp);
|
|
return COMPST_ATOMIC;
|
|
|
|
case IB_OPCODE_RC_ACKNOWLEDGE:
|
|
syn = aeth_syn(pkt);
|
|
switch (syn & AETH_TYPE_MASK) {
|
|
case AETH_ACK:
|
|
reset_retry_counters(qp);
|
|
return COMPST_WRITE_SEND;
|
|
|
|
case AETH_RNR_NAK:
|
|
return COMPST_RNR_RETRY;
|
|
|
|
case AETH_NAK:
|
|
switch (syn) {
|
|
case AETH_NAK_PSN_SEQ_ERROR:
|
|
/* a nak implicitly acks all packets with psns
|
|
* before
|
|
*/
|
|
if (psn_compare(pkt->psn, qp->comp.psn) > 0) {
|
|
qp->comp.psn = pkt->psn;
|
|
if (qp->req.wait_psn) {
|
|
qp->req.wait_psn = 0;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
}
|
|
return COMPST_ERROR_RETRY;
|
|
|
|
case AETH_NAK_INVALID_REQ:
|
|
wqe->status = IB_WC_REM_INV_REQ_ERR;
|
|
return COMPST_ERROR;
|
|
|
|
case AETH_NAK_REM_ACC_ERR:
|
|
wqe->status = IB_WC_REM_ACCESS_ERR;
|
|
return COMPST_ERROR;
|
|
|
|
case AETH_NAK_REM_OP_ERR:
|
|
wqe->status = IB_WC_REM_OP_ERR;
|
|
return COMPST_ERROR;
|
|
|
|
default:
|
|
pr_warn("unexpected nak %x\n", syn);
|
|
wqe->status = IB_WC_REM_OP_ERR;
|
|
return COMPST_ERROR;
|
|
}
|
|
|
|
default:
|
|
return COMPST_ERROR;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pr_warn("unexpected opcode\n");
|
|
}
|
|
|
|
return COMPST_ERROR;
|
|
}
|
|
|
|
static inline enum comp_state do_read(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
|
|
int ret;
|
|
|
|
ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
|
|
&wqe->dma, payload_addr(pkt),
|
|
payload_size(pkt), to_mem_obj, NULL);
|
|
if (ret)
|
|
return COMPST_ERROR;
|
|
|
|
if (wqe->dma.resid == 0 && (pkt->mask & RXE_END_MASK))
|
|
return COMPST_COMP_ACK;
|
|
else
|
|
return COMPST_UPDATE_COMP;
|
|
}
|
|
|
|
static inline enum comp_state do_atomic(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
|
|
int ret;
|
|
|
|
u64 atomic_orig = atmack_orig(pkt);
|
|
|
|
ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
|
|
&wqe->dma, &atomic_orig,
|
|
sizeof(u64), to_mem_obj, NULL);
|
|
if (ret)
|
|
return COMPST_ERROR;
|
|
else
|
|
return COMPST_COMP_ACK;
|
|
}
|
|
|
|
static void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
|
|
struct rxe_cqe *cqe)
|
|
{
|
|
memset(cqe, 0, sizeof(*cqe));
|
|
|
|
if (!qp->is_user) {
|
|
struct ib_wc *wc = &cqe->ibwc;
|
|
|
|
wc->wr_id = wqe->wr.wr_id;
|
|
wc->status = wqe->status;
|
|
wc->opcode = wr_to_wc_opcode(wqe->wr.opcode);
|
|
if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
|
|
wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
|
|
wc->wc_flags = IB_WC_WITH_IMM;
|
|
wc->byte_len = wqe->dma.length;
|
|
wc->qp = &qp->ibqp;
|
|
} else {
|
|
struct ib_uverbs_wc *uwc = &cqe->uibwc;
|
|
|
|
uwc->wr_id = wqe->wr.wr_id;
|
|
uwc->status = wqe->status;
|
|
uwc->opcode = wr_to_wc_opcode(wqe->wr.opcode);
|
|
if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
|
|
wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
|
|
uwc->wc_flags = IB_WC_WITH_IMM;
|
|
uwc->byte_len = wqe->dma.length;
|
|
uwc->qp_num = qp->ibqp.qp_num;
|
|
}
|
|
}
|
|
|
|
static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
|
|
{
|
|
struct rxe_cqe cqe;
|
|
|
|
if ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
|
|
(wqe->wr.send_flags & IB_SEND_SIGNALED) ||
|
|
(qp->req.state == QP_STATE_ERROR)) {
|
|
make_send_cqe(qp, wqe, &cqe);
|
|
rxe_cq_post(qp->scq, &cqe, 0);
|
|
}
|
|
|
|
advance_consumer(qp->sq.queue);
|
|
|
|
/*
|
|
* we completed something so let req run again
|
|
* if it is trying to fence
|
|
*/
|
|
if (qp->req.wait_fence) {
|
|
qp->req.wait_fence = 0;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
}
|
|
|
|
static inline enum comp_state complete_ack(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
unsigned long flags;
|
|
|
|
if (wqe->has_rd_atomic) {
|
|
wqe->has_rd_atomic = 0;
|
|
atomic_inc(&qp->req.rd_atomic);
|
|
if (qp->req.need_rd_atomic) {
|
|
qp->comp.timeout_retry = 0;
|
|
qp->req.need_rd_atomic = 0;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
}
|
|
|
|
if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
|
|
/* state_lock used by requester & completer */
|
|
spin_lock_irqsave(&qp->state_lock, flags);
|
|
if ((qp->req.state == QP_STATE_DRAIN) &&
|
|
(qp->comp.psn == qp->req.psn)) {
|
|
qp->req.state = QP_STATE_DRAINED;
|
|
spin_unlock_irqrestore(&qp->state_lock, flags);
|
|
|
|
if (qp->ibqp.event_handler) {
|
|
struct ib_event ev;
|
|
|
|
ev.device = qp->ibqp.device;
|
|
ev.element.qp = &qp->ibqp;
|
|
ev.event = IB_EVENT_SQ_DRAINED;
|
|
qp->ibqp.event_handler(&ev,
|
|
qp->ibqp.qp_context);
|
|
}
|
|
} else {
|
|
spin_unlock_irqrestore(&qp->state_lock, flags);
|
|
}
|
|
}
|
|
|
|
do_complete(qp, wqe);
|
|
|
|
if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
|
|
return COMPST_UPDATE_COMP;
|
|
else
|
|
return COMPST_DONE;
|
|
}
|
|
|
|
static inline enum comp_state complete_wqe(struct rxe_qp *qp,
|
|
struct rxe_pkt_info *pkt,
|
|
struct rxe_send_wqe *wqe)
|
|
{
|
|
if (pkt && wqe->state == wqe_state_pending) {
|
|
if (psn_compare(wqe->last_psn, qp->comp.psn) >= 0) {
|
|
qp->comp.psn = (wqe->last_psn + 1) & BTH_PSN_MASK;
|
|
qp->comp.opcode = -1;
|
|
}
|
|
|
|
if (qp->req.wait_psn) {
|
|
qp->req.wait_psn = 0;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
}
|
|
|
|
do_complete(qp, wqe);
|
|
|
|
return COMPST_GET_WQE;
|
|
}
|
|
|
|
int rxe_completer(void *arg)
|
|
{
|
|
struct rxe_qp *qp = (struct rxe_qp *)arg;
|
|
struct rxe_send_wqe *wqe = wqe;
|
|
struct sk_buff *skb = NULL;
|
|
struct rxe_pkt_info *pkt = NULL;
|
|
enum comp_state state;
|
|
|
|
if (!qp->valid) {
|
|
while ((skb = skb_dequeue(&qp->resp_pkts))) {
|
|
rxe_drop_ref(qp);
|
|
kfree_skb(skb);
|
|
}
|
|
skb = NULL;
|
|
pkt = NULL;
|
|
|
|
while (queue_head(qp->sq.queue))
|
|
advance_consumer(qp->sq.queue);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (qp->req.state == QP_STATE_ERROR) {
|
|
while ((skb = skb_dequeue(&qp->resp_pkts))) {
|
|
rxe_drop_ref(qp);
|
|
kfree_skb(skb);
|
|
}
|
|
skb = NULL;
|
|
pkt = NULL;
|
|
|
|
while ((wqe = queue_head(qp->sq.queue))) {
|
|
wqe->status = IB_WC_WR_FLUSH_ERR;
|
|
do_complete(qp, wqe);
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (qp->req.state == QP_STATE_RESET) {
|
|
while ((skb = skb_dequeue(&qp->resp_pkts))) {
|
|
rxe_drop_ref(qp);
|
|
kfree_skb(skb);
|
|
}
|
|
skb = NULL;
|
|
pkt = NULL;
|
|
|
|
while (queue_head(qp->sq.queue))
|
|
advance_consumer(qp->sq.queue);
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (qp->comp.timeout) {
|
|
qp->comp.timeout_retry = 1;
|
|
qp->comp.timeout = 0;
|
|
} else {
|
|
qp->comp.timeout_retry = 0;
|
|
}
|
|
|
|
if (qp->req.need_retry)
|
|
goto exit;
|
|
|
|
state = COMPST_GET_ACK;
|
|
|
|
while (1) {
|
|
pr_debug("qp#%d state = %s\n", qp_num(qp),
|
|
comp_state_name[state]);
|
|
switch (state) {
|
|
case COMPST_GET_ACK:
|
|
skb = skb_dequeue(&qp->resp_pkts);
|
|
if (skb) {
|
|
pkt = SKB_TO_PKT(skb);
|
|
qp->comp.timeout_retry = 0;
|
|
}
|
|
state = COMPST_GET_WQE;
|
|
break;
|
|
|
|
case COMPST_GET_WQE:
|
|
state = get_wqe(qp, pkt, &wqe);
|
|
break;
|
|
|
|
case COMPST_CHECK_PSN:
|
|
state = check_psn(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_CHECK_ACK:
|
|
state = check_ack(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_READ:
|
|
state = do_read(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_ATOMIC:
|
|
state = do_atomic(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_WRITE_SEND:
|
|
if (wqe->state == wqe_state_pending &&
|
|
wqe->last_psn == pkt->psn)
|
|
state = COMPST_COMP_ACK;
|
|
else
|
|
state = COMPST_UPDATE_COMP;
|
|
break;
|
|
|
|
case COMPST_COMP_ACK:
|
|
state = complete_ack(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_COMP_WQE:
|
|
state = complete_wqe(qp, pkt, wqe);
|
|
break;
|
|
|
|
case COMPST_UPDATE_COMP:
|
|
if (pkt->mask & RXE_END_MASK)
|
|
qp->comp.opcode = -1;
|
|
else
|
|
qp->comp.opcode = pkt->opcode;
|
|
|
|
if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
|
|
qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
|
|
|
|
if (qp->req.wait_psn) {
|
|
qp->req.wait_psn = 0;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
|
|
state = COMPST_DONE;
|
|
break;
|
|
|
|
case COMPST_DONE:
|
|
if (pkt) {
|
|
rxe_drop_ref(pkt->qp);
|
|
kfree_skb(skb);
|
|
}
|
|
goto done;
|
|
|
|
case COMPST_EXIT:
|
|
if (qp->comp.timeout_retry && wqe) {
|
|
state = COMPST_ERROR_RETRY;
|
|
break;
|
|
}
|
|
|
|
/* re reset the timeout counter if
|
|
* (1) QP is type RC
|
|
* (2) the QP is alive
|
|
* (3) there is a packet sent by the requester that
|
|
* might be acked (we still might get spurious
|
|
* timeouts but try to keep them as few as possible)
|
|
* (4) the timeout parameter is set
|
|
*/
|
|
if ((qp_type(qp) == IB_QPT_RC) &&
|
|
(qp->req.state == QP_STATE_READY) &&
|
|
(psn_compare(qp->req.psn, qp->comp.psn) > 0) &&
|
|
qp->qp_timeout_jiffies)
|
|
mod_timer(&qp->retrans_timer,
|
|
jiffies + qp->qp_timeout_jiffies);
|
|
goto exit;
|
|
|
|
case COMPST_ERROR_RETRY:
|
|
/* we come here if the retry timer fired and we did
|
|
* not receive a response packet. try to retry the send
|
|
* queue if that makes sense and the limits have not
|
|
* been exceeded. remember that some timeouts are
|
|
* spurious since we do not reset the timer but kick
|
|
* it down the road or let it expire
|
|
*/
|
|
|
|
/* there is nothing to retry in this case */
|
|
if (!wqe || (wqe->state == wqe_state_posted))
|
|
goto exit;
|
|
|
|
if (qp->comp.retry_cnt > 0) {
|
|
if (qp->comp.retry_cnt != 7)
|
|
qp->comp.retry_cnt--;
|
|
|
|
/* no point in retrying if we have already
|
|
* seen the last ack that the requester could
|
|
* have caused
|
|
*/
|
|
if (psn_compare(qp->req.psn,
|
|
qp->comp.psn) > 0) {
|
|
/* tell the requester to retry the
|
|
* send send queue next time around
|
|
*/
|
|
qp->req.need_retry = 1;
|
|
rxe_run_task(&qp->req.task, 1);
|
|
}
|
|
|
|
if (pkt) {
|
|
rxe_drop_ref(pkt->qp);
|
|
kfree_skb(skb);
|
|
}
|
|
|
|
goto exit;
|
|
|
|
} else {
|
|
wqe->status = IB_WC_RETRY_EXC_ERR;
|
|
state = COMPST_ERROR;
|
|
}
|
|
break;
|
|
|
|
case COMPST_RNR_RETRY:
|
|
if (qp->comp.rnr_retry > 0) {
|
|
if (qp->comp.rnr_retry != 7)
|
|
qp->comp.rnr_retry--;
|
|
|
|
qp->req.need_retry = 1;
|
|
pr_debug("qp#%d set rnr nak timer\n",
|
|
qp_num(qp));
|
|
mod_timer(&qp->rnr_nak_timer,
|
|
jiffies + rnrnak_jiffies(aeth_syn(pkt)
|
|
& ~AETH_TYPE_MASK));
|
|
goto exit;
|
|
} else {
|
|
wqe->status = IB_WC_RNR_RETRY_EXC_ERR;
|
|
state = COMPST_ERROR;
|
|
}
|
|
break;
|
|
|
|
case COMPST_ERROR:
|
|
do_complete(qp, wqe);
|
|
rxe_qp_error(qp);
|
|
|
|
if (pkt) {
|
|
rxe_drop_ref(pkt->qp);
|
|
kfree_skb(skb);
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
/* we come here if we are done with processing and want the task to
|
|
* exit from the loop calling us
|
|
*/
|
|
return -EAGAIN;
|
|
|
|
done:
|
|
/* we come here if we have processed a packet we want the task to call
|
|
* us again to see if there is anything else to do
|
|
*/
|
|
return 0;
|
|
}
|