iw_cxgb_mem.c revision 259065
1/**************************************************************************
2
3Copyright (c) 2007, Chelsio Inc.
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10    this list of conditions and the following disclaimer.
11
12 2. Neither the name of the Chelsio Corporation nor the names of its
13    contributors may be used to endorse or promote products derived from
14    this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26POSSIBILITY OF SUCH DAMAGE.
27
28***************************************************************************/
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: releng/10.0/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_mem.c 237263 2012-06-19 07:34:13Z np $");
31
32#include "opt_inet.h"
33
34#ifdef TCP_OFFLOAD
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/bus.h>
39#include <sys/pciio.h>
40#include <sys/conf.h>
41#include <machine/bus.h>
42#include <machine/resource.h>
43#include <sys/bus_dma.h>
44#include <sys/rman.h>
45#include <sys/ioccom.h>
46#include <sys/mbuf.h>
47#include <sys/mutex.h>
48#include <sys/rwlock.h>
49#include <sys/linker.h>
50#include <sys/firmware.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53#include <sys/smp.h>
54#include <sys/sysctl.h>
55#include <sys/syslog.h>
56#include <sys/queue.h>
57#include <sys/taskqueue.h>
58#include <sys/proc.h>
59#include <sys/queue.h>
60#include <sys/libkern.h>
61
62#include <netinet/in.h>
63
64#include <rdma/ib_verbs.h>
65#include <rdma/ib_umem.h>
66#include <rdma/ib_user_verbs.h>
67#include <linux/idr.h>
68#include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
69
70#include <cxgb_include.h>
71#include <ulp/iw_cxgb/iw_cxgb_wr.h>
72#include <ulp/iw_cxgb/iw_cxgb_hal.h>
73#include <ulp/iw_cxgb/iw_cxgb_provider.h>
74#include <ulp/iw_cxgb/iw_cxgb_cm.h>
75#include <ulp/iw_cxgb/iw_cxgb.h>
76#include <ulp/iw_cxgb/iw_cxgb_resource.h>
77#include <ulp/iw_cxgb/iw_cxgb_user.h>
78
79static int iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag)
80{
81	u32 mmid;
82
83	mhp->attr.state = 1;
84	mhp->attr.stag = stag;
85	mmid = stag >> 8;
86	mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
87	CTR3(KTR_IW_CXGB, "%s mmid 0x%x mhp %p", __func__, mmid, mhp);
88	return insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid);
89}
90
91int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
92					struct iwch_mr *mhp,
93					int shift)
94{
95	u32 stag;
96	int ret;
97
98	if (cxio_register_phys_mem(&rhp->rdev,
99				   &stag, mhp->attr.pdid,
100				   mhp->attr.perms,
101				   mhp->attr.zbva,
102				   mhp->attr.va_fbo,
103				   mhp->attr.len,
104				   shift - 12,
105				   mhp->attr.pbl_size, mhp->attr.pbl_addr))
106		return (-ENOMEM);
107
108	ret = iwch_finish_mem_reg(mhp, stag);
109	if (ret)
110		cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
111			mhp->attr.pbl_addr);
112	return ret;
113}
114
115int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
116					struct iwch_mr *mhp,
117					int shift,
118					int npages)
119{
120	u32 stag;
121	int ret;
122
123	/* We could support this... */
124	if (npages > mhp->attr.pbl_size)
125		return (-ENOMEM);
126
127	stag = mhp->attr.stag;
128	if (cxio_reregister_phys_mem(&rhp->rdev,
129				   &stag, mhp->attr.pdid,
130				   mhp->attr.perms,
131				   mhp->attr.zbva,
132				   mhp->attr.va_fbo,
133				   mhp->attr.len,
134				   shift - 12,
135				   mhp->attr.pbl_size, mhp->attr.pbl_addr))
136		return (-ENOMEM);
137
138	ret = iwch_finish_mem_reg(mhp, stag);
139        if (ret)
140                cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
141                        mhp->attr.pbl_addr);
142        return ret;
143}
144
145int iwch_alloc_pbl(struct iwch_mr *mhp, int npages)
146{
147	mhp->attr.pbl_addr = cxio_hal_pblpool_alloc(&mhp->rhp->rdev,
148						    npages << 3);
149
150	if (!mhp->attr.pbl_addr)
151		return -ENOMEM;
152
153	mhp->attr.pbl_size = npages;
154
155	return 0;
156 }
157
158void iwch_free_pbl(struct iwch_mr *mhp)
159{
160	cxio_hal_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
161			      mhp->attr.pbl_size << 3);
162}
163
164int iwch_write_pbl(struct iwch_mr *mhp, __be64 *pages, int npages, int offset)
165{
166	return cxio_write_pbl(&mhp->rhp->rdev, pages,
167			      mhp->attr.pbl_addr + (offset << 3), npages);
168}
169
170int build_phys_page_list(struct ib_phys_buf *buffer_list,
171					int num_phys_buf,
172					u64 *iova_start,
173					u64 *total_size,
174					int *npages,
175					int *shift,
176					__be64 **page_list)
177{
178	u64 mask;
179	int i, j, n;
180
181	mask = 0;
182	*total_size = 0;
183	for (i = 0; i < num_phys_buf; ++i) {
184		if (i != 0 && buffer_list[i].addr & ~PAGE_MASK)
185			return (-EINVAL);
186		if (i != 0 && i != num_phys_buf - 1 &&
187		    (buffer_list[i].size & ~PAGE_MASK))
188			return (-EINVAL);
189		*total_size += buffer_list[i].size;
190		if (i > 0)
191			mask |= buffer_list[i].addr;
192		else
193			mask |= buffer_list[i].addr & PAGE_MASK;
194		if (i != num_phys_buf - 1)
195			mask |= buffer_list[i].addr + buffer_list[i].size;
196		else
197			mask |= (buffer_list[i].addr + buffer_list[i].size +
198				PAGE_SIZE - 1) & PAGE_MASK;
199	}
200
201	if (*total_size > 0xFFFFFFFFULL)
202		return (-ENOMEM);
203
204	/* Find largest page shift we can use to cover buffers */
205	for (*shift = PAGE_SHIFT; *shift < 27; ++(*shift))
206		if ((1ULL << *shift) & mask)
207			break;
208
209	buffer_list[0].size += buffer_list[0].addr & ((1ULL << *shift) - 1);
210	buffer_list[0].addr &= ~0ull << *shift;
211
212	*npages = 0;
213	for (i = 0; i < num_phys_buf; ++i)
214		*npages += (buffer_list[i].size +
215			(1ULL << *shift) - 1) >> *shift;
216
217	if (!*npages)
218		return (-EINVAL);
219
220	*page_list = kmalloc(sizeof(u64) * *npages, M_NOWAIT);
221	if (!*page_list)
222		return (-ENOMEM);
223
224	n = 0;
225	for (i = 0; i < num_phys_buf; ++i)
226		for (j = 0;
227		     j < (buffer_list[i].size + (1ULL << *shift) - 1) >> *shift;
228		     ++j)
229			(*page_list)[n++] = htobe64(buffer_list[i].addr +
230			    ((u64) j << *shift));
231
232	CTR6(KTR_IW_CXGB, "%s va 0x%llx mask 0x%llx shift %d len %lld pbl_size %d",
233	     __FUNCTION__, (unsigned long long) *iova_start,
234	     (unsigned long long) mask, *shift, (unsigned long long) *total_size,
235	     *npages);
236
237	return 0;
238
239}
240#endif
241