1178786Skmacy/**************************************************************************
2178786Skmacy
3178786SkmacyCopyright (c) 2007, Chelsio Inc.
4178786SkmacyAll rights reserved.
5178786Skmacy
6178786SkmacyRedistribution and use in source and binary forms, with or without
7178786Skmacymodification, are permitted provided that the following conditions are met:
8178786Skmacy
9178786Skmacy 1. Redistributions of source code must retain the above copyright notice,
10178786Skmacy    this list of conditions and the following disclaimer.
11178786Skmacy
12178786Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13178786Skmacy    contributors may be used to endorse or promote products derived from
14178786Skmacy    this software without specific prior written permission.
15178786Skmacy
16178786SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17178786SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18178786SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19178786SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20178786SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21178786SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22178786SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23178786SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24178786SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25178786SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26178786SkmacyPOSSIBILITY OF SUCH DAMAGE.
27178786Skmacy
28178786Skmacy***************************************************************************/
29178786Skmacy#include <sys/cdefs.h>
30178786Skmacy__FBSDID("$FreeBSD$");
31178786Skmacy
32237263Snp#include "opt_inet.h"
33237263Snp
34178786Skmacy#include <sys/param.h>
35178786Skmacy#include <sys/systm.h>
36178786Skmacy#include <sys/kernel.h>
37178786Skmacy#include <sys/bus.h>
38178786Skmacy#include <sys/pciio.h>
39178786Skmacy#include <sys/conf.h>
40178786Skmacy#include <machine/bus.h>
41178786Skmacy#include <machine/resource.h>
42178786Skmacy#include <sys/bus_dma.h>
43178786Skmacy#include <sys/rman.h>
44178786Skmacy#include <sys/ioccom.h>
45178786Skmacy#include <sys/mbuf.h>
46178786Skmacy#include <sys/rwlock.h>
47178786Skmacy#include <sys/linker.h>
48178786Skmacy#include <sys/firmware.h>
49178786Skmacy#include <sys/socket.h>
50178786Skmacy#include <sys/sockio.h>
51178786Skmacy#include <sys/smp.h>
52178786Skmacy#include <sys/sysctl.h>
53178786Skmacy#include <sys/queue.h>
54178786Skmacy#include <sys/taskqueue.h>
55178786Skmacy#include <sys/proc.h>
56178786Skmacy#include <sys/eventhandler.h>
57183289Skmacy
58178786Skmacy#include <netinet/in.h>
59237263Snp#include <netinet/toecore.h>
60178786Skmacy
61237263Snp#include <rdma/ib_verbs.h>
62237263Snp#include <linux/idr.h>
63237263Snp#include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
64178786Skmacy
65237263Snp#ifdef TCP_OFFLOAD
66178786Skmacy#include <cxgb_include.h>
67178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_wr.h>
68178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_hal.h>
69178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_provider.h>
70178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_cm.h>
71178786Skmacy#include <ulp/iw_cxgb/iw_cxgb.h>
72178786Skmacy
73237263Snpstatic int iwch_mod_load(void);
74237263Snpstatic int iwch_mod_unload(void);
75237263Snpstatic int iwch_activate(struct adapter *);
76237263Snpstatic int iwch_deactivate(struct adapter *);
77178786Skmacy
78237263Snpstatic struct uld_info iwch_uld_info = {
79237263Snp	.uld_id = ULD_IWARP,
80237263Snp	.activate = iwch_activate,
81237263Snp	.deactivate = iwch_deactivate,
82237263Snp};
83178786Skmacy
84178786Skmacystatic void
85178786Skmacyrnic_init(struct iwch_dev *rnicp)
86178786Skmacy{
87237263Snp
88178786Skmacy	idr_init(&rnicp->cqidr);
89178786Skmacy	idr_init(&rnicp->qpidr);
90178786Skmacy	idr_init(&rnicp->mmidr);
91178786Skmacy	mtx_init(&rnicp->lock, "iwch rnic lock", NULL, MTX_DEF|MTX_DUPOK);
92178786Skmacy
93178786Skmacy	rnicp->attr.vendor_id = 0x168;
94178786Skmacy	rnicp->attr.vendor_part_id = 7;
95178786Skmacy	rnicp->attr.max_qps = T3_MAX_NUM_QP - 32;
96237263Snp	rnicp->attr.max_wrs = T3_MAX_QP_DEPTH;
97178786Skmacy	rnicp->attr.max_sge_per_wr = T3_MAX_SGE;
98178786Skmacy	rnicp->attr.max_sge_per_rdma_write_wr = T3_MAX_SGE;
99178786Skmacy	rnicp->attr.max_cqs = T3_MAX_NUM_CQ - 1;
100237263Snp	rnicp->attr.max_cqes_per_cq = T3_MAX_CQ_DEPTH;
101178786Skmacy	rnicp->attr.max_mem_regs = cxio_num_stags(&rnicp->rdev);
102178786Skmacy	rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE;
103178786Skmacy	rnicp->attr.max_pds = T3_MAX_NUM_PD - 1;
104237263Snp	rnicp->attr.mem_pgsizes_bitmask = T3_PAGESIZE_MASK;
105237263Snp	rnicp->attr.max_mr_size = T3_MAX_MR_SIZE;
106178786Skmacy	rnicp->attr.can_resize_wq = 0;
107178786Skmacy	rnicp->attr.max_rdma_reads_per_qp = 8;
108178786Skmacy	rnicp->attr.max_rdma_read_resources =
109178786Skmacy	    rnicp->attr.max_rdma_reads_per_qp * rnicp->attr.max_qps;
110178786Skmacy	rnicp->attr.max_rdma_read_qp_depth = 8;	/* IRD */
111178786Skmacy	rnicp->attr.max_rdma_read_depth =
112178786Skmacy	    rnicp->attr.max_rdma_read_qp_depth * rnicp->attr.max_qps;
113178786Skmacy	rnicp->attr.rq_overflow_handled = 0;
114178786Skmacy	rnicp->attr.can_modify_ird = 0;
115178786Skmacy	rnicp->attr.can_modify_ord = 0;
116178786Skmacy	rnicp->attr.max_mem_windows = rnicp->attr.max_mem_regs - 1;
117178786Skmacy	rnicp->attr.stag0_value = 1;
118178786Skmacy	rnicp->attr.zbva_support = 1;
119178786Skmacy	rnicp->attr.local_invalidate_fence = 1;
120178786Skmacy	rnicp->attr.cq_overflow_detection = 1;
121237263Snp
122178786Skmacy	return;
123178786Skmacy}
124178786Skmacy
125178786Skmacystatic void
126237263Snprnic_uninit(struct iwch_dev *rnicp)
127178786Skmacy{
128237263Snp	idr_destroy(&rnicp->cqidr);
129237263Snp	idr_destroy(&rnicp->qpidr);
130237263Snp	idr_destroy(&rnicp->mmidr);
131237263Snp	mtx_destroy(&rnicp->lock);
132237263Snp}
133237263Snp
134237263Snpstatic int
135237263Snpiwch_activate(struct adapter *sc)
136237263Snp{
137178786Skmacy	struct iwch_dev *rnicp;
138237263Snp	int rc;
139178786Skmacy
140237263Snp	KASSERT(!isset(&sc->offload_map, MAX_NPORTS),
141237263Snp	    ("%s: iWARP already activated on %s", __func__,
142237263Snp	    device_get_nameunit(sc->dev)));
143237263Snp
144178786Skmacy	rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp));
145237263Snp	if (rnicp == NULL)
146237263Snp		return (ENOMEM);
147178786Skmacy
148237263Snp	sc->iwarp_softc = rnicp;
149237263Snp	rnicp->rdev.adap = sc;
150178786Skmacy
151237263Snp	cxio_hal_init(sc);
152237263Snp	iwch_cm_init_cpl(sc);
153237263Snp
154237263Snp	rc = cxio_rdev_open(&rnicp->rdev);
155237263Snp	if (rc != 0) {
156178786Skmacy		printf("Unable to open CXIO rdev\n");
157237263Snp		goto err1;
158178786Skmacy	}
159178786Skmacy
160178786Skmacy	rnic_init(rnicp);
161178786Skmacy
162237263Snp	rc = iwch_register_device(rnicp);
163237263Snp	if (rc != 0) {
164178786Skmacy		printf("Unable to register device\n");
165237263Snp		goto err2;
166178786Skmacy	}
167237263Snp
168237263Snp	return (0);
169237263Snp
170237263Snperr2:
171237263Snp	rnic_uninit(rnicp);
172237263Snp	cxio_rdev_close(&rnicp->rdev);
173237263Snperr1:
174237263Snp	cxio_hal_uninit(sc);
175237263Snp	iwch_cm_term_cpl(sc);
176237263Snp	sc->iwarp_softc = NULL;
177237263Snp
178237263Snp	return (rc);
179178786Skmacy}
180178786Skmacy
181237263Snpstatic int
182237263Snpiwch_deactivate(struct adapter *sc)
183178786Skmacy{
184237263Snp	struct iwch_dev *rnicp;
185178786Skmacy
186237263Snp	rnicp = sc->iwarp_softc;
187237263Snp
188237263Snp	iwch_unregister_device(rnicp);
189237263Snp	rnic_uninit(rnicp);
190237263Snp	cxio_rdev_close(&rnicp->rdev);
191237263Snp	cxio_hal_uninit(sc);
192237263Snp	iwch_cm_term_cpl(sc);
193237263Snp	ib_dealloc_device(&rnicp->ibdev);
194237263Snp
195237263Snp	sc->iwarp_softc = NULL;
196237263Snp
197237263Snp	return (0);
198178786Skmacy}
199178786Skmacy
200237263Snpstatic void
201237263Snpiwch_activate_all(struct adapter *sc, void *arg __unused)
202178786Skmacy{
203237263Snp	ADAPTER_LOCK(sc);
204237263Snp	if ((sc->open_device_map & sc->offload_map) != 0 &&
205237263Snp	    t3_activate_uld(sc, ULD_IWARP) == 0)
206237263Snp		setbit(&sc->offload_map, MAX_NPORTS);
207237263Snp	ADAPTER_UNLOCK(sc);
208178786Skmacy}
209178786Skmacy
210237263Snpstatic void
211237263Snpiwch_deactivate_all(struct adapter *sc, void *arg __unused)
212237263Snp{
213237263Snp	ADAPTER_LOCK(sc);
214237263Snp	if (isset(&sc->offload_map, MAX_NPORTS) &&
215237263Snp	    t3_deactivate_uld(sc, ULD_IWARP) == 0)
216237263Snp		clrbit(&sc->offload_map, MAX_NPORTS);
217237263Snp	ADAPTER_UNLOCK(sc);
218237263Snp}
219178786Skmacy
220178786Skmacystatic int
221237263Snpiwch_mod_load(void)
222178786Skmacy{
223237263Snp	int rc;
224178786Skmacy
225237263Snp	rc = iwch_cm_init();
226237263Snp	if (rc != 0)
227237263Snp		return (rc);
228178786Skmacy
229237263Snp	rc = t3_register_uld(&iwch_uld_info);
230237263Snp	if (rc != 0) {
231237263Snp		iwch_cm_term();
232237263Snp		return (rc);
233237263Snp	}
234178786Skmacy
235237263Snp	t3_iterate(iwch_activate_all, NULL);
236237263Snp
237237263Snp	return (rc);
238178786Skmacy}
239178786Skmacy
240237263Snpstatic int
241237263Snpiwch_mod_unload(void)
242178786Skmacy{
243237263Snp	t3_iterate(iwch_deactivate_all, NULL);
244237263Snp
245178786Skmacy	iwch_cm_term();
246237263Snp
247237263Snp	if (t3_unregister_uld(&iwch_uld_info) == EBUSY)
248237263Snp		return (EBUSY);
249237263Snp
250237263Snp	return (0);
251178786Skmacy}
252237263Snp#endif	/* TCP_OFFLOAD */
253178786Skmacy
254237263Snpstatic int
255237263Snpiwch_modevent(module_t mod, int cmd, void *arg)
256178786Skmacy{
257237263Snp	int rc = 0;
258178786Skmacy
259237263Snp#ifdef TCP_OFFLOAD
260237263Snp	switch (cmd) {
261237263Snp	case MOD_LOAD:
262237263Snp		rc = iwch_mod_load();
263237263Snp		if(rc)
264237263Snp			printf("iw_cxgb: Chelsio T3 RDMA Driver failed to load\n");
265237263Snp		else
266237263Snp			printf("iw_cxgb: Chelsio T3 RDMA Driver loaded\n");
267237263Snp		break;
268178786Skmacy
269237263Snp	case MOD_UNLOAD:
270237263Snp		rc = iwch_mod_unload();
271237263Snp		if(rc)
272237263Snp			printf("iw_cxgb: Chelsio T3 RDMA Driver failed to unload\n");
273237263Snp		else
274237263Snp			printf("iw_cxgb: Chelsio T3 RDMA Driver unloaded\n");
275237263Snp		break;
276178786Skmacy
277237263Snp	default:
278237263Snp		rc = EINVAL;
279237263Snp	}
280237263Snp#else
281237263Snp	printf("iw_cxgb: compiled without TCP_OFFLOAD support.\n");
282237263Snp	rc = EOPNOTSUPP;
283237263Snp#endif
284237263Snp	return (rc);
285178786Skmacy}
286178786Skmacy
287237263Snpstatic moduledata_t iwch_mod_data = {
288178786Skmacy	"iw_cxgb",
289237263Snp	iwch_modevent,
290241394Skevlo	0
291178786Skmacy};
292178786Skmacy
293178786SkmacyMODULE_VERSION(iw_cxgb, 1);
294237263SnpDECLARE_MODULE(iw_cxgb, iwch_mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
295237263SnpMODULE_DEPEND(t3_tom, cxgbc, 1, 1, 1);
296237263SnpMODULE_DEPEND(iw_cxgb, toecore, 1, 1, 1);
297178786SkmacyMODULE_DEPEND(iw_cxgb, t3_tom, 1, 1, 1);
298256302SnpMODULE_DEPEND(iw_cxgb, ibcore, 1, 1, 1);
299289749ShselaskyMODULE_DEPEND(iw_cxgb, linuxkpi, 1, 1, 1);
300277402Shselasky
301