1256694Snp/*
2256694Snp * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved.
3256694Snp *
4256694Snp * This software is available to you under a choice of one of two
5256694Snp * licenses.  You may choose to be licensed under the terms of the GNU
6256694Snp * General Public License (GPL) Version 2, available from the file
7256694Snp * COPYING in the main directory of this source tree, or the
8256694Snp * OpenIB.org BSD license below:
9256694Snp *
10256694Snp *     Redistribution and use in source and binary forms, with or
11256694Snp *     without modification, are permitted provided that the following
12256694Snp *     conditions are met:
13256694Snp *
14256694Snp *      - Redistributions of source code must retain the above
15256694Snp *	  copyright notice, this list of conditions and the following
16256694Snp *	  disclaimer.
17256694Snp *
18256694Snp *      - Redistributions in binary form must reproduce the above
19256694Snp *	  copyright notice, this list of conditions and the following
20256694Snp *	  disclaimer in the documentation and/or other materials
21256694Snp *	  provided with the distribution.
22256694Snp *
23256694Snp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24256694Snp * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25256694Snp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26256694Snp * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27256694Snp * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28256694Snp * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29256694Snp * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30256694Snp * SOFTWARE.
31256694Snp */
32256694Snp#include <sys/cdefs.h>
33256694Snp__FBSDID("$FreeBSD: releng/10.3/sys/dev/cxgbe/iw_cxgbe/device.c 284089 2015-06-06 18:00:36Z np $");
34256694Snp
35256694Snp#include "opt_inet.h"
36256694Snp
37256694Snp#include <sys/ktr.h>
38256694Snp
39256694Snp#include <linux/module.h>
40256694Snp#include <linux/moduleparam.h>
41256694Snp
42256694Snp#include <rdma/ib_verbs.h>
43256694Snp#include <linux/idr.h>
44256694Snp
45256694Snp#ifdef TCP_OFFLOAD
46256694Snp#include "iw_cxgbe.h"
47256694Snp
48256694Snpint spg_creds = 2; /* Default status page size is 2 credits = 128B */
49256694Snp
50256694Snpvoid
51256694Snpc4iw_release_dev_ucontext(struct c4iw_rdev *rdev,
52256694Snp    struct c4iw_dev_ucontext *uctx)
53256694Snp{
54256694Snp	struct list_head *pos, *nxt;
55256694Snp	struct c4iw_qid_list *entry;
56256694Snp
57256694Snp	mutex_lock(&uctx->lock);
58256694Snp	list_for_each_safe(pos, nxt, &uctx->qpids) {
59256694Snp		entry = list_entry(pos, struct c4iw_qid_list, entry);
60256694Snp		list_del_init(&entry->entry);
61256694Snp		if (!(entry->qid & rdev->qpmask)) {
62256694Snp			c4iw_put_resource(&rdev->resource.qid_table,
63256694Snp					  entry->qid);
64256694Snp			mutex_lock(&rdev->stats.lock);
65256694Snp			rdev->stats.qid.cur -= rdev->qpmask + 1;
66256694Snp			mutex_unlock(&rdev->stats.lock);
67256694Snp		}
68256694Snp		kfree(entry);
69256694Snp	}
70256694Snp
71256694Snp	list_for_each_safe(pos, nxt, &uctx->qpids) {
72256694Snp		entry = list_entry(pos, struct c4iw_qid_list, entry);
73256694Snp		list_del_init(&entry->entry);
74256694Snp		kfree(entry);
75256694Snp	}
76256694Snp	mutex_unlock(&uctx->lock);
77256694Snp}
78256694Snp
79256694Snpvoid
80256694Snpc4iw_init_dev_ucontext(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
81256694Snp{
82256694Snp
83256694Snp	INIT_LIST_HEAD(&uctx->qpids);
84256694Snp	INIT_LIST_HEAD(&uctx->cqids);
85256694Snp	mutex_init(&uctx->lock);
86256694Snp}
87256694Snp
88256694Snpstatic int
89256694Snpc4iw_rdev_open(struct c4iw_rdev *rdev)
90256694Snp{
91256694Snp	struct adapter *sc = rdev->adap;
92256694Snp	int rc;
93256694Snp
94256694Snp	c4iw_init_dev_ucontext(rdev, &rdev->uctx);
95256694Snp
96256694Snp	/* Save the status page size set by if_cxgbe */
97256694Snp	spg_creds = (t4_read_reg(sc, A_SGE_CONTROL) & F_EGRSTATUSPAGESIZE) ?
98256694Snp	    2 : 1;
99256694Snp
100256694Snp	/* XXX: we can probably make this work */
101256694Snp	if (sc->sge.eq_s_qpp > PAGE_SHIFT || sc->sge.iq_s_qpp > PAGE_SHIFT) {
102256694Snp		device_printf(sc->dev,
103256694Snp		    "doorbell density too high (eq %d, iq %d, pg %d).\n",
104256694Snp		    sc->sge.eq_s_qpp, sc->sge.eq_s_qpp, PAGE_SHIFT);
105256694Snp		rc = -EINVAL;
106256694Snp		goto err1;
107256694Snp	}
108256694Snp
109256694Snp	rdev->qpshift = PAGE_SHIFT - sc->sge.eq_s_qpp;
110256694Snp	rdev->qpmask = (1 << sc->sge.eq_s_qpp) - 1;
111256694Snp	rdev->cqshift = PAGE_SHIFT - sc->sge.iq_s_qpp;
112256694Snp	rdev->cqmask = (1 << sc->sge.iq_s_qpp) - 1;
113256694Snp
114256694Snp	if (c4iw_num_stags(rdev) == 0) {
115256694Snp		rc = -EINVAL;
116256694Snp		goto err1;
117256694Snp	}
118256694Snp
119256694Snp	rdev->stats.pd.total = T4_MAX_NUM_PD;
120256694Snp	rdev->stats.stag.total = sc->vres.stag.size;
121256694Snp	rdev->stats.pbl.total = sc->vres.pbl.size;
122256694Snp	rdev->stats.rqt.total = sc->vres.rq.size;
123256694Snp	rdev->stats.qid.total = sc->vres.qp.size;
124256694Snp
125256694Snp	rc = c4iw_init_resource(rdev, c4iw_num_stags(rdev), T4_MAX_NUM_PD);
126256694Snp	if (rc) {
127256694Snp		device_printf(sc->dev, "error %d initializing resources\n", rc);
128256694Snp		goto err1;
129256694Snp	}
130256694Snp	rc = c4iw_pblpool_create(rdev);
131256694Snp	if (rc) {
132256694Snp		device_printf(sc->dev, "error %d initializing pbl pool\n", rc);
133256694Snp		goto err2;
134256694Snp	}
135256694Snp	rc = c4iw_rqtpool_create(rdev);
136256694Snp	if (rc) {
137256694Snp		device_printf(sc->dev, "error %d initializing rqt pool\n", rc);
138256694Snp		goto err3;
139256694Snp	}
140256694Snp
141256694Snp	return (0);
142256694Snperr3:
143256694Snp	c4iw_pblpool_destroy(rdev);
144256694Snperr2:
145256694Snp	c4iw_destroy_resource(&rdev->resource);
146256694Snperr1:
147256694Snp	return (rc);
148256694Snp}
149256694Snp
150256694Snpstatic void c4iw_rdev_close(struct c4iw_rdev *rdev)
151256694Snp{
152256694Snp	c4iw_pblpool_destroy(rdev);
153256694Snp	c4iw_rqtpool_destroy(rdev);
154256694Snp	c4iw_destroy_resource(&rdev->resource);
155256694Snp}
156256694Snp
157256694Snpstatic void
158256694Snpc4iw_dealloc(struct c4iw_dev *iwsc)
159256694Snp{
160256694Snp
161256694Snp	c4iw_rdev_close(&iwsc->rdev);
162256694Snp	idr_destroy(&iwsc->cqidr);
163256694Snp	idr_destroy(&iwsc->qpidr);
164256694Snp	idr_destroy(&iwsc->mmidr);
165256694Snp	ib_dealloc_device(&iwsc->ibdev);
166256694Snp}
167256694Snp
168256694Snpstatic struct c4iw_dev *
169256694Snpc4iw_alloc(struct adapter *sc)
170256694Snp{
171256694Snp	struct c4iw_dev *iwsc;
172256694Snp	int rc;
173256694Snp
174256694Snp	iwsc = (struct c4iw_dev *)ib_alloc_device(sizeof(*iwsc));
175256694Snp	if (iwsc == NULL) {
176256694Snp		device_printf(sc->dev, "Cannot allocate ib device.\n");
177256694Snp		return (ERR_PTR(-ENOMEM));
178256694Snp	}
179256694Snp	iwsc->rdev.adap = sc;
180256694Snp
181256694Snp	rc = c4iw_rdev_open(&iwsc->rdev);
182256694Snp	if (rc != 0) {
183256694Snp		device_printf(sc->dev, "Unable to open CXIO rdev (%d)\n", rc);
184256694Snp		ib_dealloc_device(&iwsc->ibdev);
185256694Snp		return (ERR_PTR(rc));
186256694Snp	}
187256694Snp
188256694Snp	idr_init(&iwsc->cqidr);
189256694Snp	idr_init(&iwsc->qpidr);
190256694Snp	idr_init(&iwsc->mmidr);
191256694Snp	spin_lock_init(&iwsc->lock);
192256694Snp	mutex_init(&iwsc->rdev.stats.lock);
193256694Snp
194256694Snp	return (iwsc);
195256694Snp}
196256694Snp
197256694Snpstatic int c4iw_mod_load(void);
198256694Snpstatic int c4iw_mod_unload(void);
199256694Snpstatic int c4iw_activate(struct adapter *);
200256694Snpstatic int c4iw_deactivate(struct adapter *);
201256694Snp
202256694Snpstatic struct uld_info c4iw_uld_info = {
203256694Snp	.uld_id = ULD_IWARP,
204256694Snp	.activate = c4iw_activate,
205256694Snp	.deactivate = c4iw_deactivate,
206256694Snp};
207256694Snp
208256694Snpstatic int
209256694Snpc4iw_activate(struct adapter *sc)
210256694Snp{
211256694Snp	struct c4iw_dev *iwsc;
212256694Snp	int rc;
213256694Snp
214256694Snp	ASSERT_SYNCHRONIZED_OP(sc);
215256694Snp
216284089Snp	if (uld_active(sc, ULD_IWARP)) {
217256694Snp		KASSERT(0, ("%s: RDMA already eanbled on sc %p", __func__, sc));
218256694Snp		return (0);
219256694Snp	}
220256694Snp
221256694Snp	if (sc->rdmacaps == 0) {
222256694Snp		device_printf(sc->dev,
223256694Snp		    "RDMA not supported or RDMA cap is not enabled.\n");
224256694Snp		return (ENOSYS);
225256694Snp	}
226256694Snp
227256694Snp	iwsc = c4iw_alloc(sc);
228256694Snp	if (IS_ERR(iwsc)) {
229256694Snp		rc = -PTR_ERR(iwsc);
230256694Snp		device_printf(sc->dev, "initialization failed: %d\n", rc);
231256694Snp		return (rc);
232256694Snp	}
233256694Snp
234256694Snp	sc->iwarp_softc = iwsc;
235256694Snp	c4iw_cm_init_cpl(sc);
236256694Snp
237256694Snp	rc = -c4iw_register_device(iwsc);
238256694Snp	if (rc) {
239256694Snp		device_printf(sc->dev, "RDMA registration failed: %d\n", rc);
240256694Snp		c4iw_dealloc(iwsc);
241256694Snp		sc->iwarp_softc = NULL;
242256694Snp	}
243256694Snp
244256694Snp	return (rc);
245256694Snp}
246256694Snp
247256694Snpstatic int
248256694Snpc4iw_deactivate(struct adapter *sc)
249256694Snp{
250256694Snp	struct c4iw_dev *iwsc = sc->iwarp_softc;
251256694Snp
252256694Snp	ASSERT_SYNCHRONIZED_OP(sc);
253256694Snp
254256694Snp	c4iw_unregister_device(iwsc);
255256694Snp	c4iw_dealloc(iwsc);
256256694Snp	sc->iwarp_softc = NULL;
257256694Snp
258256694Snp	return (0);
259256694Snp}
260256694Snp
261256694Snpstatic void
262256694Snpc4iw_activate_all(struct adapter *sc, void *arg __unused)
263256694Snp{
264256694Snp
265256694Snp	if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4iwact") != 0)
266256694Snp		return;
267256694Snp
268284089Snp	/* Activate iWARP if any port on this adapter has IFCAP_TOE enabled. */
269284089Snp	if (sc->offload_map && !uld_active(sc, ULD_IWARP))
270284089Snp		(void) t4_activate_uld(sc, ULD_IWARP);
271256694Snp
272256694Snp	end_synchronized_op(sc, 0);
273256694Snp}
274256694Snp
275256694Snpstatic void
276256694Snpc4iw_deactivate_all(struct adapter *sc, void *arg __unused)
277256694Snp{
278256694Snp
279256694Snp	if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4iwdea") != 0)
280256694Snp		return;
281256694Snp
282284089Snp	if (uld_active(sc, ULD_IWARP))
283284089Snp	    (void) t4_deactivate_uld(sc, ULD_IWARP);
284256694Snp
285256694Snp	end_synchronized_op(sc, 0);
286256694Snp}
287256694Snp
288256694Snpstatic int
289256694Snpc4iw_mod_load(void)
290256694Snp{
291256694Snp	int rc;
292256694Snp
293256694Snp	rc = -c4iw_cm_init();
294256694Snp	if (rc != 0)
295256694Snp		return (rc);
296256694Snp
297256694Snp	rc = t4_register_uld(&c4iw_uld_info);
298256694Snp	if (rc != 0) {
299256694Snp		c4iw_cm_term();
300256694Snp		return (rc);
301256694Snp	}
302256694Snp
303256694Snp	t4_iterate(c4iw_activate_all, NULL);
304256694Snp
305256694Snp	return (rc);
306256694Snp}
307256694Snp
308256694Snpstatic int
309256694Snpc4iw_mod_unload(void)
310256694Snp{
311256694Snp
312256694Snp	t4_iterate(c4iw_deactivate_all, NULL);
313256694Snp
314256694Snp	c4iw_cm_term();
315256694Snp
316256694Snp	if (t4_unregister_uld(&c4iw_uld_info) == EBUSY)
317256694Snp		return (EBUSY);
318256694Snp
319256694Snp	return (0);
320256694Snp}
321256694Snp
322256694Snp#endif
323256694Snp#undef MODULE_VERSION
324256694Snp#include <sys/module.h>
325256694Snp
326256694Snp/*
327256694Snp * t4_tom won't load on kernels without TCP_OFFLOAD and this module's dependency
328256694Snp * on t4_tom ensures that it won't either.  So we don't directly check for
329256694Snp * TCP_OFFLOAD here.
330256694Snp */
331256694Snpstatic int
332256694Snpc4iw_modevent(module_t mod, int cmd, void *arg)
333256694Snp{
334256694Snp	int rc = 0;
335256694Snp
336256694Snp#ifdef TCP_OFFLOAD
337256694Snp	switch (cmd) {
338256694Snp	case MOD_LOAD:
339256694Snp		rc = c4iw_mod_load();
340256694Snp		if (rc == 0)
341256694Snp			printf("iw_cxgbe: Chelsio T4/T5 RDMA driver loaded.\n");
342256694Snp		break;
343256694Snp
344256694Snp	case MOD_UNLOAD:
345256694Snp		rc = c4iw_mod_unload();
346256694Snp		break;
347256694Snp
348256694Snp	default:
349256694Snp		rc = EINVAL;
350256694Snp	}
351256694Snp#else
352256694Snp	printf("t4_tom: compiled without TCP_OFFLOAD support.\n");
353256694Snp	rc = EOPNOTSUPP;
354256694Snp#endif
355256694Snp	return (rc);
356256694Snp}
357256694Snp
358256694Snpstatic moduledata_t c4iw_mod_data = {
359256694Snp	"iw_cxgbe",
360256694Snp	c4iw_modevent,
361256694Snp	0
362256694Snp};
363256694Snp
364256694SnpMODULE_VERSION(iw_cxgbe, 1);
365256819SnpMODULE_DEPEND(iw_cxgbe, t4nex, 1, 1, 1);
366256694SnpMODULE_DEPEND(iw_cxgbe, t4_tom, 1, 1, 1);
367256694SnpMODULE_DEPEND(iw_cxgbe, ibcore, 1, 1, 1);
368256694SnpDECLARE_MODULE(iw_cxgbe, c4iw_mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
369