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