18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/module.h>
348c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
358c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h>
368c2ecf20Sopenharmony_ci#include <linux/atomic.h>
378c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "iw_cxgb4.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciint use_dsgl = 1;
428c2ecf20Sopenharmony_cimodule_param(use_dsgl, int, 0644);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=1) (DEPRECATED)");
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define T4_ULPTX_MIN_IO 32
468c2ecf20Sopenharmony_ci#define C4IW_MAX_INLINE_SIZE 96
478c2ecf20Sopenharmony_ci#define T4_ULPTX_MAX_DMA 1024
488c2ecf20Sopenharmony_ci#define C4IW_INLINE_THRESHOLD 128
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int inline_threshold = C4IW_INLINE_THRESHOLD;
518c2ecf20Sopenharmony_cimodule_param(inline_threshold, int, 0644);
528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inline_threshold, "inline vs dsgl threshold (default=128)");
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int mr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return (is_t4(dev->rdev.lldi.adapter_type) ||
578c2ecf20Sopenharmony_ci		is_t5(dev->rdev.lldi.adapter_type)) &&
588c2ecf20Sopenharmony_ci		length >= 8*1024*1024*1024ULL;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
628c2ecf20Sopenharmony_ci				       u32 len, dma_addr_t data,
638c2ecf20Sopenharmony_ci				       struct sk_buff *skb,
648c2ecf20Sopenharmony_ci				       struct c4iw_wr_wait *wr_waitp)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct ulp_mem_io *req;
678c2ecf20Sopenharmony_ci	struct ulptx_sgl *sgl;
688c2ecf20Sopenharmony_ci	u8 wr_len;
698c2ecf20Sopenharmony_ci	int ret = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	addr &= 0x7FFFFFF;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (wr_waitp)
748c2ecf20Sopenharmony_ci		c4iw_init_wr_wait(wr_waitp);
758c2ecf20Sopenharmony_ci	wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (!skb) {
788c2ecf20Sopenharmony_ci		skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
798c2ecf20Sopenharmony_ci		if (!skb)
808c2ecf20Sopenharmony_ci			return -ENOMEM;
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	req = __skb_put_zero(skb, wr_len);
858c2ecf20Sopenharmony_ci	INIT_ULPTX_WR(req, wr_len, 0, 0);
868c2ecf20Sopenharmony_ci	req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
878c2ecf20Sopenharmony_ci			(wr_waitp ? FW_WR_COMPL_F : 0));
888c2ecf20Sopenharmony_ci	req->wr.wr_lo = wr_waitp ? (__force __be64)(unsigned long)wr_waitp : 0L;
898c2ecf20Sopenharmony_ci	req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
908c2ecf20Sopenharmony_ci	req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
918c2ecf20Sopenharmony_ci			       T5_ULP_MEMIO_ORDER_V(1) |
928c2ecf20Sopenharmony_ci			       T5_ULP_MEMIO_FID_V(rdev->lldi.rxq_ids[0]));
938c2ecf20Sopenharmony_ci	req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(len>>5));
948c2ecf20Sopenharmony_ci	req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
958c2ecf20Sopenharmony_ci	req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr));
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	sgl = (struct ulptx_sgl *)(req + 1);
988c2ecf20Sopenharmony_ci	sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
998c2ecf20Sopenharmony_ci				    ULPTX_NSGE_V(1));
1008c2ecf20Sopenharmony_ci	sgl->len0 = cpu_to_be32(len);
1018c2ecf20Sopenharmony_ci	sgl->addr0 = cpu_to_be64(data);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (wr_waitp)
1048c2ecf20Sopenharmony_ci		ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
1058c2ecf20Sopenharmony_ci	else
1068c2ecf20Sopenharmony_ci		ret = c4iw_ofld_send(rdev, skb);
1078c2ecf20Sopenharmony_ci	return ret;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
1118c2ecf20Sopenharmony_ci				  void *data, struct sk_buff *skb,
1128c2ecf20Sopenharmony_ci				  struct c4iw_wr_wait *wr_waitp)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct ulp_mem_io *req;
1158c2ecf20Sopenharmony_ci	struct ulptx_idata *sc;
1168c2ecf20Sopenharmony_ci	u8 wr_len, *to_dp, *from_dp;
1178c2ecf20Sopenharmony_ci	int copy_len, num_wqe, i, ret = 0;
1188c2ecf20Sopenharmony_ci	__be32 cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (is_t4(rdev->lldi.adapter_type))
1218c2ecf20Sopenharmony_ci		cmd |= cpu_to_be32(ULP_MEMIO_ORDER_F);
1228c2ecf20Sopenharmony_ci	else
1238c2ecf20Sopenharmony_ci		cmd |= cpu_to_be32(T5_ULP_MEMIO_IMM_F);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	addr &= 0x7FFFFFF;
1268c2ecf20Sopenharmony_ci	pr_debug("addr 0x%x len %u\n", addr, len);
1278c2ecf20Sopenharmony_ci	num_wqe = DIV_ROUND_UP(len, C4IW_MAX_INLINE_SIZE);
1288c2ecf20Sopenharmony_ci	c4iw_init_wr_wait(wr_waitp);
1298c2ecf20Sopenharmony_ci	for (i = 0; i < num_wqe; i++) {
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		copy_len = len > C4IW_MAX_INLINE_SIZE ? C4IW_MAX_INLINE_SIZE :
1328c2ecf20Sopenharmony_ci			   len;
1338c2ecf20Sopenharmony_ci		wr_len = roundup(sizeof(*req) + sizeof(*sc) +
1348c2ecf20Sopenharmony_ci					 roundup(copy_len, T4_ULPTX_MIN_IO),
1358c2ecf20Sopenharmony_ci				 16);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		if (!skb) {
1388c2ecf20Sopenharmony_ci			skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
1398c2ecf20Sopenharmony_ci			if (!skb)
1408c2ecf20Sopenharmony_ci				return -ENOMEM;
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		req = __skb_put_zero(skb, wr_len);
1458c2ecf20Sopenharmony_ci		INIT_ULPTX_WR(req, wr_len, 0, 0);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		if (i == (num_wqe-1)) {
1488c2ecf20Sopenharmony_ci			req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
1498c2ecf20Sopenharmony_ci						    FW_WR_COMPL_F);
1508c2ecf20Sopenharmony_ci			req->wr.wr_lo = (__force __be64)(unsigned long)wr_waitp;
1518c2ecf20Sopenharmony_ci		} else
1528c2ecf20Sopenharmony_ci			req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
1538c2ecf20Sopenharmony_ci		req->wr.wr_mid = cpu_to_be32(
1548c2ecf20Sopenharmony_ci				       FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		req->cmd = cmd;
1578c2ecf20Sopenharmony_ci		req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(
1588c2ecf20Sopenharmony_ci				DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
1598c2ecf20Sopenharmony_ci		req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr),
1608c2ecf20Sopenharmony_ci						      16));
1618c2ecf20Sopenharmony_ci		req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr + i * 3));
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		sc = (struct ulptx_idata *)(req + 1);
1648c2ecf20Sopenharmony_ci		sc->cmd_more = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_IMM));
1658c2ecf20Sopenharmony_ci		sc->len = cpu_to_be32(roundup(copy_len, T4_ULPTX_MIN_IO));
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci		to_dp = (u8 *)(sc + 1);
1688c2ecf20Sopenharmony_ci		from_dp = (u8 *)data + i * C4IW_MAX_INLINE_SIZE;
1698c2ecf20Sopenharmony_ci		if (data)
1708c2ecf20Sopenharmony_ci			memcpy(to_dp, from_dp, copy_len);
1718c2ecf20Sopenharmony_ci		else
1728c2ecf20Sopenharmony_ci			memset(to_dp, 0, copy_len);
1738c2ecf20Sopenharmony_ci		if (copy_len % T4_ULPTX_MIN_IO)
1748c2ecf20Sopenharmony_ci			memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO -
1758c2ecf20Sopenharmony_ci			       (copy_len % T4_ULPTX_MIN_IO));
1768c2ecf20Sopenharmony_ci		if (i == (num_wqe-1))
1778c2ecf20Sopenharmony_ci			ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0,
1788c2ecf20Sopenharmony_ci						 __func__);
1798c2ecf20Sopenharmony_ci		else
1808c2ecf20Sopenharmony_ci			ret = c4iw_ofld_send(rdev, skb);
1818c2ecf20Sopenharmony_ci		if (ret)
1828c2ecf20Sopenharmony_ci			break;
1838c2ecf20Sopenharmony_ci		skb = NULL;
1848c2ecf20Sopenharmony_ci		len -= C4IW_MAX_INLINE_SIZE;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return ret;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
1918c2ecf20Sopenharmony_ci			       void *data, struct sk_buff *skb,
1928c2ecf20Sopenharmony_ci			       struct c4iw_wr_wait *wr_waitp)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	u32 remain = len;
1958c2ecf20Sopenharmony_ci	u32 dmalen;
1968c2ecf20Sopenharmony_ci	int ret = 0;
1978c2ecf20Sopenharmony_ci	dma_addr_t daddr;
1988c2ecf20Sopenharmony_ci	dma_addr_t save;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	daddr = dma_map_single(&rdev->lldi.pdev->dev, data, len, DMA_TO_DEVICE);
2018c2ecf20Sopenharmony_ci	if (dma_mapping_error(&rdev->lldi.pdev->dev, daddr))
2028c2ecf20Sopenharmony_ci		return -1;
2038c2ecf20Sopenharmony_ci	save = daddr;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	while (remain > inline_threshold) {
2068c2ecf20Sopenharmony_ci		if (remain < T4_ULPTX_MAX_DMA) {
2078c2ecf20Sopenharmony_ci			if (remain & ~T4_ULPTX_MIN_IO)
2088c2ecf20Sopenharmony_ci				dmalen = remain & ~(T4_ULPTX_MIN_IO-1);
2098c2ecf20Sopenharmony_ci			else
2108c2ecf20Sopenharmony_ci				dmalen = remain;
2118c2ecf20Sopenharmony_ci		} else
2128c2ecf20Sopenharmony_ci			dmalen = T4_ULPTX_MAX_DMA;
2138c2ecf20Sopenharmony_ci		remain -= dmalen;
2148c2ecf20Sopenharmony_ci		ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr,
2158c2ecf20Sopenharmony_ci						 skb, remain ? NULL : wr_waitp);
2168c2ecf20Sopenharmony_ci		if (ret)
2178c2ecf20Sopenharmony_ci			goto out;
2188c2ecf20Sopenharmony_ci		addr += dmalen >> 5;
2198c2ecf20Sopenharmony_ci		data += dmalen;
2208c2ecf20Sopenharmony_ci		daddr += dmalen;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	if (remain)
2238c2ecf20Sopenharmony_ci		ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb,
2248c2ecf20Sopenharmony_ci					     wr_waitp);
2258c2ecf20Sopenharmony_ciout:
2268c2ecf20Sopenharmony_ci	dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE);
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * write len bytes of data into addr (32B aligned address)
2328c2ecf20Sopenharmony_ci * If data is NULL, clear len byte of memory to zero.
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_cistatic int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
2358c2ecf20Sopenharmony_ci			     void *data, struct sk_buff *skb,
2368c2ecf20Sopenharmony_ci			     struct c4iw_wr_wait *wr_waitp)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	int ret;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl) {
2418c2ecf20Sopenharmony_ci		ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
2428c2ecf20Sopenharmony_ci					      wr_waitp);
2438c2ecf20Sopenharmony_ci		goto out;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (len <= inline_threshold) {
2478c2ecf20Sopenharmony_ci		ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
2488c2ecf20Sopenharmony_ci					      wr_waitp);
2498c2ecf20Sopenharmony_ci		goto out;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ret = _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
2538c2ecf20Sopenharmony_ci	if (ret) {
2548c2ecf20Sopenharmony_ci		pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
2558c2ecf20Sopenharmony_ci				    pci_name(rdev->lldi.pdev));
2568c2ecf20Sopenharmony_ci		ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
2578c2ecf20Sopenharmony_ci					      wr_waitp);
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ciout:
2608c2ecf20Sopenharmony_ci	return ret;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/*
2658c2ecf20Sopenharmony_ci * Build and write a TPT entry.
2668c2ecf20Sopenharmony_ci * IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size,
2678c2ecf20Sopenharmony_ci *     pbl_size and pbl_addr
2688c2ecf20Sopenharmony_ci * OUT: stag index
2698c2ecf20Sopenharmony_ci */
2708c2ecf20Sopenharmony_cistatic int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
2718c2ecf20Sopenharmony_ci			   u32 *stag, u8 stag_state, u32 pdid,
2728c2ecf20Sopenharmony_ci			   enum fw_ri_stag_type type, enum fw_ri_mem_perms perm,
2738c2ecf20Sopenharmony_ci			   int bind_enabled, u32 zbva, u64 to,
2748c2ecf20Sopenharmony_ci			   u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr,
2758c2ecf20Sopenharmony_ci			   struct sk_buff *skb, struct c4iw_wr_wait *wr_waitp)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int err;
2788c2ecf20Sopenharmony_ci	struct fw_ri_tpte *tpt;
2798c2ecf20Sopenharmony_ci	u32 stag_idx;
2808c2ecf20Sopenharmony_ci	static atomic_t key;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (c4iw_fatal_error(rdev))
2838c2ecf20Sopenharmony_ci		return -EIO;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	tpt = kmalloc(sizeof(*tpt), GFP_KERNEL);
2868c2ecf20Sopenharmony_ci	if (!tpt)
2878c2ecf20Sopenharmony_ci		return -ENOMEM;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	stag_state = stag_state > 0;
2908c2ecf20Sopenharmony_ci	stag_idx = (*stag) >> 8;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
2938c2ecf20Sopenharmony_ci		stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
2948c2ecf20Sopenharmony_ci		if (!stag_idx) {
2958c2ecf20Sopenharmony_ci			mutex_lock(&rdev->stats.lock);
2968c2ecf20Sopenharmony_ci			rdev->stats.stag.fail++;
2978c2ecf20Sopenharmony_ci			mutex_unlock(&rdev->stats.lock);
2988c2ecf20Sopenharmony_ci			kfree(tpt);
2998c2ecf20Sopenharmony_ci			return -ENOMEM;
3008c2ecf20Sopenharmony_ci		}
3018c2ecf20Sopenharmony_ci		mutex_lock(&rdev->stats.lock);
3028c2ecf20Sopenharmony_ci		rdev->stats.stag.cur += 32;
3038c2ecf20Sopenharmony_ci		if (rdev->stats.stag.cur > rdev->stats.stag.max)
3048c2ecf20Sopenharmony_ci			rdev->stats.stag.max = rdev->stats.stag.cur;
3058c2ecf20Sopenharmony_ci		mutex_unlock(&rdev->stats.lock);
3068c2ecf20Sopenharmony_ci		*stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff);
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci	pr_debug("stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
3098c2ecf20Sopenharmony_ci		 stag_state, type, pdid, stag_idx);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* write TPT entry */
3128c2ecf20Sopenharmony_ci	if (reset_tpt_entry)
3138c2ecf20Sopenharmony_ci		memset(tpt, 0, sizeof(*tpt));
3148c2ecf20Sopenharmony_ci	else {
3158c2ecf20Sopenharmony_ci		tpt->valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
3168c2ecf20Sopenharmony_ci			FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) |
3178c2ecf20Sopenharmony_ci			FW_RI_TPTE_STAGSTATE_V(stag_state) |
3188c2ecf20Sopenharmony_ci			FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid));
3198c2ecf20Sopenharmony_ci		tpt->locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
3208c2ecf20Sopenharmony_ci			(bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) |
3218c2ecf20Sopenharmony_ci			FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO :
3228c2ecf20Sopenharmony_ci						      FW_RI_VA_BASED_TO))|
3238c2ecf20Sopenharmony_ci			FW_RI_TPTE_PS_V(page_size));
3248c2ecf20Sopenharmony_ci		tpt->nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
3258c2ecf20Sopenharmony_ci			FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3));
3268c2ecf20Sopenharmony_ci		tpt->len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
3278c2ecf20Sopenharmony_ci		tpt->va_hi = cpu_to_be32((u32)(to >> 32));
3288c2ecf20Sopenharmony_ci		tpt->va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
3298c2ecf20Sopenharmony_ci		tpt->dca_mwbcnt_pstag = cpu_to_be32(0);
3308c2ecf20Sopenharmony_ci		tpt->len_hi = cpu_to_be32((u32)(len >> 32));
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci	err = write_adapter_mem(rdev, stag_idx +
3338c2ecf20Sopenharmony_ci				(rdev->lldi.vr->stag.start >> 5),
3348c2ecf20Sopenharmony_ci				sizeof(*tpt), tpt, skb, wr_waitp);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (reset_tpt_entry) {
3378c2ecf20Sopenharmony_ci		c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
3388c2ecf20Sopenharmony_ci		mutex_lock(&rdev->stats.lock);
3398c2ecf20Sopenharmony_ci		rdev->stats.stag.cur -= 32;
3408c2ecf20Sopenharmony_ci		mutex_unlock(&rdev->stats.lock);
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	kfree(tpt);
3438c2ecf20Sopenharmony_ci	return err;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int write_pbl(struct c4iw_rdev *rdev, __be64 *pbl,
3478c2ecf20Sopenharmony_ci		     u32 pbl_addr, u32 pbl_size, struct c4iw_wr_wait *wr_waitp)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	int err;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	pr_debug("*pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
3528c2ecf20Sopenharmony_ci		 pbl_addr, rdev->lldi.vr->pbl.start,
3538c2ecf20Sopenharmony_ci		 pbl_size);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL,
3568c2ecf20Sopenharmony_ci				wr_waitp);
3578c2ecf20Sopenharmony_ci	return err;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size,
3618c2ecf20Sopenharmony_ci		     u32 pbl_addr, struct sk_buff *skb,
3628c2ecf20Sopenharmony_ci		     struct c4iw_wr_wait *wr_waitp)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0,
3658c2ecf20Sopenharmony_ci			       pbl_size, pbl_addr, skb, wr_waitp);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic int allocate_window(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
3698c2ecf20Sopenharmony_ci			   struct c4iw_wr_wait *wr_waitp)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	*stag = T4_STAG_UNSET;
3728c2ecf20Sopenharmony_ci	return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_MW, 0, 0, 0,
3738c2ecf20Sopenharmony_ci			       0UL, 0, 0, 0, 0, NULL, wr_waitp);
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int deallocate_window(struct c4iw_rdev *rdev, u32 stag,
3778c2ecf20Sopenharmony_ci			     struct sk_buff *skb,
3788c2ecf20Sopenharmony_ci			     struct c4iw_wr_wait *wr_waitp)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 0,
3818c2ecf20Sopenharmony_ci			       0, skb, wr_waitp);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
3858c2ecf20Sopenharmony_ci			 u32 pbl_size, u32 pbl_addr,
3868c2ecf20Sopenharmony_ci			 struct c4iw_wr_wait *wr_waitp)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	*stag = T4_STAG_UNSET;
3898c2ecf20Sopenharmony_ci	return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0,
3908c2ecf20Sopenharmony_ci			       0UL, 0, 0, pbl_size, pbl_addr, NULL, wr_waitp);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int finish_mem_reg(struct c4iw_mr *mhp, u32 stag)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	u32 mmid;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	mhp->attr.state = 1;
3988c2ecf20Sopenharmony_ci	mhp->attr.stag = stag;
3998c2ecf20Sopenharmony_ci	mmid = stag >> 8;
4008c2ecf20Sopenharmony_ci	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
4018c2ecf20Sopenharmony_ci	mhp->ibmr.length = mhp->attr.len;
4028c2ecf20Sopenharmony_ci	mhp->ibmr.page_size = 1U << (mhp->attr.page_size + 12);
4038c2ecf20Sopenharmony_ci	pr_debug("mmid 0x%x mhp %p\n", mmid, mhp);
4048c2ecf20Sopenharmony_ci	return xa_insert_irq(&mhp->rhp->mrs, mmid, mhp, GFP_KERNEL);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
4088c2ecf20Sopenharmony_ci		      struct c4iw_mr *mhp, int shift)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	u32 stag = T4_STAG_UNSET;
4118c2ecf20Sopenharmony_ci	int ret;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, mhp->attr.pdid,
4148c2ecf20Sopenharmony_ci			      FW_RI_STAG_NSMR, mhp->attr.len ?
4158c2ecf20Sopenharmony_ci			      mhp->attr.perms : 0,
4168c2ecf20Sopenharmony_ci			      mhp->attr.mw_bind_enable, mhp->attr.zbva,
4178c2ecf20Sopenharmony_ci			      mhp->attr.va_fbo, mhp->attr.len ?
4188c2ecf20Sopenharmony_ci			      mhp->attr.len : -1, shift - 12,
4198c2ecf20Sopenharmony_ci			      mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL,
4208c2ecf20Sopenharmony_ci			      mhp->wr_waitp);
4218c2ecf20Sopenharmony_ci	if (ret)
4228c2ecf20Sopenharmony_ci		return ret;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	ret = finish_mem_reg(mhp, stag);
4258c2ecf20Sopenharmony_ci	if (ret) {
4268c2ecf20Sopenharmony_ci		dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
4278c2ecf20Sopenharmony_ci			  mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
4288c2ecf20Sopenharmony_ci		mhp->dereg_skb = NULL;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci	return ret;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int alloc_pbl(struct c4iw_mr *mhp, int npages)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	mhp->attr.pbl_addr = c4iw_pblpool_alloc(&mhp->rhp->rdev,
4368c2ecf20Sopenharmony_ci						    npages << 3);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (!mhp->attr.pbl_addr)
4398c2ecf20Sopenharmony_ci		return -ENOMEM;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	mhp->attr.pbl_size = npages;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistruct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
4498c2ecf20Sopenharmony_ci	struct c4iw_pd *php;
4508c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp;
4518c2ecf20Sopenharmony_ci	int ret;
4528c2ecf20Sopenharmony_ci	u32 stag = T4_STAG_UNSET;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	pr_debug("ib_pd %p\n", pd);
4558c2ecf20Sopenharmony_ci	php = to_c4iw_pd(pd);
4568c2ecf20Sopenharmony_ci	rhp = php->rhp;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
4598c2ecf20Sopenharmony_ci	if (!mhp)
4608c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4618c2ecf20Sopenharmony_ci	mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
4628c2ecf20Sopenharmony_ci	if (!mhp->wr_waitp) {
4638c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4648c2ecf20Sopenharmony_ci		goto err_free_mhp;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	c4iw_init_wr_wait(mhp->wr_waitp);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
4698c2ecf20Sopenharmony_ci	if (!mhp->dereg_skb) {
4708c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4718c2ecf20Sopenharmony_ci		goto err_free_wr_wait;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	mhp->rhp = rhp;
4758c2ecf20Sopenharmony_ci	mhp->attr.pdid = php->pdid;
4768c2ecf20Sopenharmony_ci	mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
4778c2ecf20Sopenharmony_ci	mhp->attr.mw_bind_enable = (acc&IB_ACCESS_MW_BIND) == IB_ACCESS_MW_BIND;
4788c2ecf20Sopenharmony_ci	mhp->attr.zbva = 0;
4798c2ecf20Sopenharmony_ci	mhp->attr.va_fbo = 0;
4808c2ecf20Sopenharmony_ci	mhp->attr.page_size = 0;
4818c2ecf20Sopenharmony_ci	mhp->attr.len = ~0ULL;
4828c2ecf20Sopenharmony_ci	mhp->attr.pbl_size = 0;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
4858c2ecf20Sopenharmony_ci			      FW_RI_STAG_NSMR, mhp->attr.perms,
4868c2ecf20Sopenharmony_ci			      mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
4878c2ecf20Sopenharmony_ci			      NULL, mhp->wr_waitp);
4888c2ecf20Sopenharmony_ci	if (ret)
4898c2ecf20Sopenharmony_ci		goto err_free_skb;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	ret = finish_mem_reg(mhp, stag);
4928c2ecf20Sopenharmony_ci	if (ret)
4938c2ecf20Sopenharmony_ci		goto err_dereg_mem;
4948c2ecf20Sopenharmony_ci	return &mhp->ibmr;
4958c2ecf20Sopenharmony_cierr_dereg_mem:
4968c2ecf20Sopenharmony_ci	dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
4978c2ecf20Sopenharmony_ci		  mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
4988c2ecf20Sopenharmony_cierr_free_skb:
4998c2ecf20Sopenharmony_ci	kfree_skb(mhp->dereg_skb);
5008c2ecf20Sopenharmony_cierr_free_wr_wait:
5018c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
5028c2ecf20Sopenharmony_cierr_free_mhp:
5038c2ecf20Sopenharmony_ci	kfree(mhp);
5048c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistruct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
5088c2ecf20Sopenharmony_ci			       u64 virt, int acc, struct ib_udata *udata)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	__be64 *pages;
5118c2ecf20Sopenharmony_ci	int shift, n, i;
5128c2ecf20Sopenharmony_ci	int err = -ENOMEM;
5138c2ecf20Sopenharmony_ci	struct ib_block_iter biter;
5148c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
5158c2ecf20Sopenharmony_ci	struct c4iw_pd *php;
5168c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	pr_debug("ib_pd %p\n", pd);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (length == ~0ULL)
5218c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if ((length + start) < start)
5248c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	php = to_c4iw_pd(pd);
5278c2ecf20Sopenharmony_ci	rhp = php->rhp;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (mr_exceeds_hw_limits(rhp, length))
5308c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
5338c2ecf20Sopenharmony_ci	if (!mhp)
5348c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5358c2ecf20Sopenharmony_ci	mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
5368c2ecf20Sopenharmony_ci	if (!mhp->wr_waitp)
5378c2ecf20Sopenharmony_ci		goto err_free_mhp;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
5408c2ecf20Sopenharmony_ci	if (!mhp->dereg_skb)
5418c2ecf20Sopenharmony_ci		goto err_free_wr_wait;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	mhp->rhp = rhp;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	mhp->umem = ib_umem_get(pd->device, start, length, acc);
5468c2ecf20Sopenharmony_ci	if (IS_ERR(mhp->umem))
5478c2ecf20Sopenharmony_ci		goto err_free_skb;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	shift = PAGE_SHIFT;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	n = ib_umem_num_dma_blocks(mhp->umem, 1 << shift);
5528c2ecf20Sopenharmony_ci	err = alloc_pbl(mhp, n);
5538c2ecf20Sopenharmony_ci	if (err)
5548c2ecf20Sopenharmony_ci		goto err_umem_release;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	pages = (__be64 *) __get_free_page(GFP_KERNEL);
5578c2ecf20Sopenharmony_ci	if (!pages) {
5588c2ecf20Sopenharmony_ci		err = -ENOMEM;
5598c2ecf20Sopenharmony_ci		goto err_pbl_free;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	i = n = 0;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	rdma_umem_for_each_dma_block(mhp->umem, &biter, 1 << shift) {
5658c2ecf20Sopenharmony_ci		pages[i++] = cpu_to_be64(rdma_block_iter_dma_address(&biter));
5668c2ecf20Sopenharmony_ci		if (i == PAGE_SIZE / sizeof(*pages)) {
5678c2ecf20Sopenharmony_ci			err = write_pbl(&mhp->rhp->rdev, pages,
5688c2ecf20Sopenharmony_ci					mhp->attr.pbl_addr + (n << 3), i,
5698c2ecf20Sopenharmony_ci					mhp->wr_waitp);
5708c2ecf20Sopenharmony_ci			if (err)
5718c2ecf20Sopenharmony_ci				goto pbl_done;
5728c2ecf20Sopenharmony_ci			n += i;
5738c2ecf20Sopenharmony_ci			i = 0;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (i)
5788c2ecf20Sopenharmony_ci		err = write_pbl(&mhp->rhp->rdev, pages,
5798c2ecf20Sopenharmony_ci				mhp->attr.pbl_addr + (n << 3), i,
5808c2ecf20Sopenharmony_ci				mhp->wr_waitp);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cipbl_done:
5838c2ecf20Sopenharmony_ci	free_page((unsigned long) pages);
5848c2ecf20Sopenharmony_ci	if (err)
5858c2ecf20Sopenharmony_ci		goto err_pbl_free;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	mhp->attr.pdid = php->pdid;
5888c2ecf20Sopenharmony_ci	mhp->attr.zbva = 0;
5898c2ecf20Sopenharmony_ci	mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
5908c2ecf20Sopenharmony_ci	mhp->attr.va_fbo = virt;
5918c2ecf20Sopenharmony_ci	mhp->attr.page_size = shift - 12;
5928c2ecf20Sopenharmony_ci	mhp->attr.len = length;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	err = register_mem(rhp, php, mhp, shift);
5958c2ecf20Sopenharmony_ci	if (err)
5968c2ecf20Sopenharmony_ci		goto err_pbl_free;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return &mhp->ibmr;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cierr_pbl_free:
6018c2ecf20Sopenharmony_ci	c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
6028c2ecf20Sopenharmony_ci			      mhp->attr.pbl_size << 3);
6038c2ecf20Sopenharmony_cierr_umem_release:
6048c2ecf20Sopenharmony_ci	ib_umem_release(mhp->umem);
6058c2ecf20Sopenharmony_cierr_free_skb:
6068c2ecf20Sopenharmony_ci	kfree_skb(mhp->dereg_skb);
6078c2ecf20Sopenharmony_cierr_free_wr_wait:
6088c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
6098c2ecf20Sopenharmony_cierr_free_mhp:
6108c2ecf20Sopenharmony_ci	kfree(mhp);
6118c2ecf20Sopenharmony_ci	return ERR_PTR(err);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ciint c4iw_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct c4iw_mw *mhp = to_c4iw_mw(ibmw);
6178c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
6188c2ecf20Sopenharmony_ci	struct c4iw_pd *php;
6198c2ecf20Sopenharmony_ci	u32 mmid;
6208c2ecf20Sopenharmony_ci	u32 stag = 0;
6218c2ecf20Sopenharmony_ci	int ret;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (ibmw->type != IB_MW_TYPE_1)
6248c2ecf20Sopenharmony_ci		return -EINVAL;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	php = to_c4iw_pd(ibmw->pd);
6278c2ecf20Sopenharmony_ci	rhp = php->rhp;
6288c2ecf20Sopenharmony_ci	mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
6298c2ecf20Sopenharmony_ci	if (!mhp->wr_waitp)
6308c2ecf20Sopenharmony_ci		return -ENOMEM;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
6338c2ecf20Sopenharmony_ci	if (!mhp->dereg_skb) {
6348c2ecf20Sopenharmony_ci		ret = -ENOMEM;
6358c2ecf20Sopenharmony_ci		goto free_wr_wait;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	ret = allocate_window(&rhp->rdev, &stag, php->pdid, mhp->wr_waitp);
6398c2ecf20Sopenharmony_ci	if (ret)
6408c2ecf20Sopenharmony_ci		goto free_skb;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	mhp->rhp = rhp;
6438c2ecf20Sopenharmony_ci	mhp->attr.pdid = php->pdid;
6448c2ecf20Sopenharmony_ci	mhp->attr.type = FW_RI_STAG_MW;
6458c2ecf20Sopenharmony_ci	mhp->attr.stag = stag;
6468c2ecf20Sopenharmony_ci	mmid = (stag) >> 8;
6478c2ecf20Sopenharmony_ci	ibmw->rkey = stag;
6488c2ecf20Sopenharmony_ci	if (xa_insert_irq(&rhp->mrs, mmid, mhp, GFP_KERNEL)) {
6498c2ecf20Sopenharmony_ci		ret = -ENOMEM;
6508c2ecf20Sopenharmony_ci		goto dealloc_win;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci	pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
6538c2ecf20Sopenharmony_ci	return 0;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cidealloc_win:
6568c2ecf20Sopenharmony_ci	deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb,
6578c2ecf20Sopenharmony_ci			  mhp->wr_waitp);
6588c2ecf20Sopenharmony_cifree_skb:
6598c2ecf20Sopenharmony_ci	kfree_skb(mhp->dereg_skb);
6608c2ecf20Sopenharmony_cifree_wr_wait:
6618c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
6628c2ecf20Sopenharmony_ci	return ret;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ciint c4iw_dealloc_mw(struct ib_mw *mw)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
6688c2ecf20Sopenharmony_ci	struct c4iw_mw *mhp;
6698c2ecf20Sopenharmony_ci	u32 mmid;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	mhp = to_c4iw_mw(mw);
6728c2ecf20Sopenharmony_ci	rhp = mhp->rhp;
6738c2ecf20Sopenharmony_ci	mmid = (mw->rkey) >> 8;
6748c2ecf20Sopenharmony_ci	xa_erase_irq(&rhp->mrs, mmid);
6758c2ecf20Sopenharmony_ci	deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb,
6768c2ecf20Sopenharmony_ci			  mhp->wr_waitp);
6778c2ecf20Sopenharmony_ci	kfree_skb(mhp->dereg_skb);
6788c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
6798c2ecf20Sopenharmony_ci	return 0;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistruct ib_mr *c4iw_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
6838c2ecf20Sopenharmony_ci			    u32 max_num_sg)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
6868c2ecf20Sopenharmony_ci	struct c4iw_pd *php;
6878c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp;
6888c2ecf20Sopenharmony_ci	u32 mmid;
6898c2ecf20Sopenharmony_ci	u32 stag = 0;
6908c2ecf20Sopenharmony_ci	int ret = 0;
6918c2ecf20Sopenharmony_ci	int length = roundup(max_num_sg * sizeof(u64), 32);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	php = to_c4iw_pd(pd);
6948c2ecf20Sopenharmony_ci	rhp = php->rhp;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (mr_type != IB_MR_TYPE_MEM_REG ||
6978c2ecf20Sopenharmony_ci	    max_num_sg > t4_max_fr_depth(rhp->rdev.lldi.ulptx_memwrite_dsgl &&
6988c2ecf20Sopenharmony_ci					 use_dsgl))
6998c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
7028c2ecf20Sopenharmony_ci	if (!mhp) {
7038c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7048c2ecf20Sopenharmony_ci		goto err;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
7088c2ecf20Sopenharmony_ci	if (!mhp->wr_waitp) {
7098c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7108c2ecf20Sopenharmony_ci		goto err_free_mhp;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci	c4iw_init_wr_wait(mhp->wr_waitp);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	mhp->mpl = dma_alloc_coherent(&rhp->rdev.lldi.pdev->dev,
7158c2ecf20Sopenharmony_ci				      length, &mhp->mpl_addr, GFP_KERNEL);
7168c2ecf20Sopenharmony_ci	if (!mhp->mpl) {
7178c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7188c2ecf20Sopenharmony_ci		goto err_free_wr_wait;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci	mhp->max_mpl_len = length;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	mhp->rhp = rhp;
7238c2ecf20Sopenharmony_ci	ret = alloc_pbl(mhp, max_num_sg);
7248c2ecf20Sopenharmony_ci	if (ret)
7258c2ecf20Sopenharmony_ci		goto err_free_dma;
7268c2ecf20Sopenharmony_ci	mhp->attr.pbl_size = max_num_sg;
7278c2ecf20Sopenharmony_ci	ret = allocate_stag(&rhp->rdev, &stag, php->pdid,
7288c2ecf20Sopenharmony_ci			    mhp->attr.pbl_size, mhp->attr.pbl_addr,
7298c2ecf20Sopenharmony_ci			    mhp->wr_waitp);
7308c2ecf20Sopenharmony_ci	if (ret)
7318c2ecf20Sopenharmony_ci		goto err_free_pbl;
7328c2ecf20Sopenharmony_ci	mhp->attr.pdid = php->pdid;
7338c2ecf20Sopenharmony_ci	mhp->attr.type = FW_RI_STAG_NSMR;
7348c2ecf20Sopenharmony_ci	mhp->attr.stag = stag;
7358c2ecf20Sopenharmony_ci	mhp->attr.state = 0;
7368c2ecf20Sopenharmony_ci	mmid = (stag) >> 8;
7378c2ecf20Sopenharmony_ci	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
7388c2ecf20Sopenharmony_ci	if (xa_insert_irq(&rhp->mrs, mmid, mhp, GFP_KERNEL)) {
7398c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7408c2ecf20Sopenharmony_ci		goto err_dereg;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
7448c2ecf20Sopenharmony_ci	return &(mhp->ibmr);
7458c2ecf20Sopenharmony_cierr_dereg:
7468c2ecf20Sopenharmony_ci	dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
7478c2ecf20Sopenharmony_ci		  mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
7488c2ecf20Sopenharmony_cierr_free_pbl:
7498c2ecf20Sopenharmony_ci	c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
7508c2ecf20Sopenharmony_ci			      mhp->attr.pbl_size << 3);
7518c2ecf20Sopenharmony_cierr_free_dma:
7528c2ecf20Sopenharmony_ci	dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
7538c2ecf20Sopenharmony_ci			  mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
7548c2ecf20Sopenharmony_cierr_free_wr_wait:
7558c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
7568c2ecf20Sopenharmony_cierr_free_mhp:
7578c2ecf20Sopenharmony_ci	kfree(mhp);
7588c2ecf20Sopenharmony_cierr:
7598c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic int c4iw_set_page(struct ib_mr *ibmr, u64 addr)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if (unlikely(mhp->mpl_len == mhp->attr.pbl_size))
7678c2ecf20Sopenharmony_ci		return -ENOMEM;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	mhp->mpl[mhp->mpl_len++] = addr;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	return 0;
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ciint c4iw_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
7758c2ecf20Sopenharmony_ci		   unsigned int *sg_offset)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	mhp->mpl_len = 0;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, c4iw_set_page);
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ciint c4iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct c4iw_dev *rhp;
7878c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp;
7888c2ecf20Sopenharmony_ci	u32 mmid;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	pr_debug("ib_mr %p\n", ib_mr);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	mhp = to_c4iw_mr(ib_mr);
7938c2ecf20Sopenharmony_ci	rhp = mhp->rhp;
7948c2ecf20Sopenharmony_ci	mmid = mhp->attr.stag >> 8;
7958c2ecf20Sopenharmony_ci	xa_erase_irq(&rhp->mrs, mmid);
7968c2ecf20Sopenharmony_ci	if (mhp->mpl)
7978c2ecf20Sopenharmony_ci		dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
7988c2ecf20Sopenharmony_ci				  mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
7998c2ecf20Sopenharmony_ci	dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
8008c2ecf20Sopenharmony_ci		  mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
8018c2ecf20Sopenharmony_ci	if (mhp->attr.pbl_size)
8028c2ecf20Sopenharmony_ci		c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
8038c2ecf20Sopenharmony_ci				  mhp->attr.pbl_size << 3);
8048c2ecf20Sopenharmony_ci	if (mhp->kva)
8058c2ecf20Sopenharmony_ci		kfree((void *) (unsigned long) mhp->kva);
8068c2ecf20Sopenharmony_ci	ib_umem_release(mhp->umem);
8078c2ecf20Sopenharmony_ci	pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
8088c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(mhp->wr_waitp);
8098c2ecf20Sopenharmony_ci	kfree(mhp);
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_civoid c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct c4iw_mr *mhp;
8168c2ecf20Sopenharmony_ci	unsigned long flags;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	xa_lock_irqsave(&rhp->mrs, flags);
8198c2ecf20Sopenharmony_ci	mhp = xa_load(&rhp->mrs, rkey >> 8);
8208c2ecf20Sopenharmony_ci	if (mhp)
8218c2ecf20Sopenharmony_ci		mhp->attr.state = 0;
8228c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(&rhp->mrs, flags);
8238c2ecf20Sopenharmony_ci}
824