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$");
31
32#include "opt_inet.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/bus.h>
38#include <sys/pciio.h>
39#include <sys/conf.h>
40#include <machine/bus.h>
41#include <machine/resource.h>
42#include <sys/bus_dma.h>
43#include <sys/rman.h>
44#include <sys/ioccom.h>
45#include <sys/mbuf.h>
46#include <sys/rwlock.h>
47#include <sys/linker.h>
48#include <sys/firmware.h>
49#include <sys/socket.h>
50#include <sys/sockio.h>
51#include <sys/smp.h>
52#include <sys/sysctl.h>
53#include <sys/queue.h>
54#include <sys/taskqueue.h>
55#include <sys/proc.h>
56#include <sys/eventhandler.h>
57
58#include <netinet/in.h>
59#include <netinet/toecore.h>
60
61#include <rdma/ib_verbs.h>
62#include <linux/idr.h>
63#include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
64
65#ifdef TCP_OFFLOAD
66#include <cxgb_include.h>
67#include <ulp/iw_cxgb/iw_cxgb_wr.h>
68#include <ulp/iw_cxgb/iw_cxgb_hal.h>
69#include <ulp/iw_cxgb/iw_cxgb_provider.h>
70#include <ulp/iw_cxgb/iw_cxgb_cm.h>
71#include <ulp/iw_cxgb/iw_cxgb.h>
72
73static int iwch_mod_load(void);
74static int iwch_mod_unload(void);
75static int iwch_activate(struct adapter *);
76static int iwch_deactivate(struct adapter *);
77
78static struct uld_info iwch_uld_info = {
79	.uld_id = ULD_IWARP,
80	.activate = iwch_activate,
81	.deactivate = iwch_deactivate,
82};
83
84static void
85rnic_init(struct iwch_dev *rnicp)
86{
87
88	idr_init(&rnicp->cqidr);
89	idr_init(&rnicp->qpidr);
90	idr_init(&rnicp->mmidr);
91	mtx_init(&rnicp->lock, "iwch rnic lock", NULL, MTX_DEF|MTX_DUPOK);
92
93	rnicp->attr.vendor_id = 0x168;
94	rnicp->attr.vendor_part_id = 7;
95	rnicp->attr.max_qps = T3_MAX_NUM_QP - 32;
96	rnicp->attr.max_wrs = T3_MAX_QP_DEPTH;
97	rnicp->attr.max_sge_per_wr = T3_MAX_SGE;
98	rnicp->attr.max_sge_per_rdma_write_wr = T3_MAX_SGE;
99	rnicp->attr.max_cqs = T3_MAX_NUM_CQ - 1;
100	rnicp->attr.max_cqes_per_cq = T3_MAX_CQ_DEPTH;
101	rnicp->attr.max_mem_regs = cxio_num_stags(&rnicp->rdev);
102	rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE;
103	rnicp->attr.max_pds = T3_MAX_NUM_PD - 1;
104	rnicp->attr.mem_pgsizes_bitmask = T3_PAGESIZE_MASK;
105	rnicp->attr.max_mr_size = T3_MAX_MR_SIZE;
106	rnicp->attr.can_resize_wq = 0;
107	rnicp->attr.max_rdma_reads_per_qp = 8;
108	rnicp->attr.max_rdma_read_resources =
109	    rnicp->attr.max_rdma_reads_per_qp * rnicp->attr.max_qps;
110	rnicp->attr.max_rdma_read_qp_depth = 8;	/* IRD */
111	rnicp->attr.max_rdma_read_depth =
112	    rnicp->attr.max_rdma_read_qp_depth * rnicp->attr.max_qps;
113	rnicp->attr.rq_overflow_handled = 0;
114	rnicp->attr.can_modify_ird = 0;
115	rnicp->attr.can_modify_ord = 0;
116	rnicp->attr.max_mem_windows = rnicp->attr.max_mem_regs - 1;
117	rnicp->attr.stag0_value = 1;
118	rnicp->attr.zbva_support = 1;
119	rnicp->attr.local_invalidate_fence = 1;
120	rnicp->attr.cq_overflow_detection = 1;
121
122	return;
123}
124
125static void
126rnic_uninit(struct iwch_dev *rnicp)
127{
128	idr_destroy(&rnicp->cqidr);
129	idr_destroy(&rnicp->qpidr);
130	idr_destroy(&rnicp->mmidr);
131	mtx_destroy(&rnicp->lock);
132}
133
134static int
135iwch_activate(struct adapter *sc)
136{
137	struct iwch_dev *rnicp;
138	int rc;
139
140	KASSERT(!isset(&sc->offload_map, MAX_NPORTS),
141	    ("%s: iWARP already activated on %s", __func__,
142	    device_get_nameunit(sc->dev)));
143
144	rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp));
145	if (rnicp == NULL)
146		return (ENOMEM);
147
148	sc->iwarp_softc = rnicp;
149	rnicp->rdev.adap = sc;
150
151	cxio_hal_init(sc);
152	iwch_cm_init_cpl(sc);
153
154	rc = cxio_rdev_open(&rnicp->rdev);
155	if (rc != 0) {
156		printf("Unable to open CXIO rdev\n");
157		goto err1;
158	}
159
160	rnic_init(rnicp);
161
162	rc = iwch_register_device(rnicp);
163	if (rc != 0) {
164		printf("Unable to register device\n");
165		goto err2;
166	}
167
168	return (0);
169
170err2:
171	rnic_uninit(rnicp);
172	cxio_rdev_close(&rnicp->rdev);
173err1:
174	cxio_hal_uninit(sc);
175	iwch_cm_term_cpl(sc);
176	sc->iwarp_softc = NULL;
177
178	return (rc);
179}
180
181static int
182iwch_deactivate(struct adapter *sc)
183{
184	struct iwch_dev *rnicp;
185
186	rnicp = sc->iwarp_softc;
187
188	iwch_unregister_device(rnicp);
189	rnic_uninit(rnicp);
190	cxio_rdev_close(&rnicp->rdev);
191	cxio_hal_uninit(sc);
192	iwch_cm_term_cpl(sc);
193	ib_dealloc_device(&rnicp->ibdev);
194
195	sc->iwarp_softc = NULL;
196
197	return (0);
198}
199
200static void
201iwch_activate_all(struct adapter *sc, void *arg __unused)
202{
203	ADAPTER_LOCK(sc);
204	if ((sc->open_device_map & sc->offload_map) != 0 &&
205	    t3_activate_uld(sc, ULD_IWARP) == 0)
206		setbit(&sc->offload_map, MAX_NPORTS);
207	ADAPTER_UNLOCK(sc);
208}
209
210static void
211iwch_deactivate_all(struct adapter *sc, void *arg __unused)
212{
213	ADAPTER_LOCK(sc);
214	if (isset(&sc->offload_map, MAX_NPORTS) &&
215	    t3_deactivate_uld(sc, ULD_IWARP) == 0)
216		clrbit(&sc->offload_map, MAX_NPORTS);
217	ADAPTER_UNLOCK(sc);
218}
219
220static int
221iwch_mod_load(void)
222{
223	int rc;
224
225	rc = iwch_cm_init();
226	if (rc != 0)
227		return (rc);
228
229	rc = t3_register_uld(&iwch_uld_info);
230	if (rc != 0) {
231		iwch_cm_term();
232		return (rc);
233	}
234
235	t3_iterate(iwch_activate_all, NULL);
236
237	return (rc);
238}
239
240static int
241iwch_mod_unload(void)
242{
243	t3_iterate(iwch_deactivate_all, NULL);
244
245	iwch_cm_term();
246
247	if (t3_unregister_uld(&iwch_uld_info) == EBUSY)
248		return (EBUSY);
249
250	return (0);
251}
252#endif	/* TCP_OFFLOAD */
253
254#undef MODULE_VERSION
255#include <sys/module.h>
256
257static int
258iwch_modevent(module_t mod, int cmd, void *arg)
259{
260	int rc = 0;
261
262#ifdef TCP_OFFLOAD
263	switch (cmd) {
264	case MOD_LOAD:
265		rc = iwch_mod_load();
266		if(rc)
267			printf("iw_cxgb: Chelsio T3 RDMA Driver failed to load\n");
268		else
269			printf("iw_cxgb: Chelsio T3 RDMA Driver loaded\n");
270		break;
271
272	case MOD_UNLOAD:
273		rc = iwch_mod_unload();
274		if(rc)
275			printf("iw_cxgb: Chelsio T3 RDMA Driver failed to unload\n");
276		else
277			printf("iw_cxgb: Chelsio T3 RDMA Driver unloaded\n");
278		break;
279
280	default:
281		rc = EINVAL;
282	}
283#else
284	printf("iw_cxgb: compiled without TCP_OFFLOAD support.\n");
285	rc = EOPNOTSUPP;
286#endif
287	return (rc);
288}
289
290static moduledata_t iwch_mod_data = {
291	"iw_cxgb",
292	iwch_modevent,
293	0
294};
295
296MODULE_VERSION(iw_cxgb, 1);
297DECLARE_MODULE(iw_cxgb, iwch_mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
298MODULE_DEPEND(t3_tom, cxgbc, 1, 1, 1);
299MODULE_DEPEND(iw_cxgb, toecore, 1, 1, 1);
300MODULE_DEPEND(iw_cxgb, t3_tom, 1, 1, 1);
301