]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/cxgb/ulp/toecore/toedev.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 #ifdef CONFIG_DEFINED
56 #include <cxgb_include.h>
57 #else
58 #include <dev/cxgb/cxgb_include.h>
59 #endif
60
61
62
63 static struct mtx offload_db_lock;
64 static TAILQ_HEAD(, toedev) offload_dev_list;
65 static TAILQ_HEAD(, tom_info) offload_module_list;
66
67 /*
68  * Returns the entry in the given table with the given offload id, or NULL
69  * if the id is not found.
70  */
71 static const struct offload_id *
72 id_find(unsigned int id, const struct offload_id *table)
73 {
74         for ( ; table->id; ++table)
75                 if (table->id == id)
76                         return table;
77         return NULL;
78 }
79
80 /*
81  * Returns true if an offload device is presently attached to an offload module.
82  */
83 static inline int
84 is_attached(const struct toedev *dev)
85 {
86         return dev->tod_offload_mod != NULL;
87 }
88
89 /*
90  * Try to attach a new offload device to an existing TCP offload module that
91  * can handle the device's offload id.  Returns 0 if it succeeds.
92  *
93  * Must be called with the offload_db_lock held.
94  */
95 static int
96 offload_attach(struct toedev *dev)
97 {
98         struct tom_info *t;
99
100         TAILQ_FOREACH(t, &offload_module_list, entry) {
101                 const struct offload_id *entry;
102
103                 entry = id_find(dev->tod_ttid, t->ti_id_table);
104                 if (entry && t->ti_attach(dev, entry) == 0) {
105                         dev->tod_offload_mod = t;
106                         return 0;
107                 }
108         }
109         return (ENOPROTOOPT);
110 }
111
112 /**
113  * register_tom - register a TCP Offload Module (TOM)
114  * @t: the offload module to register
115  *
116  * Register a TCP Offload Module (TOM).
117  */
118 int
119 register_tom(struct tom_info *t)
120 {
121         mtx_lock(&offload_db_lock);
122         toedev_registration_count++;
123         TAILQ_INSERT_HEAD(&offload_module_list, t, entry);
124         mtx_unlock(&offload_db_lock);
125         return 0;
126 }
127
128 /**
129  * unregister_tom - unregister a TCP Offload Module (TOM)
130  * @t: the offload module to register
131  *
132  * Unregister a TCP Offload Module (TOM).  Note that this does not affect any
133  * TOE devices to which the TOM is already attached.
134  */
135 int
136 unregister_tom(struct tom_info *t)
137 {
138         mtx_lock(&offload_db_lock);
139         TAILQ_REMOVE(&offload_module_list, t, entry);
140         mtx_unlock(&offload_db_lock);
141         return 0;
142 }
143
144 /*
145  * Find an offload device by name.  Must be called with offload_db_lock held.
146  */
147 static struct toedev *
148 __find_offload_dev_by_name(const char *name)
149 {
150         struct toedev *dev;
151
152         TAILQ_FOREACH(dev, &offload_dev_list, entry) {
153                 if (!strncmp(dev->tod_name, name, TOENAMSIZ))
154                         return dev;
155         }
156         return NULL;
157 }
158
159 /*
160  * Returns true if an offload device is already registered.
161  * Must be called with the offload_db_lock held.
162  */
163 static int
164 is_registered(const struct toedev *dev)
165 {
166         struct toedev *d;
167
168         TAILQ_FOREACH(d, &offload_dev_list, entry) {
169                 if (d == dev)
170                         return 1;
171         }
172         return 0;
173 }
174
175 /*
176  * Finalize the name of an offload device by assigning values to any format
177  * strings in its name.
178  */
179 static int
180 assign_name(struct toedev *dev, const char *name, int limit)
181 {
182         int i;
183
184         for (i = 0; i < limit; ++i) {
185                 char s[TOENAMSIZ];
186
187                 if (snprintf(s, sizeof(s), name, i) >= sizeof(s))
188                         return -1;                  /* name too long */
189                 if (!__find_offload_dev_by_name(s)) {
190                         strcpy(dev->tod_name, s);
191                         return 0;
192                 }
193         }
194         return -1;
195 }
196
197 /**
198  * register_toedev - register a TOE device
199  * @dev: the device
200  * @name: a name template for the device
201  *
202  * Register a TOE device and try to attach an appropriate TCP offload module
203  * to it.  @name is a template that may contain at most one %d format
204  * specifier.
205  */
206 int
207 register_toedev(struct toedev *dev, const char *name)
208 {
209         int ret;
210         const char *p;
211
212         /*
213          * Validate the name template.  Only one %d allowed and name must be
214          * a valid filename so it can appear in sysfs.
215          */
216         if (!name || !*name || !strcmp(name, ".") || !strcmp(name, "..") ||
217             strchr(name, '/'))
218                 return EINVAL;
219
220         p = strchr(name, '%');
221         if (p && (p[1] != 'd' || strchr(p + 2, '%')))
222                 return EINVAL;
223
224         mtx_lock(&offload_db_lock);
225         if (is_registered(dev)) {  /* device already registered */
226                 ret = EEXIST;
227                 goto out;
228         }
229
230         if ((ret = assign_name(dev, name, 32)) != 0)
231                 goto out;
232
233         dev->tod_offload_mod = NULL;
234         TAILQ_INSERT_TAIL(&offload_dev_list, dev, entry);
235 out:
236         mtx_unlock(&offload_db_lock);
237         return ret;
238 }
239
240 /**
241  * unregister_toedev - unregister a TOE device
242  * @dev: the device
243  *
244  * Unregister a TOE device.  The device must not be attached to an offload
245  * module.
246  */
247 int
248 unregister_toedev(struct toedev *dev)
249 {
250         int ret = 0;
251
252         mtx_lock(&offload_db_lock);
253         if (!is_registered(dev)) {
254                 ret = ENODEV;
255                 goto out;
256         }
257         if (is_attached(dev)) {
258                 ret = EBUSY;
259                 goto out;
260         }
261         TAILQ_REMOVE(&offload_dev_list, dev, entry);
262 out:
263         mtx_unlock(&offload_db_lock);
264         return ret;
265 }
266
267 /**
268  * activate_offload - activate an offload device
269  * @dev: the device
270  *
271  * Activate an offload device by locating an appropriate registered offload
272  * module.  If no module is found the operation fails and may be retried at
273  * a later time.
274  */
275 int
276 activate_offload(struct toedev *dev)
277 {
278         int ret = 0;
279
280         mtx_lock(&offload_db_lock);
281         if (!is_registered(dev))
282                 ret = ENODEV;
283         else if (!is_attached(dev))
284                 ret = offload_attach(dev);
285         mtx_unlock(&offload_db_lock);
286         return ret;
287 }
288
289 /**
290  * toe_send - send a packet to a TOE device
291  * @dev: the device
292  * @m: the packet
293  *
294  * Sends an mbuf to a TOE driver after dealing with any active network taps.
295  */
296 int
297 toe_send(struct toedev *dev, struct mbuf *m)
298 {
299         int r;
300
301         critical_enter(); /* XXX neccessary? */
302         r = dev->tod_send(dev, m);
303         critical_exit();
304         if (r)
305                 BPF_MTAP(dev->tod_lldev, m);
306         return r;
307 }
308
309 /**
310  * toe_receive_mbuf - process n received TOE packets
311  * @dev: the toe device
312  * @m: an array of offload packets
313  * @n: the number of offload packets
314  *
315  * Process an array of ingress offload packets.  Each packet is forwarded
316  * to any active network taps and then passed to the toe device's receive
317  * method.  We optimize passing packets to the receive method by passing
318  * it the whole array at once except when there are active taps.
319  */
320 int
321 toe_receive_mbuf(struct toedev *dev, struct mbuf **m, int n)
322 {
323         if (__predict_true(!bpf_peers_present(dev->tod_lldev->if_bpf)))
324                 return dev->tod_recv(dev, m, n);
325
326         for ( ; n; n--, m++) {
327                 m[0]->m_pkthdr.rcvif = dev->tod_lldev;
328                 BPF_MTAP(dev->tod_lldev, m[0]);
329                 dev->tod_recv(dev, m, 1);
330         }
331         return 0;
332 }
333
334 static inline int
335 ifnet_is_offload(const struct ifnet *ifp)
336 {
337         return (ifp->if_flags & IFCAP_TOE);
338 }
339
340 void
341 toe_arp_update(struct rtentry *rt)
342 {
343         struct ifnet *ifp = rt->rt_ifp;
344
345         if (ifp && ifnet_is_offload(ifp)) {
346                 struct toedev *tdev = TOEDEV(ifp);
347
348                 if (tdev && tdev->tod_arp_update)
349                         tdev->tod_arp_update(tdev, rt);
350         }
351 }
352
353 /**
354  * offload_get_phys_egress - find the physical egress device
355  * @root_dev: the root device anchoring the search
356  * @so: the socket used to determine egress port in bonding mode
357  * @context: in bonding mode, indicates a connection set up or failover
358  *
359  * Given a root network device it returns the physical egress device that is a
360  * descendant of the root device.  The root device may be either a physical
361  * device, in which case it is the device returned, or a virtual device, such
362  * as a VLAN or bonding device.  In case of a bonding device the search
363  * considers the decisions of the bonding device given its mode to locate the
364  * correct egress device.
365  */
366 struct ifnet *
367 offload_get_phys_egress(struct ifnet *root_dev, struct socket *so, int context)
368 {
369
370 #if 0
371         while (root_dev && ifnet_is_offload(root_dev)) {
372                 if (root_dev->tod_priv_flags & IFF_802_1Q_VLAN)
373                         root_dev = VLAN_DEV_INFO(root_dev)->real_dev;
374                 else if (root_dev->tod_flags & IFF_MASTER)
375                         root_dev = toe_bond_get_slave(root_dev, sk, context);
376                 else
377                         break;
378         }
379 #endif
380         return root_dev;
381 }
382
383 static int
384 toecore_load(module_t mod, int cmd, void *arg)
385 {
386         int err = 0;
387
388         switch (cmd) {
389         case MOD_LOAD:
390                 mtx_init(&offload_db_lock, "toedev lock", NULL, MTX_DEF);
391                 TAILQ_INIT(&offload_dev_list);
392                 TAILQ_INIT(&offload_module_list);
393                 break;
394         case MOD_QUIESCE:
395                 break;
396         case MOD_UNLOAD:
397                 mtx_lock(&offload_db_lock);
398                 if (!TAILQ_EMPTY(&offload_dev_list) ||
399                     !TAILQ_EMPTY(&offload_module_list)) {
400                         err = EBUSY;
401                         mtx_unlock(&offload_db_lock);
402                         break;
403                 }
404                 mtx_unlock(&offload_db_lock);
405                 mtx_destroy(&offload_db_lock);
406                 break;
407         case MOD_SHUTDOWN:
408                 break;
409         default:
410                 err = EOPNOTSUPP;
411                 break;
412         }
413
414         return (err);
415 }
416
417
418 static moduledata_t mod_data= {
419         "toecore",
420         toecore_load,
421         0
422 };
423
424 MODULE_VERSION(toecore, 1);
425 DECLARE_MODULE(toecore, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);