aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/netdev.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2008-12-20 19:57:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:18 -0500
commitce6cde92803e961d95ddacdf74bd8b067f82f7d4 (patch)
tree5bdbfa6448e0bb1d0795da8fa222b16ea2b2736c /drivers/net/wimax/i2400m/netdev.c
parent024f7f31ed15c471f80408d8b5045497e27e1135 (diff)
i2400m: linkage to the networking stack
Implementation of the glue to the network stack so the WiMAX device shows up as an Ethernet device. Initially we shot for implementing a Pure IP device -- however, the world seems to turn around Ethernet devices. Main issues were with the ISC DHCP client and servers (as they don't understand types other than Ethernet and Token Ring). We proceeded to register with IANA the PureIP hw type, so that DHCP requests could declare such. We also created patches to the main ISC DHCP versions to support it. However, until all that permeates into deployments, there is going to be a long time. So we moved back to wrap Ethernet frames around the PureIP device. At the time being this has overhead; we need to reallocate with space for an Ethernet header. The reason is the device-to-host protocol coalesces many network packets into a single message, so we can't introduce Ethernet headers without overwriting valid data from other packets. Coming-soon versions of the firmware have this issue solved. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/net/wimax/i2400m/netdev.c')
-rw-r--r--drivers/net/wimax/i2400m/netdev.c524
1 files changed, 524 insertions, 0 deletions
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
new file mode 100644
index 000000000000..63fe708e8a31
--- /dev/null
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -0,0 +1,524 @@
1/*
2 * Intel Wireless WiMAX Connection 2400m
3 * Glue with the networking stack
4 *
5 *
6 * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
7 * Yanir Lubetkin <yanirx.lubetkin@intel.com>
8 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License version
12 * 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 *
24 *
25 * This implements an ethernet device for the i2400m.
26 *
27 * We fake being an ethernet device to simplify the support from user
28 * space and from the other side. The world is (sadly) configured to
29 * take in only Ethernet devices...
30 *
31 * Because of this, currently there is an copy-each-rxed-packet
32 * overhead on the RX path. Each IP packet has to be reallocated to
33 * add an ethernet header (as there is no space in what we get from
34 * the device). This is a known drawback and coming versions of the
35 * device's firmware are being changed to add header space that can be
36 * used to insert the ethernet header without having to reallocate and
37 * copy.
38 *
39 * TX error handling is tricky; because we have to FIFO/queue the
40 * buffers for transmission (as the hardware likes it aggregated), we
41 * just give the skb to the TX subsystem and by the time it is
42 * transmitted, we have long forgotten about it. So we just don't care
43 * too much about it.
44 *
45 * Note that when the device is in idle mode with the basestation, we
46 * need to negotiate coming back up online. That involves negotiation
47 * and possible user space interaction. Thus, we defer to a workqueue
48 * to do all that. By default, we only queue a single packet and drop
49 * the rest, as potentially the time to go back from idle to normal is
50 * long.
51 *
52 * ROADMAP
53 *
54 * i2400m_open Called on ifconfig up
55 * i2400m_stop Called on ifconfig down
56 *
57 * i2400m_hard_start_xmit Called by the network stack to send a packet
58 * i2400m_net_wake_tx Wake up device from basestation-IDLE & TX
59 * i2400m_wake_tx_work
60 * i2400m_cmd_exit_idle
61 * i2400m_tx
62 * i2400m_net_tx TX a data frame
63 * i2400m_tx
64 *
65 * i2400m_change_mtu Called on ifconfig mtu XXX
66 *
67 * i2400m_tx_timeout Called when the device times out
68 *
69 * i2400m_net_rx Called by the RX code when a data frame is
70 * available.
71 * i2400m_netdev_setup Called to setup all the netdev stuff from
72 * alloc_netdev.
73 */
74#include <linux/if_arp.h>
75#include <linux/netdevice.h>
76#include "i2400m.h"
77
78
79#define D_SUBMODULE netdev
80#include "debug-levels.h"
81
82enum {
83/* netdev interface */
84 /*
85 * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
86 *
87 * The MTU is 1400 or less
88 */
89 I2400M_MAX_MTU = 1400,
90 I2400M_TX_TIMEOUT = HZ,
91 I2400M_TX_QLEN = 5,
92};
93
94
95static
96int i2400m_open(struct net_device *net_dev)
97{
98 int result;
99 struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
100 struct device *dev = i2400m_dev(i2400m);
101
102 d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
103 if (i2400m->ready == 0) {
104 dev_err(dev, "Device is still initializing\n");
105 result = -EBUSY;
106 } else
107 result = 0;
108 d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
109 net_dev, i2400m, result);
110 return result;
111}
112
113
114/*
115 *
116 * On kernel versions where cancel_work_sync() didn't return anything,
117 * we rely on wake_tx_skb() being non-NULL.
118 */
119static
120int i2400m_stop(struct net_device *net_dev)
121{
122 struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
123 struct device *dev = i2400m_dev(i2400m);
124
125 d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
126 /* See i2400m_hard_start_xmit(), references are taken there
127 * and here we release them if the work was still
128 * pending. Note we can't differentiate work not pending vs
129 * never scheduled, so the NULL check does that. */
130 if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
131 && i2400m->wake_tx_skb != NULL) {
132 unsigned long flags;
133 struct sk_buff *wake_tx_skb;
134 spin_lock_irqsave(&i2400m->tx_lock, flags);
135 wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
136 i2400m->wake_tx_skb = NULL; /* compat help */
137 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
138 i2400m_put(i2400m);
139 kfree_skb(wake_tx_skb);
140 }
141 d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m);
142 return 0;
143}
144
145
146/*
147 * Wake up the device and transmit a held SKB, then restart the net queue
148 *
149 * When the device goes into basestation-idle mode, we need to tell it
150 * to exit that mode; it will negotiate with the base station, user
151 * space may have to intervene to rehandshake crypto and then tell us
152 * when it is ready to transmit the packet we have "queued". Still we
153 * need to give it sometime after it reports being ok.
154 *
155 * On error, there is not much we can do. If the error was on TX, we
156 * still wake the queue up to see if the next packet will be luckier.
157 *
158 * If _cmd_exit_idle() fails...well, it could be many things; most
159 * commonly it is that something else took the device out of IDLE mode
160 * (for example, the base station). In that case we get an -EILSEQ and
161 * we are just going to ignore that one. If the device is back to
162 * connected, then fine -- if it is someother state, the packet will
163 * be dropped anyway.
164 */
165void i2400m_wake_tx_work(struct work_struct *ws)
166{
167 int result;
168 struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
169 struct device *dev = i2400m_dev(i2400m);
170 struct sk_buff *skb = i2400m->wake_tx_skb;
171 unsigned long flags;
172
173 spin_lock_irqsave(&i2400m->tx_lock, flags);
174 skb = i2400m->wake_tx_skb;
175 i2400m->wake_tx_skb = NULL;
176 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
177
178 d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb);
179 result = -EINVAL;
180 if (skb == NULL) {
181 dev_err(dev, "WAKE&TX: skb dissapeared!\n");
182 goto out_put;
183 }
184 result = i2400m_cmd_exit_idle(i2400m);
185 if (result == -EILSEQ)
186 result = 0;
187 if (result < 0) {
188 dev_err(dev, "WAKE&TX: device didn't get out of idle: "
189 "%d\n", result);
190 goto error;
191 }
192 result = wait_event_timeout(i2400m->state_wq,
193 i2400m->state != I2400M_SS_IDLE, 5 * HZ);
194 if (result == 0)
195 result = -ETIMEDOUT;
196 if (result < 0) {
197 dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
198 "%d\n", result);
199 goto error;
200 }
201 msleep(20); /* device still needs some time or it drops it */
202 result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
203 netif_wake_queue(i2400m->wimax_dev.net_dev);
204error:
205 kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */
206out_put:
207 i2400m_put(i2400m);
208 d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n",
209 ws, i2400m, skb, result);
210}
211
212
213/*
214 * Prepare the data payload TX header
215 *
216 * The i2400m expects a 4 byte header in front of a data packet.
217 *
218 * Because we pretend to be an ethernet device, this packet comes with
219 * an ethernet header. Pull it and push our header.
220 */
221static
222void i2400m_tx_prep_header(struct sk_buff *skb)
223{
224 struct i2400m_pl_data_hdr *pl_hdr;
225 skb_pull(skb, ETH_HLEN);
226 pl_hdr = (struct i2400m_pl_data_hdr *) skb_push(skb, sizeof(*pl_hdr));
227 pl_hdr->reserved = 0;
228}
229
230
231/*
232 * TX an skb to an idle device
233 *
234 * When the device is in basestation-idle mode, we need to wake it up
235 * and then TX. So we queue a work_struct for doing so.
236 *
237 * We need to get an extra ref for the skb (so it is not dropped), as
238 * well as be careful not to queue more than one request (won't help
239 * at all). If more than one request comes or there are errors, we
240 * just drop the packets (see i2400m_hard_start_xmit()).
241 */
242static
243int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
244 struct sk_buff *skb)
245{
246 int result;
247 struct device *dev = i2400m_dev(i2400m);
248 unsigned long flags;
249
250 d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
251 if (net_ratelimit()) {
252 d_printf(3, dev, "WAKE&NETTX: "
253 "skb %p sending %d bytes to radio\n",
254 skb, skb->len);
255 d_dump(4, dev, skb->data, skb->len);
256 }
257 /* We hold a ref count for i2400m and skb, so when
258 * stopping() the device, we need to cancel that work
259 * and if pending, release those resources. */
260 result = 0;
261 spin_lock_irqsave(&i2400m->tx_lock, flags);
262 if (!work_pending(&i2400m->wake_tx_ws)) {
263 netif_stop_queue(net_dev);
264 i2400m_get(i2400m);
265 i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */
266 i2400m_tx_prep_header(skb);
267 result = schedule_work(&i2400m->wake_tx_ws);
268 WARN_ON(result == 0);
269 }
270 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
271 if (result == 0) {
272 /* Yes, this happens even if we stopped the
273 * queue -- blame the queue disciplines that
274 * queue without looking -- I guess there is a reason
275 * for that. */
276 if (net_ratelimit())
277 d_printf(1, dev, "NETTX: device exiting idle, "
278 "dropping skb %p, queue running %d\n",
279 skb, netif_queue_stopped(net_dev));
280 result = -EBUSY;
281 }
282 d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
283 return result;
284}
285
286
287/*
288 * Transmit a packet to the base station on behalf of the network stack.
289 *
290 * Returns: 0 if ok, < 0 errno code on error.
291 *
292 * We need to pull the ethernet header and add the hardware header,
293 * which is currently set to all zeroes and reserved.
294 */
295static
296int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev,
297 struct sk_buff *skb)
298{
299 int result;
300 struct device *dev = i2400m_dev(i2400m);
301
302 d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n",
303 i2400m, net_dev, skb);
304 /* FIXME: check eth hdr, only IPv4 is routed by the device as of now */
305 net_dev->trans_start = jiffies;
306 i2400m_tx_prep_header(skb);
307 d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n",
308 skb, skb->len);
309 d_dump(4, dev, skb->data, skb->len);
310 result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
311 d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n",
312 i2400m, net_dev, skb, result);
313 return result;
314}
315
316
317/*
318 * Transmit a packet to the base station on behalf of the network stack
319 *
320 *
321 * Returns: NETDEV_TX_OK (always, even in case of error)
322 *
323 * In case of error, we just drop it. Reasons:
324 *
325 * - we add a hw header to each skb, and if the network stack
326 * retries, we have no way to know if that skb has it or not.
327 *
328 * - network protocols have their own drop-recovery mechanisms
329 *
330 * - there is not much else we can do
331 *
332 * If the device is idle, we need to wake it up; that is an operation
333 * that will sleep. See i2400m_net_wake_tx() for details.
334 */
335static
336int i2400m_hard_start_xmit(struct sk_buff *skb,
337 struct net_device *net_dev)
338{
339 int result;
340 struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
341 struct device *dev = i2400m_dev(i2400m);
342
343 d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
344 if (i2400m->state == I2400M_SS_IDLE)
345 result = i2400m_net_wake_tx(i2400m, net_dev, skb);
346 else
347 result = i2400m_net_tx(i2400m, net_dev, skb);
348 if (result < 0)
349 net_dev->stats.tx_dropped++;
350 else {
351 net_dev->stats.tx_packets++;
352 net_dev->stats.tx_bytes += skb->len;
353 }
354 kfree_skb(skb);
355 result = NETDEV_TX_OK;
356 d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
357 return result;
358}
359
360
361static
362int i2400m_change_mtu(struct net_device *net_dev, int new_mtu)
363{
364 int result;
365 struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
366 struct device *dev = i2400m_dev(i2400m);
367
368 if (new_mtu >= I2400M_MAX_MTU) {
369 dev_err(dev, "Cannot change MTU to %d (max is %d)\n",
370 new_mtu, I2400M_MAX_MTU);
371 result = -EINVAL;
372 } else {
373 net_dev->mtu = new_mtu;
374 result = 0;
375 }
376 return result;
377}
378
379
380static
381void i2400m_tx_timeout(struct net_device *net_dev)
382{
383 /*
384 * We might want to kick the device
385 *
386 * There is not much we can do though, as the device requires
387 * that we send the data aggregated. By the time we receive
388 * this, there might be data pending to be sent or not...
389 */
390 net_dev->stats.tx_errors++;
391 return;
392}
393
394
395/*
396 * Create a fake ethernet header
397 *
398 * For emulating an ethernet device, every received IP header has to
399 * be prefixed with an ethernet header.
400 *
401 * What we receive has (potentially) many IP packets concatenated with
402 * no ETH_HLEN bytes prefixed. Thus there is no space for an eth
403 * header.
404 *
405 * We would have to reallocate or do ugly fragment tricks in order to
406 * add it.
407 *
408 * But what we do is use the header space of the RX transaction
409 * (*msg_hdr) as we don't need it anymore; then we'll point all the
410 * data skbs there, as they share the same backing store.
411 *
412 * We only support IPv4 for v3 firmware.
413 */
414static
415void i2400m_rx_fake_eth_header(struct net_device *net_dev,
416 void *_eth_hdr)
417{
418 struct ethhdr *eth_hdr = _eth_hdr;
419
420 memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
421 memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
422 eth_hdr->h_proto = __constant_cpu_to_be16(ETH_P_IP);
423}
424
425
426/*
427 * i2400m_net_rx - pass a network packet to the stack
428 *
429 * @i2400m: device instance
430 * @skb_rx: the skb where the buffer pointed to by @buf is
431 * @i: 1 if payload is the only one
432 * @buf: pointer to the buffer containing the data
433 * @len: buffer's length
434 *
435 * We just clone the skb and set it up so that it's skb->data pointer
436 * points to "buf" and it's length.
437 *
438 * Note that if the payload is the last (or the only one) in a
439 * multi-payload message, we don't clone the SKB but just reuse it.
440 *
441 * This function is normally run from a thread context. However, we
442 * still use netif_rx() instead of netif_receive_skb() as was
443 * recommended in the mailing list. Reason is in some stress tests
444 * when sending/receiving a lot of data we seem to hit a softlock in
445 * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
446 * netif_rx() took care of the issue.
447 *
448 * This is, of course, still open to do more research on why running
449 * with netif_receive_skb() hits this softlock. FIXME.
450 *
451 * FIXME: currently we don't do any efforts at distinguishing if what
452 * we got was an IPv4 or IPv6 header, to setup the protocol field
453 * correctly.
454 */
455void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
456 unsigned i, const void *buf, int buf_len)
457{
458 struct net_device *net_dev = i2400m->wimax_dev.net_dev;
459 struct device *dev = i2400m_dev(i2400m);
460 struct sk_buff *skb;
461
462 d_fnstart(2, dev, "(i2400m %p buf %p buf_len %d)\n",
463 i2400m, buf, buf_len);
464 if (i) {
465 skb = skb_get(skb_rx);
466 d_printf(2, dev, "RX: reusing first payload skb %p\n", skb);
467 skb_pull(skb, buf - (void *) skb->data);
468 skb_trim(skb, (void *) skb_end_pointer(skb) - buf);
469 } else {
470 /* Yes, this is bad -- a lot of overhead -- see
471 * comments at the top of the file */
472 skb = __netdev_alloc_skb(net_dev, buf_len, GFP_KERNEL);
473 if (skb == NULL) {
474 dev_err(dev, "NETRX: no memory to realloc skb\n");
475 net_dev->stats.rx_dropped++;
476 goto error_skb_realloc;
477 }
478 memcpy(skb_put(skb, buf_len), buf, buf_len);
479 }
480 i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
481 skb->data - ETH_HLEN);
482 skb_set_mac_header(skb, -ETH_HLEN);
483 skb->dev = i2400m->wimax_dev.net_dev;
484 skb->protocol = htons(ETH_P_IP);
485 net_dev->stats.rx_packets++;
486 net_dev->stats.rx_bytes += buf_len;
487 d_printf(3, dev, "NETRX: receiving %d bytes to network stack\n",
488 buf_len);
489 d_dump(4, dev, buf, buf_len);
490 netif_rx_ni(skb); /* see notes in function header */
491error_skb_realloc:
492 d_fnend(2, dev, "(i2400m %p buf %p buf_len %d) = void\n",
493 i2400m, buf, buf_len);
494}
495
496
497/**
498 * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data
499 *
500 * Called by alloc_netdev()
501 */
502void i2400m_netdev_setup(struct net_device *net_dev)
503{
504 d_fnstart(3, NULL, "(net_dev %p)\n", net_dev);
505 ether_setup(net_dev);
506 net_dev->mtu = I2400M_MAX_MTU;
507 net_dev->tx_queue_len = I2400M_TX_QLEN;
508 net_dev->features =
509 NETIF_F_VLAN_CHALLENGED
510 | NETIF_F_HIGHDMA;
511 net_dev->flags =
512 IFF_NOARP /* i2400m is apure IP device */
513 & (~IFF_BROADCAST /* i2400m is P2P */
514 & ~IFF_MULTICAST);
515 net_dev->watchdog_timeo = I2400M_TX_TIMEOUT;
516 net_dev->open = i2400m_open;
517 net_dev->stop = i2400m_stop;
518 net_dev->hard_start_xmit = i2400m_hard_start_xmit;
519 net_dev->change_mtu = i2400m_change_mtu;
520 net_dev->tx_timeout = i2400m_tx_timeout;
521 d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev);
522}
523EXPORT_SYMBOL_GPL(i2400m_netdev_setup);
524