mem.c revision 346876
197403Sobrien/*
297403Sobrien * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved.
3169691Skan *
497403Sobrien * This software is available to you under a choice of one of two
597403Sobrien * licenses.  You may choose to be licensed under the terms of the GNU
697403Sobrien * General Public License (GPL) Version 2, available from the file
797403Sobrien * COPYING in the main directory of this source tree, or the
897403Sobrien * OpenIB.org BSD license below:
997403Sobrien *
1097403Sobrien *     Redistribution and use in source and binary forms, with or
1197403Sobrien *     without modification, are permitted provided that the following
1297403Sobrien *     conditions are met:
1397403Sobrien *
1497403Sobrien *      - Redistributions of source code must retain the above
1597403Sobrien *        copyright notice, this list of conditions and the following
1697403Sobrien *        disclaimer.
1797403Sobrien *
18169691Skan *      - Redistributions in binary form must reproduce the above
1997403Sobrien *        copyright notice, this list of conditions and the following
2097403Sobrien *        disclaimer in the documentation and/or other materials
2197403Sobrien *        provided with the distribution.
2297403Sobrien *
2397403Sobrien * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2497403Sobrien * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2597403Sobrien * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2697403Sobrien * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2797403Sobrien * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2897403Sobrien * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2997403Sobrien * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3097403Sobrien * SOFTWARE.
3197403Sobrien */
3297403Sobrien#include <sys/cdefs.h>
3397403Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/cxgbe/iw_cxgbe/mem.c 346876 2019-04-29 04:42:18Z np $");
3497403Sobrien
3597403Sobrien#include "opt_inet.h"
3697403Sobrien
3797403Sobrien#ifdef TCP_OFFLOAD
3897403Sobrien#include <linux/types.h>
3997403Sobrien#include <linux/kref.h>
4097403Sobrien#include <rdma/ib_umem.h>
4197403Sobrien#include <asm/atomic.h>
4297403Sobrien
4397403Sobrien#include <common/t4_msg.h>
4497403Sobrien#include "iw_cxgbe.h"
4597403Sobrien
4697403Sobrienint use_dsgl = 1;
4797403Sobrien#define T4_ULPTX_MIN_IO 32
4897403Sobrien#define C4IW_MAX_INLINE_SIZE 96
4997403Sobrien
5097403Sobrienstatic int
5197403Sobrienmr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
5297403Sobrien{
5397403Sobrien
5497403Sobrien	return (is_t5(dev->rdev.adap) && length >= 8*1024*1024*1024ULL);
5597403Sobrien}
5697403Sobrien
5797403Sobrienstatic int
5897403Sobrienwrite_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
5997403Sobrien{
6097403Sobrien	struct adapter *sc = rdev->adap;
61132720Skan	struct ulp_mem_io *ulpmc;
62132720Skan	struct ulptx_idata *ulpsc;
6397403Sobrien	u8 wr_len, *to_dp, *from_dp;
6497403Sobrien	int copy_len, num_wqe, i, ret = 0;
6597403Sobrien	struct c4iw_wr_wait wr_wait;
66169691Skan	struct wrqe *wr;
67132720Skan	u32 cmd;
6897403Sobrien
69117397Skan	cmd = cpu_to_be32(V_ULPTX_CMD(ULP_TX_MEM_WRITE));
70117397Skan
7197403Sobrien	cmd |= cpu_to_be32(F_T5_ULP_MEMIO_IMM);
72117397Skan
73117397Skan	addr &= 0x7FFFFFF;
7497403Sobrien	CTR3(KTR_IW_CXGBE, "%s addr 0x%x len %u", __func__, addr, len);
75117397Skan	num_wqe = DIV_ROUND_UP(len, C4IW_MAX_INLINE_SIZE);
76117397Skan	c4iw_init_wr_wait(&wr_wait);
77117397Skan	for (i = 0; i < num_wqe; i++) {
78117397Skan
79117397Skan		copy_len = min(len, C4IW_MAX_INLINE_SIZE);
8097403Sobrien		wr_len = roundup(sizeof *ulpmc + sizeof *ulpsc +
81117397Skan				 roundup(copy_len, T4_ULPTX_MIN_IO), 16);
8297403Sobrien
83117397Skan		wr = alloc_wrqe(wr_len, &sc->sge.ctrlq[0]);
84117397Skan		if (wr == NULL)
85117397Skan			return (0);
86117397Skan		ulpmc = wrtod(wr);
87117397Skan
8897403Sobrien		memset(ulpmc, 0, wr_len);
89169691Skan		INIT_ULPTX_WR(ulpmc, wr_len, 0, 0);
90169691Skan
91169691Skan		if (i == (num_wqe-1)) {
92117397Skan			ulpmc->wr.wr_hi = cpu_to_be32(V_FW_WR_OP(FW_ULPTX_WR) |
93132720Skan						    F_FW_WR_COMPL);
94169691Skan			ulpmc->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
95169691Skan		} else
96169691Skan			ulpmc->wr.wr_hi = cpu_to_be32(V_FW_WR_OP(FW_ULPTX_WR));
97169691Skan		ulpmc->wr.wr_mid = cpu_to_be32(
98169691Skan				       V_FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
99169691Skan
100169691Skan		ulpmc->cmd = cmd;
101169691Skan		ulpmc->dlen = cpu_to_be32(V_ULP_MEMIO_DATA_LEN(
102132720Skan		    DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
103169691Skan		ulpmc->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(ulpmc->wr),
104132720Skan						      16));
105132720Skan		ulpmc->lock_addr = cpu_to_be32(V_ULP_MEMIO_ADDR(addr + i * 3));
106132720Skan
107169691Skan		ulpsc = (struct ulptx_idata *)(ulpmc + 1);
108132720Skan		ulpsc->cmd_more = cpu_to_be32(V_ULPTX_CMD(ULP_TX_SC_IMM));
109132720Skan		ulpsc->len = cpu_to_be32(roundup(copy_len, T4_ULPTX_MIN_IO));
110132720Skan
111169691Skan		to_dp = (u8 *)(ulpsc + 1);
112117397Skan		from_dp = (u8 *)data + i * C4IW_MAX_INLINE_SIZE;
113169691Skan		if (data)
114117397Skan			memcpy(to_dp, from_dp, copy_len);
115132720Skan		else
116132720Skan			memset(to_dp, 0, copy_len);
117132720Skan		if (copy_len % T4_ULPTX_MIN_IO)
118132720Skan			memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO -
119132720Skan			       (copy_len % T4_ULPTX_MIN_IO));
120117397Skan		t4_wrq_tx(sc, wr);
121132720Skan		len -= C4IW_MAX_INLINE_SIZE;
122132720Skan	}
123132720Skan
124132720Skan	ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, NULL, __func__);
125132720Skan	return ret;
126132720Skan}
127169691Skan
128169691Skan/*
129169691Skan * Build and write a TPT entry.
130169691Skan * IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size,
131169691Skan *     pbl_size and pbl_addr
132132720Skan * OUT: stag index
133132720Skan */
134132720Skanstatic int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
135132720Skan			   u32 *stag, u8 stag_state, u32 pdid,
136132720Skan			   enum fw_ri_stag_type type, enum fw_ri_mem_perms perm,
137132720Skan			   int bind_enabled, u32 zbva, u64 to,
138169691Skan			   u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr)
139169691Skan{
140169691Skan	int err;
141169691Skan	struct fw_ri_tpte tpt;
142132720Skan	u32 stag_idx;
143132720Skan	static atomic_t key;
144132720Skan
145132720Skan	if (c4iw_fatal_error(rdev))
146132720Skan		return -EIO;
147132720Skan
148132720Skan	stag_state = stag_state > 0;
149132720Skan	stag_idx = (*stag) >> 8;
150132720Skan
151132720Skan	if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
152132720Skan		stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
153132720Skan		if (!stag_idx) {
154132720Skan			mutex_lock(&rdev->stats.lock);
155236829Spfg			rdev->stats.stag.fail++;
156132720Skan			mutex_unlock(&rdev->stats.lock);
157132720Skan			return -ENOMEM;
158132720Skan		}
159132720Skan		mutex_lock(&rdev->stats.lock);
160132720Skan		rdev->stats.stag.cur += 32;
161132720Skan		if (rdev->stats.stag.cur > rdev->stats.stag.max)
162132720Skan			rdev->stats.stag.max = rdev->stats.stag.cur;
163132720Skan		mutex_unlock(&rdev->stats.lock);
164117397Skan		*stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff);
165132720Skan	}
166132720Skan	CTR5(KTR_IW_CXGBE,
167132720Skan	    "%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x",
168132720Skan	    __func__, stag_state, type, pdid, stag_idx);
169132720Skan
170132720Skan	/* write TPT entry */
171132720Skan	if (reset_tpt_entry)
172132720Skan		memset(&tpt, 0, sizeof(tpt));
173132720Skan	else {
174117397Skan		tpt.valid_to_pdid = cpu_to_be32(F_FW_RI_TPTE_VALID |
175132720Skan			V_FW_RI_TPTE_STAGKEY((*stag & M_FW_RI_TPTE_STAGKEY)) |
176132720Skan			V_FW_RI_TPTE_STAGSTATE(stag_state) |
177132720Skan			V_FW_RI_TPTE_STAGTYPE(type) | V_FW_RI_TPTE_PDID(pdid));
178132720Skan		tpt.locread_to_qpid = cpu_to_be32(V_FW_RI_TPTE_PERM(perm) |
179132720Skan			(bind_enabled ? F_FW_RI_TPTE_MWBINDEN : 0) |
180132720Skan			V_FW_RI_TPTE_ADDRTYPE((zbva ? FW_RI_ZERO_BASED_TO :
181132720Skan						      FW_RI_VA_BASED_TO))|
182132720Skan			V_FW_RI_TPTE_PS(page_size));
183132720Skan		tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
184132720Skan			V_FW_RI_TPTE_PBLADDR(PBL_OFF(rdev, pbl_addr)>>3));
185132720Skan		tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
186132720Skan		tpt.va_hi = cpu_to_be32((u32)(to >> 32));
187236829Spfg		tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
188265090Smarius		tpt.dca_mwbcnt_pstag = cpu_to_be32(0);
189132720Skan		tpt.len_hi = cpu_to_be32((u32)(len >> 32));
190132720Skan	}
191132720Skan	err = write_adapter_mem(rdev, stag_idx +
192132720Skan				(rdev->adap->vres.stag.start >> 5),
193132720Skan				sizeof(tpt), &tpt);
194132720Skan
195132720Skan	if (reset_tpt_entry) {
196132720Skan		c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
197132720Skan		mutex_lock(&rdev->stats.lock);
198132720Skan		rdev->stats.stag.cur -= 32;
199132720Skan		mutex_unlock(&rdev->stats.lock);
200132720Skan	}
201132720Skan	return err;
202132720Skan}
203132720Skan
204132720Skanstatic int write_pbl(struct c4iw_rdev *rdev, __be64 *pbl,
205117397Skan		     u32 pbl_addr, u32 pbl_size)
206169691Skan{
207132720Skan	int err;
208132720Skan
209132720Skan	CTR4(KTR_IW_CXGBE, "%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d",
210132720Skan	     __func__, pbl_addr, rdev->adap->vres.pbl.start, pbl_size);
211132720Skan
212132720Skan	err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl);
213132720Skan	return err;
214132720Skan}
215132720Skan
216132720Skanstatic int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size,
217132720Skan		     u32 pbl_addr)
218132720Skan{
219132720Skan	return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0,
220132720Skan			       pbl_size, pbl_addr);
221132720Skan}
222132720Skan
223132720Skanstatic int allocate_window(struct c4iw_rdev *rdev, u32 * stag, u32 pdid)
224132720Skan{
225132720Skan	*stag = T4_STAG_UNSET;
226132720Skan	return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_MW, 0, 0, 0,
227132720Skan			       0UL, 0, 0, 0, 0);
228132720Skan}
229132720Skan
230132720Skanstatic int deallocate_window(struct c4iw_rdev *rdev, u32 stag)
231132720Skan{
232132720Skan	return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 0,
233132720Skan			       0);
234132720Skan}
235132720Skan
236132720Skanstatic int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
237132720Skan			 u32 pbl_size, u32 pbl_addr)
238132720Skan{
239132720Skan	*stag = T4_STAG_UNSET;
240132720Skan	return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0,
241132720Skan			       0UL, 0, 0, pbl_size, pbl_addr);
242132720Skan}
243132720Skan
244132720Skanstatic int finish_mem_reg(struct c4iw_mr *mhp, u32 stag)
245132720Skan{
246132720Skan	u32 mmid;
247132720Skan
248132720Skan	mhp->attr.state = 1;
249132720Skan	mhp->attr.stag = stag;
250132720Skan	mmid = stag >> 8;
251132720Skan	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
252132720Skan	CTR3(KTR_IW_CXGBE, "%s mmid 0x%x mhp %p", __func__, mmid, mhp);
253132720Skan	return insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid);
254132720Skan}
255132720Skan
256132720Skanstatic int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
257132720Skan		      struct c4iw_mr *mhp, int shift)
258132720Skan{
259132720Skan	u32 stag = T4_STAG_UNSET;
260132720Skan	int ret;
261132720Skan
262132720Skan	ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, mhp->attr.pdid,
263132720Skan			      FW_RI_STAG_NSMR, mhp->attr.len ? mhp->attr.perms : 0,
264132720Skan			      mhp->attr.mw_bind_enable, mhp->attr.zbva,
265132720Skan			      mhp->attr.va_fbo, mhp->attr.len ? mhp->attr.len : -1, shift - 12,
266132720Skan			      mhp->attr.pbl_size, mhp->attr.pbl_addr);
267132720Skan	if (ret)
268132720Skan		return ret;
269132720Skan
270132720Skan	ret = finish_mem_reg(mhp, stag);
271132720Skan	if (ret)
272132720Skan		dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
273132720Skan		       mhp->attr.pbl_addr);
274132720Skan	return ret;
275132720Skan}
276132720Skan
277132720Skanstatic int alloc_pbl(struct c4iw_mr *mhp, int npages)
278132720Skan{
279132720Skan	mhp->attr.pbl_addr = c4iw_pblpool_alloc(&mhp->rhp->rdev,
280132720Skan						    npages << 3);
281132720Skan
282132720Skan	if (!mhp->attr.pbl_addr)
283132720Skan		return -ENOMEM;
284132720Skan
285132720Skan	mhp->attr.pbl_size = npages;
286132720Skan
287132720Skan	return 0;
288132720Skan}
289132720Skan
290132720Skanstruct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
291132720Skan{
292132720Skan	struct c4iw_dev *rhp;
293132720Skan	struct c4iw_pd *php;
294132720Skan	struct c4iw_mr *mhp;
295132720Skan	int ret;
296132720Skan	u32 stag = T4_STAG_UNSET;
297132720Skan
298132720Skan	CTR2(KTR_IW_CXGBE, "%s ib_pd %p", __func__, pd);
299132720Skan	php = to_c4iw_pd(pd);
300132720Skan	rhp = php->rhp;
301132720Skan
302132720Skan	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
303132720Skan	if (!mhp)
304132720Skan		return ERR_PTR(-ENOMEM);
305132720Skan
306132720Skan	mhp->rhp = rhp;
307132720Skan	mhp->attr.pdid = php->pdid;
308132720Skan	mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
309132720Skan	mhp->attr.mw_bind_enable = (acc&IB_ACCESS_MW_BIND) == IB_ACCESS_MW_BIND;
310132720Skan	mhp->attr.zbva = 0;
311132720Skan	mhp->attr.va_fbo = 0;
312132720Skan	mhp->attr.page_size = 0;
313132720Skan	mhp->attr.len = ~0ULL;
314132720Skan	mhp->attr.pbl_size = 0;
315132720Skan
316132720Skan	ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
317132720Skan			      FW_RI_STAG_NSMR, mhp->attr.perms,
318132720Skan			      mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0);
319132720Skan	if (ret)
320132720Skan		goto err1;
321132720Skan
322132720Skan	ret = finish_mem_reg(mhp, stag);
323132720Skan	if (ret)
324132720Skan		goto err2;
325132720Skan	return &mhp->ibmr;
326132720Skanerr2:
327132720Skan	dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
328132720Skan		  mhp->attr.pbl_addr);
329132720Skanerr1:
330132720Skan	kfree(mhp);
331132720Skan	return ERR_PTR(ret);
332132720Skan}
333132720Skan
334132720Skanstruct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
335132720Skan		u64 virt, int acc, struct ib_udata *udata)
336132720Skan{
337132720Skan	__be64 *pages;
338132720Skan	int shift, n, len;
339132720Skan	int i, k, entry;
340169691Skan	int err = 0;
341132720Skan	struct scatterlist *sg;
342132720Skan	struct c4iw_dev *rhp;
343132720Skan	struct c4iw_pd *php;
344132720Skan	struct c4iw_mr *mhp;
345132720Skan
346132720Skan	CTR2(KTR_IW_CXGBE, "%s ib_pd %p", __func__, pd);
347132720Skan
348132720Skan	if (length == ~0ULL)
349132720Skan		return ERR_PTR(-EINVAL);
350132720Skan
351132720Skan	if ((length + start) < start)
352132720Skan		return ERR_PTR(-EINVAL);
353132720Skan
354132720Skan	php = to_c4iw_pd(pd);
355132720Skan	rhp = php->rhp;
356132720Skan
357132720Skan	if (mr_exceeds_hw_limits(rhp, length))
358132720Skan		return ERR_PTR(-EINVAL);
359132720Skan
360132720Skan	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
361132720Skan	if (!mhp)
362132720Skan		return ERR_PTR(-ENOMEM);
363132720Skan
364169691Skan	mhp->rhp = rhp;
365132720Skan
366132720Skan	mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
367132720Skan	if (IS_ERR(mhp->umem)) {
368132720Skan		err = PTR_ERR(mhp->umem);
369132720Skan		kfree(mhp);
370132720Skan		return ERR_PTR(err);
371132720Skan	}
372132720Skan
373132720Skan	shift = ffs(mhp->umem->page_size) - 1;
374132720Skan
375132720Skan	n = mhp->umem->nmap;
376132720Skan	err = alloc_pbl(mhp, n);
377169691Skan	if (err)
378132720Skan		goto err;
379132720Skan
380132720Skan	pages = (__be64 *) __get_free_page(GFP_KERNEL);
381132720Skan	if (!pages) {
382132720Skan		err = -ENOMEM;
383132720Skan		goto err_pbl;
384132720Skan	}
385132720Skan
386132720Skan	i = n = 0;
387132720Skan	for_each_sg(mhp->umem->sg_head.sgl, sg, mhp->umem->nmap, entry) {
388132720Skan		len = sg_dma_len(sg) >> shift;
389117397Skan		for (k = 0; k < len; ++k) {
390132720Skan			pages[i++] = cpu_to_be64(sg_dma_address(sg) +
391132720Skan					mhp->umem->page_size * k);
392132720Skan			if (i == PAGE_SIZE / sizeof *pages) {
393132720Skan				err = write_pbl(&mhp->rhp->rdev,
394132720Skan						pages,
395132720Skan						mhp->attr.pbl_addr + (n << 3), i);
396132720Skan				if (err)
397132720Skan					goto pbl_done;
398132720Skan				n += i;
399132720Skan				i = 0;
400132720Skan
401132720Skan			}
402132720Skan		}
403132720Skan	}
404132720Skan
405132720Skan	if (i)
406132720Skan		err = write_pbl(&mhp->rhp->rdev, pages,
407132720Skan				     mhp->attr.pbl_addr + (n << 3), i);
408132720Skan
409132720Skanpbl_done:
410132720Skan	free_page((unsigned long) pages);
411132720Skan	if (err)
412132720Skan		goto err_pbl;
413132720Skan
414132720Skan	mhp->attr.pdid = php->pdid;
415132720Skan	mhp->attr.zbva = 0;
416132720Skan	mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
417132720Skan	mhp->attr.va_fbo = virt;
418132720Skan	mhp->attr.page_size = shift - 12;
419132720Skan	mhp->attr.len = length;
420132720Skan
421132720Skan	err = register_mem(rhp, php, mhp, shift);
422132720Skan	if (err)
423132720Skan		goto err_pbl;
424132720Skan
425132720Skan	return &mhp->ibmr;
426132720Skan
427132720Skanerr_pbl:
428132720Skan	c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
429132720Skan			      mhp->attr.pbl_size << 3);
430132720Skan
431132720Skanerr:
432132720Skan	ib_umem_release(mhp->umem);
433132720Skan	kfree(mhp);
434132720Skan	return ERR_PTR(err);
435132720Skan}
436132720Skan
437132720Skanstruct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
438132720Skan	struct ib_udata *udata)
439132720Skan{
440132720Skan	struct c4iw_dev *rhp;
441132720Skan	struct c4iw_pd *php;
442132720Skan	struct c4iw_mw *mhp;
443132720Skan	u32 mmid;
444132720Skan	u32 stag = 0;
445132720Skan	int ret;
446132720Skan
447132720Skan	if (type != IB_MW_TYPE_1)
448132720Skan		return ERR_PTR(-EINVAL);
449132720Skan
450132720Skan	php = to_c4iw_pd(pd);
451132720Skan	rhp = php->rhp;
452132720Skan	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
453132720Skan	if (!mhp)
454132720Skan		return ERR_PTR(-ENOMEM);
455132720Skan	ret = allocate_window(&rhp->rdev, &stag, php->pdid);
456132720Skan	if (ret) {
457132720Skan		kfree(mhp);
458132720Skan		return ERR_PTR(ret);
459132720Skan	}
460132720Skan	mhp->rhp = rhp;
461132720Skan	mhp->attr.pdid = php->pdid;
462132720Skan	mhp->attr.type = FW_RI_STAG_MW;
463132720Skan	mhp->attr.stag = stag;
464132720Skan	mmid = (stag) >> 8;
465132720Skan	mhp->ibmw.rkey = stag;
466132720Skan	if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
467132720Skan		deallocate_window(&rhp->rdev, mhp->attr.stag);
468132720Skan		kfree(mhp);
469132720Skan		return ERR_PTR(-ENOMEM);
470132720Skan	}
471132720Skan	CTR4(KTR_IW_CXGBE, "%s mmid 0x%x mhp %p stag 0x%x", __func__, mmid, mhp,
472132720Skan	    stag);
473132720Skan	return &(mhp->ibmw);
474132720Skan}
475132720Skan
476132720Skanint c4iw_dealloc_mw(struct ib_mw *mw)
477132720Skan{
478132720Skan	struct c4iw_dev *rhp;
479132720Skan	struct c4iw_mw *mhp;
480132720Skan	u32 mmid;
481132720Skan
482132720Skan	mhp = to_c4iw_mw(mw);
483132720Skan	rhp = mhp->rhp;
484132720Skan	mmid = (mw->rkey) >> 8;
485132720Skan	remove_handle(rhp, &rhp->mmidr, mmid);
486132720Skan	deallocate_window(&rhp->rdev, mhp->attr.stag);
487132720Skan	kfree(mhp);
488132720Skan	CTR4(KTR_IW_CXGBE, "%s ib_mw %p mmid 0x%x ptr %p", __func__, mw, mmid,
489132720Skan	    mhp);
490132720Skan	return 0;
491132720Skan}
492132720Skan
493132720Skanstruct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
494132720Skan			    enum ib_mr_type mr_type,
495132720Skan			    u32 max_num_sg)
496132720Skan{
497132720Skan	struct c4iw_dev *rhp;
498132720Skan	struct c4iw_pd *php;
499132720Skan	struct c4iw_mr *mhp;
500132720Skan	u32 mmid;
501132720Skan	u32 stag = 0;
502132720Skan	int ret = 0;
503132720Skan	int length = roundup(max_num_sg * sizeof(u64), 32);
504132720Skan
505132720Skan	php = to_c4iw_pd(pd);
506132720Skan	rhp = php->rhp;
507132720Skan
508132720Skan	if (mr_type != IB_MR_TYPE_MEM_REG ||
509132720Skan	    max_num_sg > t4_max_fr_depth(
510132720Skan		    rhp->rdev.adap->params.ulptx_memwrite_dsgl && use_dsgl))
511132720Skan		return ERR_PTR(-EINVAL);
512132720Skan
513132720Skan	mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
514132720Skan	if (!mhp) {
515132720Skan		ret = -ENOMEM;
516132720Skan		goto err;
517132720Skan	}
518132720Skan
519132720Skan	mhp->mpl = dma_alloc_coherent(rhp->ibdev.dma_device,
520132720Skan				      length, &mhp->mpl_addr, GFP_KERNEL);
521132720Skan	if (!mhp->mpl) {
522132720Skan		ret = -ENOMEM;
523132720Skan		goto err_mpl;
524132720Skan	}
525132720Skan	mhp->max_mpl_len = length;
526132720Skan
527132720Skan	mhp->rhp = rhp;
528132720Skan	ret = alloc_pbl(mhp, max_num_sg);
529132720Skan	if (ret)
530132720Skan		goto err1;
531132720Skan	mhp->attr.pbl_size = max_num_sg;
532132720Skan	ret = allocate_stag(&rhp->rdev, &stag, php->pdid,
533132720Skan			    mhp->attr.pbl_size, mhp->attr.pbl_addr);
534132720Skan	if (ret)
535132720Skan		goto err2;
536132720Skan	mhp->attr.pdid = php->pdid;
537132720Skan	mhp->attr.type = FW_RI_STAG_NSMR;
538132720Skan	mhp->attr.stag = stag;
539132720Skan	mhp->attr.state = 0;
540132720Skan	mmid = (stag) >> 8;
541132720Skan	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
542132720Skan	if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
543132720Skan		ret = -ENOMEM;
544132720Skan		goto err3;
545132720Skan	}
546132720Skan
547132720Skan	PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
548132720Skan	return &(mhp->ibmr);
549132720Skanerr3:
550132720Skan	dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
551132720Skan		       mhp->attr.pbl_addr);
552132720Skanerr2:
553132720Skan	c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
554132720Skan			      mhp->attr.pbl_size << 3);
555132720Skanerr1:
556132720Skan	dma_free_coherent(rhp->ibdev.dma_device,
557132720Skan			  mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
558132720Skanerr_mpl:
559132720Skan	kfree(mhp);
560132720Skanerr:
561132720Skan	return ERR_PTR(ret);
562132720Skan}
563132720Skanstatic int c4iw_set_page(struct ib_mr *ibmr, u64 addr)
564132720Skan{
565132720Skan	struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
566132720Skan
567132720Skan	if (unlikely(mhp->mpl_len == mhp->max_mpl_len))
568169691Skan		return -ENOMEM;
569132720Skan
570132720Skan	mhp->mpl[mhp->mpl_len++] = addr;
571132720Skan
572132720Skan	return 0;
573132720Skan}
574132720Skan
575132720Skanint c4iw_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
576132720Skan		   int sg_nents, unsigned int *sg_offset)
577132720Skan{
578132720Skan	struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
579132720Skan
580132720Skan	mhp->mpl_len = 0;
581132720Skan
582132720Skan	return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, c4iw_set_page);
583132720Skan}
584132720Skan
585169691Skan
586132720Skanint c4iw_dereg_mr(struct ib_mr *ib_mr)
587132720Skan{
588132720Skan	struct c4iw_dev *rhp;
589132720Skan	struct c4iw_mr *mhp;
590132720Skan	u32 mmid;
591169691Skan
592169691Skan	CTR2(KTR_IW_CXGBE, "%s ib_mr %p", __func__, ib_mr);
593132720Skan
594132720Skan	mhp = to_c4iw_mr(ib_mr);
595132720Skan	rhp = mhp->rhp;
596169691Skan	mmid = mhp->attr.stag >> 8;
597169691Skan	remove_handle(rhp, &rhp->mmidr, mmid);
598117397Skan	dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
599132720Skan		       mhp->attr.pbl_addr);
60097403Sobrien	if (mhp->attr.pbl_size)
601117397Skan		c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
602117397Skan				  mhp->attr.pbl_size << 3);
603117397Skan	if (mhp->kva)
604117397Skan		kfree((void *) (unsigned long) mhp->kva);
60597403Sobrien	if (mhp->umem)
606117397Skan		ib_umem_release(mhp->umem);
607117397Skan	CTR3(KTR_IW_CXGBE, "%s mmid 0x%x ptr %p", __func__, mmid, mhp);
608117397Skan	kfree(mhp);
60997403Sobrien	return 0;
610117397Skan}
611117397Skan
612169691Skanvoid c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
613169691Skan{
614132720Skan	struct c4iw_mr *mhp;
615132720Skan	unsigned long flags;
61697403Sobrien
617117397Skan	spin_lock_irqsave(&rhp->lock, flags);
618117397Skan	mhp = get_mhp(rhp, rkey >> 8);
619117397Skan	if (mhp)
620132720Skan		mhp->attr.state = 0;
62197403Sobrien	spin_unlock_irqrestore(&rhp->lock, flags);
622117397Skan}
623117397Skan#endif
62497403Sobrien