]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/cxgb/ulp/toecore/toedev.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / cxgb / ulp / toecore / toedev.c
1
2 /**************************************************************************
3
4 Copyright (c) 2007, Chelsio Inc.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10  1. Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12
13  2. Neither the name of the Chelsio Corporation nor the names of its
14     contributors may be used to endorse or promote products derived from
15     this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
28
29 ***************************************************************************/
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/bus.h>
38 #include <sys/module.h>
39 #include <sys/queue.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
42
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45
46 #include <net/bpf.h>
47 #include <net/ethernet.h>
48 #include <net/if.h>
49 #include <net/route.h>
50
51
52 /*
53  * XXX 
54  */
55 #include <cxgb_include.h>
56 #include <ulp/toecore/cxgb_toedev.h>
57
58 static struct mtx offload_db_lock;
59 static TAILQ_HEAD(, toedev) offload_dev_list;
60 static TAILQ_HEAD(, tom_info) offload_module_list;
61
62 /*
63  * Returns the entry in the given table with the given offload id, or NULL
64  * if the id is not found.
65  */
66 static const struct offload_id *
67 id_find(unsigned int id, const struct offload_id *table)
68 {
69         for ( ; table->id; ++table)
70                 if (table->id == id)
71                         return table;
72         return NULL;
73 }
74
75 /*
76  * Returns true if an offload device is presently attached to an offload module.
77  */
78 static inline int
79 is_attached(const struct toedev *dev)
80 {
81         return dev->tod_offload_mod != NULL;
82 }
83
84 /*
85  * Try to attach a new offload device to an existing TCP offload module that
86  * can handle the device's offload id.  Returns 0 if it succeeds.
87  *
88  * Must be called with the offload_db_lock held.
89  */
90 static int
91 offload_attach(struct toedev *dev)
92 {
93         struct tom_info *t;
94
95         TAILQ_FOREACH(t, &offload_module_list, entry) {
96                 const struct offload_id *entry;
97
98                 entry = id_find(dev->tod_ttid, t->ti_id_table);
99                 if (entry && t->ti_attach(dev, entry) == 0) {
100                         dev->tod_offload_mod = t;
101                         return 0;
102                 }
103         }
104         return (ENOPROTOOPT);
105 }
106
107 /**
108  * register_tom - register a TCP Offload Module (TOM)
109  * @t: the offload module to register
110  *
111  * Register a TCP Offload Module (TOM).
112  */
113 int
114 register_tom(struct tom_info *t)
115 {
116         mtx_lock(&offload_db_lock);
117         toedev_registration_count++;
118         TAILQ_INSERT_HEAD(&offload_module_list, t, entry);
119         mtx_unlock(&offload_db_lock);
120         return 0;
121 }
122
123 /**
124  * unregister_tom - unregister a TCP Offload Module (TOM)
125  * @t: the offload module to register
126  *
127  * Unregister a TCP Offload Module (TOM).  Note that this does not affect any
128  * TOE devices to which the TOM is already attached.
129  */
130 int
131 unregister_tom(struct tom_info *t)
132 {
133         mtx_lock(&offload_db_lock);
134         TAILQ_REMOVE(&offload_module_list, t, entry);
135         mtx_unlock(&offload_db_lock);
136         return 0;
137 }
138
139 /*
140  * Find an offload device by name.  Must be called with offload_db_lock held.
141  */
142 static struct toedev *
143 __find_offload_dev_by_name(const char *name)
144 {
145         struct toedev *dev;
146
147         TAILQ_FOREACH(dev, &offload_dev_list, entry) {
148                 if (!strncmp(dev->tod_name, name, TOENAMSIZ))
149                         return dev;
150         }
151         return NULL;
152 }
153
154 /*
155  * Returns true if an offload device is already registered.
156  * Must be called with the offload_db_lock held.
157  */
158 static int
159 is_registered(const struct toedev *dev)
160 {
161         struct toedev *d;
162
163         TAILQ_FOREACH(d, &offload_dev_list, entry) {
164                 if (d == dev)
165                         return 1;
166         }
167         return 0;
168 }
169
170 /*
171  * Finalize the name of an offload device by assigning values to any format
172  * strings in its name.
173  */
174 static int
175 assign_name(struct toedev *dev, const char *name, int limit)
176 {
177         int i;
178
179         for (i = 0; i < limit; ++i) {
180                 char s[TOENAMSIZ];
181
182                 if (snprintf(s, sizeof(s), name, i) >= sizeof(s))
183                         return -1;                  /* name too long */
184                 if (!__find_offload_dev_by_name(s)) {
185                         strcpy(dev->tod_name, s);
186                         return 0;
187                 }
188         }
189         return -1;
190 }
191
192 /**
193  * register_toedev - register a TOE device
194  * @dev: the device
195  * @name: a name template for the device
196  *
197  * Register a TOE device and try to attach an appropriate TCP offload module
198  * to it.  @name is a template that may contain at most one %d format
199  * specifier.
200  */
201 int
202 register_toedev(struct toedev *dev, const char *name)
203 {
204         int ret;
205         const char *p;
206
207         /*
208          * Validate the name template.  Only one %d allowed and name must be
209          * a valid filename so it can appear in sysfs.
210          */
211         if (!name || !*name || !strcmp(name, ".") || !strcmp(name, "..") ||
212             strchr(name, '/'))
213                 return EINVAL;
214
215         p = strchr(name, '%');
216         if (p && (p[1] != 'd' || strchr(p + 2, '%')))
217                 return EINVAL;
218
219         mtx_lock(&offload_db_lock);
220         if (is_registered(dev)) {  /* device already registered */
221                 ret = EEXIST;
222                 goto out;
223         }
224
225         if ((ret = assign_name(dev, name, 32)) != 0)
226                 goto out;
227
228         dev->tod_offload_mod = NULL;
229         TAILQ_INSERT_TAIL(&offload_dev_list, dev, entry);
230 out:
231         mtx_unlock(&offload_db_lock);
232         return ret;
233 }
234
235 /**
236  * unregister_toedev - unregister a TOE device
237  * @dev: the device
238  *
239  * Unregister a TOE device.  The device must not be attached to an offload
240  * module.
241  */
242 int
243 unregister_toedev(struct toedev *dev)
244 {
245         int ret = 0;
246
247         mtx_lock(&offload_db_lock);
248         if (!is_registered(dev)) {
249                 ret = ENODEV;
250                 goto out;
251         }
252         if (is_attached(dev)) {
253                 ret = EBUSY;
254                 goto out;
255         }
256         TAILQ_REMOVE(&offload_dev_list, dev, entry);
257 out:
258         mtx_unlock(&offload_db_lock);
259         return ret;
260 }
261
262 /**
263  * activate_offload - activate an offload device
264  * @dev: the device
265  *
266  * Activate an offload device by locating an appropriate registered offload
267  * module.  If no module is found the operation fails and may be retried at
268  * a later time.
269  */
270 int
271 activate_offload(struct toedev *dev)
272 {
273         int ret = 0;
274
275         mtx_lock(&offload_db_lock);
276         if (!is_registered(dev))
277                 ret = ENODEV;
278         else if (!is_attached(dev))
279                 ret = offload_attach(dev);
280         mtx_unlock(&offload_db_lock);
281         return ret;
282 }
283
284 /**
285  * toe_send - send a packet to a TOE device
286  * @dev: the device
287  * @m: the packet
288  *
289  * Sends an mbuf to a TOE driver after dealing with any active network taps.
290  */
291 int
292 toe_send(struct toedev *dev, struct mbuf *m)
293 {
294         int r;
295
296         critical_enter(); /* XXX neccessary? */
297         r = dev->tod_send(dev, m);
298         critical_exit();
299         if (r)
300                 BPF_MTAP(dev->tod_lldev, m);
301         return r;
302 }
303
304 /**
305  * toe_receive_mbuf - process n received TOE packets
306  * @dev: the toe device
307  * @m: an array of offload packets
308  * @n: the number of offload packets
309  *
310  * Process an array of ingress offload packets.  Each packet is forwarded
311  * to any active network taps and then passed to the toe device's receive
312  * method.  We optimize passing packets to the receive method by passing
313  * it the whole array at once except when there are active taps.
314  */
315 int
316 toe_receive_mbuf(struct toedev *dev, struct mbuf **m, int n)
317 {
318         if (__predict_true(!bpf_peers_present(dev->tod_lldev->if_bpf)))
319                 return dev->tod_recv(dev, m, n);
320
321         for ( ; n; n--, m++) {
322                 m[0]->m_pkthdr.rcvif = dev->tod_lldev;
323                 BPF_MTAP(dev->tod_lldev, m[0]);
324                 dev->tod_recv(dev, m, 1);
325         }
326         return 0;
327 }
328
329 static inline int
330 ifnet_is_offload(const struct ifnet *ifp)
331 {
332         return (ifp->if_flags & IFCAP_TOE);
333 }
334
335 void
336 toe_arp_update(struct rtentry *rt)
337 {
338         struct ifnet *ifp = rt->rt_ifp;
339
340         if (ifp && ifnet_is_offload(ifp)) {
341                 struct toedev *tdev = TOEDEV(ifp);
342
343                 if (tdev && tdev->tod_arp_update)
344                         tdev->tod_arp_update(tdev, rt);
345         }
346 }
347
348 /**
349  * offload_get_phys_egress - find the physical egress device
350  * @root_dev: the root device anchoring the search
351  * @so: the socket used to determine egress port in bonding mode
352  * @context: in bonding mode, indicates a connection set up or failover
353  *
354  * Given a root network device it returns the physical egress device that is a
355  * descendant of the root device.  The root device may be either a physical
356  * device, in which case it is the device returned, or a virtual device, such
357  * as a VLAN or bonding device.  In case of a bonding device the search
358  * considers the decisions of the bonding device given its mode to locate the
359  * correct egress device.
360  */
361 struct ifnet *
362 offload_get_phys_egress(struct ifnet *root_dev, struct socket *so, int context)
363 {
364
365 #if 0
366         while (root_dev && ifnet_is_offload(root_dev)) {
367                 if (root_dev->tod_priv_flags & IFF_802_1Q_VLAN)
368                         root_dev = VLAN_DEV_INFO(root_dev)->real_dev;
369                 else if (root_dev->tod_flags & IFF_MASTER)
370                         root_dev = toe_bond_get_slave(root_dev, sk, context);
371                 else
372                         break;
373         }
374 #endif
375         return root_dev;
376 }
377
378 static int
379 toecore_load(module_t mod, int cmd, void *arg)
380 {
381         int err = 0;
382
383         switch (cmd) {
384         case MOD_LOAD:
385                 mtx_init(&offload_db_lock, "toedev lock", NULL, MTX_DEF);
386                 TAILQ_INIT(&offload_dev_list);
387                 TAILQ_INIT(&offload_module_list);
388                 break;
389         case MOD_QUIESCE:
390                 break;
391         case MOD_UNLOAD:
392                 mtx_lock(&offload_db_lock);
393                 if (!TAILQ_EMPTY(&offload_dev_list) ||
394                     !TAILQ_EMPTY(&offload_module_list)) {
395                         err = EBUSY;
396                         mtx_unlock(&offload_db_lock);
397                         break;
398                 }
399                 mtx_unlock(&offload_db_lock);
400                 mtx_destroy(&offload_db_lock);
401                 break;
402         case MOD_SHUTDOWN:
403                 break;
404         default:
405                 err = EOPNOTSUPP;
406                 break;
407         }
408
409         return (err);
410 }
411
412
413 static moduledata_t mod_data= {
414         "toecore",
415         toecore_load,
416         0
417 };
418
419 MODULE_VERSION(toecore, 1);
420 DECLARE_MODULE(toecore, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);