1 /**************************************************************************
2
3 Copyright (c) 2007-2008, 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 ***************************************************************************/
30
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD: releng/9.0/sys/dev/cxgb/cxgb_offload.c 190330 2009-03-23 19:58:26Z gnn $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/bus.h>
39 #include <sys/module.h>
40 #include <sys/pciio.h>
41 #include <sys/conf.h>
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/bus_dma.h>
45 #include <sys/rman.h>
46 #include <sys/ioccom.h>
47 #include <sys/mbuf.h>
48 #include <sys/linker.h>
49 #include <sys/firmware.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <sys/smp.h>
53 #include <sys/sysctl.h>
54 #include <sys/syslog.h>
55 #include <sys/queue.h>
56 #include <sys/taskqueue.h>
57 #include <sys/proc.h>
58
59 #include <cxgb_include.h>
60
61 #include <net/route.h>
62
63 #define VALIDATE_TID 0
64 MALLOC_DEFINE(M_CXGB, "cxgb", "Chelsio 10 Gigabit Ethernet and services");
65
66 TAILQ_HEAD(, cxgb_client) client_list;
67 TAILQ_HEAD(, t3cdev) ofld_dev_list;
68
69
70 static struct mtx cxgb_db_lock;
71
72
73 static int inited = 0;
74
75 static inline int
76 offload_activated(struct t3cdev *tdev)
77 {
78 struct adapter *adapter = tdev2adap(tdev);
79
80 return (isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT));
81 }
82
83 static inline void
84 register_tdev(struct t3cdev *tdev)
85 {
86 static int unit;
87
88 mtx_lock(&cxgb_db_lock);
89 snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
90 TAILQ_INSERT_TAIL(&ofld_dev_list, tdev, entry);
91 mtx_unlock(&cxgb_db_lock);
92 }
93
94 static inline void
95 unregister_tdev(struct t3cdev *tdev)
96 {
97 if (!inited)
98 return;
99
100 mtx_lock(&cxgb_db_lock);
101 TAILQ_REMOVE(&ofld_dev_list, tdev, entry);
102 mtx_unlock(&cxgb_db_lock);
103 }
104
105 #ifndef TCP_OFFLOAD_DISABLE
106 /**
107 * cxgb_register_client - register an offload client
108 * @client: the client
109 *
110 * Add the client to the client list,
111 * and call backs the client for each activated offload device
112 */
113 void
114 cxgb_register_client(struct cxgb_client *client)
115 {
116 struct t3cdev *tdev;
117
118 mtx_lock(&cxgb_db_lock);
119 TAILQ_INSERT_TAIL(&client_list, client, client_entry);
120
121 if (client->add) {
122 TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
123 if (offload_activated(tdev)) {
124 client->add(tdev);
125 } else
126 CTR1(KTR_CXGB,
127 "cxgb_register_client: %p not activated", tdev);
128
129 }
130 }
131 mtx_unlock(&cxgb_db_lock);
132 }
133
134 /**
135 * cxgb_unregister_client - unregister an offload client
136 * @client: the client
137 *
138 * Remove the client to the client list,
139 * and call backs the client for each activated offload device.
140 */
141 void
142 cxgb_unregister_client(struct cxgb_client *client)
143 {
144 struct t3cdev *tdev;
145
146 mtx_lock(&cxgb_db_lock);
147 TAILQ_REMOVE(&client_list, client, client_entry);
148
149 if (client->remove) {
150 TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
151 if (offload_activated(tdev))
152 client->remove(tdev);
153 }
154 }
155 mtx_unlock(&cxgb_db_lock);
156 }
157
158 /**
159 * cxgb_add_clients - activate register clients for an offload device
160 * @tdev: the offload device
161 *
162 * Call backs all registered clients once a offload device is activated
163 */
164 void
165 cxgb_add_clients(struct t3cdev *tdev)
166 {
167 struct cxgb_client *client;
168
169 mtx_lock(&cxgb_db_lock);
170 TAILQ_FOREACH(client, &client_list, client_entry) {
171 if (client->add)
172 client->add(tdev);
173 }
174 mtx_unlock(&cxgb_db_lock);
175 }
176
177 /**
178 * cxgb_remove_clients - activate register clients for an offload device
179 * @tdev: the offload device
180 *
181 * Call backs all registered clients once a offload device is deactivated
182 */
183 void
184 cxgb_remove_clients(struct t3cdev *tdev)
185 {
186 struct cxgb_client *client;
187
188 mtx_lock(&cxgb_db_lock);
189 TAILQ_FOREACH(client, &client_list, client_entry) {
190 if (client->remove)
191 client->remove(tdev);
192 }
193 mtx_unlock(&cxgb_db_lock);
194 }
195 #endif
196
197 /**
198 * cxgb_ofld_recv - process n received offload packets
199 * @dev: the offload device
200 * @m: an array of offload packets
201 * @n: the number of offload packets
202 *
203 * Process an array of ingress offload packets. Each packet is forwarded
204 * to any active network taps and then passed to the offload device's receive
205 * method. We optimize passing packets to the receive method by passing
206 * it the whole array at once except when there are active taps.
207 */
208 int
209 cxgb_ofld_recv(struct t3cdev *dev, struct mbuf **m, int n)
210 {
211
212 return dev->recv(dev, m, n);
213 }
214
215 /*
216 * Dummy handler for Rx offload packets in case we get an offload packet before
217 * proper processing is setup. This complains and drops the packet as it isn't
218 * normal to get offload packets at this stage.
219 */
220 static int
221 rx_offload_blackhole(struct t3cdev *dev, struct mbuf **m, int n)
222 {
223 while (n--)
224 m_freem(m[n]);
225 return 0;
226 }
227
228 static void
229 dummy_neigh_update(struct t3cdev *dev, struct rtentry *neigh, uint8_t *enaddr,
230 struct sockaddr *sa)
231 {
232 }
233
234 void
235 cxgb_set_dummy_ops(struct t3cdev *dev)
236 {
237 dev->recv = rx_offload_blackhole;
238 dev->arp_update = dummy_neigh_update;
239 }
240
241 static int
242 do_smt_write_rpl(struct t3cdev *dev, struct mbuf *m)
243 {
244 struct cpl_smt_write_rpl *rpl = cplhdr(m);
245
246 if (rpl->status != CPL_ERR_NONE)
247 log(LOG_ERR,
248 "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
249 rpl->status, GET_TID(rpl));
250
251 return CPL_RET_BUF_DONE;
252 }
253
254 static int
255 do_l2t_write_rpl(struct t3cdev *dev, struct mbuf *m)
256 {
257 struct cpl_l2t_write_rpl *rpl = cplhdr(m);
258
259 if (rpl->status != CPL_ERR_NONE)
260 log(LOG_ERR,
261 "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
262 rpl->status, GET_TID(rpl));
263
264 return CPL_RET_BUF_DONE;
265 }
266
267 static int
268 do_rte_write_rpl(struct t3cdev *dev, struct mbuf *m)
269 {
270 struct cpl_rte_write_rpl *rpl = cplhdr(m);
271
272 if (rpl->status != CPL_ERR_NONE)
273 log(LOG_ERR,
274 "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
275 rpl->status, GET_TID(rpl));
276
277 return CPL_RET_BUF_DONE;
278 }
279
280 static int
281 do_set_tcb_rpl(struct t3cdev *dev, struct mbuf *m)
282 {
283 struct cpl_set_tcb_rpl *rpl = cplhdr(m);
284
285 if (rpl->status != CPL_ERR_NONE)
286 log(LOG_ERR,
287 "Unexpected SET_TCB_RPL status %u for tid %u\n",
288 rpl->status, GET_TID(rpl));
289 return CPL_RET_BUF_DONE;
290 }
291
292 static int
293 do_trace(struct t3cdev *dev, struct mbuf *m)
294 {
295 #if 0
296 struct cpl_trace_pkt *p = cplhdr(m);
297
298
299 skb->protocol = 0xffff;
300 skb->dev = dev->lldev;
301 skb_pull(skb, sizeof(*p));
302 skb->mac.raw = mtod(m, (char *));
303 netif_receive_skb(skb);
304 #endif
305 return 0;
306 }
307
308 /*
309 * Process a received packet with an unknown/unexpected CPL opcode.
310 */
311 static int
312 do_bad_cpl(struct t3cdev *dev, struct mbuf *m)
313 {
314 log(LOG_ERR, "%s: received bad CPL command 0x%x\n", dev->name,
315 0xFF & *mtod(m, uint32_t *));
316 return (CPL_RET_BUF_DONE | CPL_RET_BAD_MSG);
317 }
318
319 /*
320 * Handlers for each CPL opcode
321 */
322 static cpl_handler_func cpl_handlers[256];
323
324 /*
325 * T3CDEV's receive method.
326 */
327 int
328 process_rx(struct t3cdev *dev, struct mbuf **m, int n)
329 {
330 while (n--) {
331 struct mbuf *m0 = *m++;
332 unsigned int opcode = G_OPCODE(ntohl(m0->m_pkthdr.csum_data));
333 int ret;
334
335 DPRINTF("processing op=0x%x m=%p data=%p\n", opcode, m0, m0->m_data);
336
337 ret = cpl_handlers[opcode] (dev, m0);
338
339 #if VALIDATE_TID
340 if (ret & CPL_RET_UNKNOWN_TID) {
341 union opcode_tid *p = cplhdr(m0);
342
343 log(LOG_ERR, "%s: CPL message (opcode %u) had "
344 "unknown TID %u\n", dev->name, opcode,
345 G_TID(ntohl(p->opcode_tid)));
346 }
347 #endif
348 if (ret & CPL_RET_BUF_DONE)
349 m_freem(m0);
350 }
351 return 0;
352 }
353
354 /*
355 * Add a new handler to the CPL dispatch table. A NULL handler may be supplied
356 * to unregister an existing handler.
357 */
358 void
359 t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
360 {
361 if (opcode < NUM_CPL_CMDS)
362 cpl_handlers[opcode] = h ? h : do_bad_cpl;
363 else
364 log(LOG_ERR, "T3C: handler registration for "
365 "opcode %x failed\n", opcode);
366 }
367
368 /*
369 * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
370 * The allocated memory is cleared.
371 */
372 void *
373 cxgb_alloc_mem(unsigned long size)
374 {
375
376 return malloc(size, M_CXGB, M_ZERO|M_NOWAIT);
377 }
378
379 /*
380 * Free memory allocated through t3_alloc_mem().
381 */
382 void
383 cxgb_free_mem(void *addr)
384 {
385 free(addr, M_CXGB);
386 }
387
388 static __inline int
389 adap2type(struct adapter *adapter)
390 {
391 int type = 0;
392
393 switch (adapter->params.rev) {
394 case T3_REV_A:
395 type = T3A;
396 break;
397 case T3_REV_B:
398 case T3_REV_B2:
399 type = T3B;
400 break;
401 case T3_REV_C:
402 type = T3C;
403 break;
404 }
405 return type;
406 }
407
408 void
409 cxgb_adapter_ofld(struct adapter *adapter)
410 {
411 struct t3cdev *tdev = &adapter->tdev;
412
413 cxgb_set_dummy_ops(tdev);
414 tdev->type = adap2type(adapter);
415 tdev->adapter = adapter;
416 register_tdev(tdev);
417
418 }
419
420 void
421 cxgb_adapter_unofld(struct adapter *adapter)
422 {
423 struct t3cdev *tdev = &adapter->tdev;
424
425 tdev->recv = NULL;
426 tdev->arp_update = NULL;
427 unregister_tdev(tdev);
428 }
429
430 void
431 cxgb_offload_init(void)
432 {
433 int i;
434
435 if (inited++)
436 return;
437
438 mtx_init(&cxgb_db_lock, "ofld db", NULL, MTX_DEF);
439
440 TAILQ_INIT(&client_list);
441 TAILQ_INIT(&ofld_dev_list);
442
443 for (i = 0; i < 0x100; ++i)
444 cpl_handlers[i] = do_bad_cpl;
445
446 t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
447 t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl);
448 t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
449
450 t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
451 t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
452
453 }
454
455 void
456 cxgb_offload_exit(void)
457 {
458
459 if (--inited)
460 return;
461
462 mtx_destroy(&cxgb_db_lock);
463 }
464
465 MODULE_VERSION(if_cxgb, 1);
Cache object: 8a071a54c68b6a399a849cdab2b77f45
|