1 /**************************************************************************
2 
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, 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 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
27 
28 ***************************************************************************/
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: stable/9/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c 237920 2012-07-01 12:00:36Z np $");
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 
73 static int iwch_mod_load(void);
74 static int iwch_mod_unload(void);
75 static int iwch_activate(struct adapter *);
76 static int iwch_deactivate(struct adapter *);
77 
78 static struct uld_info iwch_uld_info = {
79 	.uld_id = ULD_IWARP,
80 	.activate = iwch_activate,
81 	.deactivate = iwch_deactivate,
82 };
83 
84 static void
rnic_init(struct iwch_dev * rnicp)85 rnic_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 
125 static void
rnic_uninit(struct iwch_dev * rnicp)126 rnic_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 
134 static int
iwch_activate(struct adapter * sc)135 iwch_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 
170 err2:
171 	rnic_uninit(rnicp);
172 	cxio_rdev_close(&rnicp->rdev);
173 err1:
174 	cxio_hal_uninit(sc);
175 	iwch_cm_term_cpl(sc);
176 	sc->iwarp_softc = NULL;
177 
178 	return (rc);
179 }
180 
181 static int
iwch_deactivate(struct adapter * sc)182 iwch_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 
200 static void
iwch_activate_all(struct adapter * sc,void * arg __unused)201 iwch_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 
210 static void
iwch_deactivate_all(struct adapter * sc,void * arg __unused)211 iwch_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 
220 static int
iwch_mod_load(void)221 iwch_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 
240 static int
iwch_mod_unload(void)241 iwch_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 
257 static int
iwch_modevent(module_t mod,int cmd,void * arg)258 iwch_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 
290 static moduledata_t iwch_mod_data = {
291 	"iw_cxgb",
292 	iwch_modevent,
293 	0
294 };
295 
296 MODULE_VERSION(iw_cxgb, 1);
297 DECLARE_MODULE(iw_cxgb, iwch_mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
298 MODULE_DEPEND(t3_tom, cxgbc, 1, 1, 1);
299 MODULE_DEPEND(iw_cxgb, toecore, 1, 1, 1);
300 MODULE_DEPEND(iw_cxgb, t3_tom, 1, 1, 1);
301