]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/cxgb/cxgb_offload.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / cxgb / cxgb_offload.c
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$");
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);