aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wimax/i2400m/control.c9
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h2
-rw-r--r--drivers/net/wimax/i2400m/netdev.c104
-rw-r--r--drivers/net/wimax/i2400m/rx.c117
-rw-r--r--include/linux/wimax/i2400m.h35
5 files changed, 234 insertions, 33 deletions
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index c3968b240d6..4073c3e93bd 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -1311,6 +1311,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
1311 struct device *dev = i2400m_dev(i2400m); 1311 struct device *dev = i2400m_dev(i2400m);
1312 struct i2400m_tlv_config_idle_parameters idle_params; 1312 struct i2400m_tlv_config_idle_parameters idle_params;
1313 struct i2400m_tlv_config_idle_timeout idle_timeout; 1313 struct i2400m_tlv_config_idle_timeout idle_timeout;
1314 struct i2400m_tlv_config_d2h_data_format df;
1314 const struct i2400m_tlv_hdr *args[9]; 1315 const struct i2400m_tlv_hdr *args[9];
1315 unsigned argc = 0; 1316 unsigned argc = 0;
1316 1317
@@ -1333,6 +1334,14 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
1333 args[argc++] = &idle_timeout.hdr; 1334 args[argc++] = &idle_timeout.hdr;
1334 } 1335 }
1335 } 1336 }
1337 if (i2400m_ge_v1_4(i2400m)) {
1338 df.hdr.type =
1339 cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT);
1340 df.hdr.length = cpu_to_le16(
1341 sizeof(df) - sizeof(df.hdr));
1342 df.format = 1;
1343 args[argc++] = &df.hdr;
1344 }
1336 result = i2400m_set_init_config(i2400m, args, argc); 1345 result = i2400m_set_init_config(i2400m, args, argc);
1337 if (result < 0) 1346 if (result < 0)
1338 goto error; 1347 goto error;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 0c60d5c4300..125c30594e6 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -593,6 +593,8 @@ extern void i2400m_tx_release(struct i2400m *);
593 593
594extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned, 594extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
595 const void *, int); 595 const void *, int);
596extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
597 enum i2400m_cs);
596enum i2400m_pt; 598enum i2400m_pt;
597extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt); 599extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);
598 600
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index be8be4d0709..2bdd0cdbb31 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -28,13 +28,12 @@
28 * space and from the other side. The world is (sadly) configured to 28 * space and from the other side. The world is (sadly) configured to
29 * take in only Ethernet devices... 29 * take in only Ethernet devices...
30 * 30 *
31 * Because of this, currently there is an copy-each-rxed-packet 31 * Because of this, when using firmwares <= v1.3, there is an
32 * overhead on the RX path. Each IP packet has to be reallocated to 32 * copy-each-rxed-packet overhead on the RX path. Each IP packet has
33 * add an ethernet header (as there is no space in what we get from 33 * to be reallocated to add an ethernet header (as there is no space
34 * the device). This is a known drawback and coming versions of the 34 * in what we get from the device). This is a known drawback and
35 * device's firmware are being changed to add header space that can be 35 * firmwares >= 1.4 add header space that can be used to insert the
36 * used to insert the ethernet header without having to reallocate and 36 * ethernet header without having to reallocate and copy.
37 * copy.
38 * 37 *
39 * TX error handling is tricky; because we have to FIFO/queue the 38 * TX error handling is tricky; because we have to FIFO/queue the
40 * buffers for transmission (as the hardware likes it aggregated), we 39 * buffers for transmission (as the hardware likes it aggregated), we
@@ -67,7 +66,9 @@
67 * i2400m_tx_timeout Called when the device times out 66 * i2400m_tx_timeout Called when the device times out
68 * 67 *
69 * i2400m_net_rx Called by the RX code when a data frame is 68 * i2400m_net_rx Called by the RX code when a data frame is
70 * available. 69 * available (firmware <= 1.3)
70 * i2400m_net_erx Called by the RX code when a data frame is
71 * available (firmware >= 1.4).
71 * i2400m_netdev_setup Called to setup all the netdev stuff from 72 * i2400m_netdev_setup Called to setup all the netdev stuff from
72 * alloc_netdev. 73 * alloc_netdev.
73 */ 74 */
@@ -396,30 +397,18 @@ void i2400m_tx_timeout(struct net_device *net_dev)
396 * Create a fake ethernet header 397 * Create a fake ethernet header
397 * 398 *
398 * For emulating an ethernet device, every received IP header has to 399 * For emulating an ethernet device, every received IP header has to
399 * be prefixed with an ethernet header. 400 * be prefixed with an ethernet header. Fake it with the given
400 * 401 * protocol.
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 */ 402 */
414static 403static
415void i2400m_rx_fake_eth_header(struct net_device *net_dev, 404void i2400m_rx_fake_eth_header(struct net_device *net_dev,
416 void *_eth_hdr) 405 void *_eth_hdr, int protocol)
417{ 406{
418 struct ethhdr *eth_hdr = _eth_hdr; 407 struct ethhdr *eth_hdr = _eth_hdr;
419 408
420 memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); 409 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)); 410 memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
422 eth_hdr->h_proto = cpu_to_be16(ETH_P_IP); 411 eth_hdr->h_proto = cpu_to_be16(protocol);
423} 412}
424 413
425 414
@@ -432,6 +421,13 @@ void i2400m_rx_fake_eth_header(struct net_device *net_dev,
432 * @buf: pointer to the buffer containing the data 421 * @buf: pointer to the buffer containing the data
433 * @len: buffer's length 422 * @len: buffer's length
434 * 423 *
424 * This is only used now for the v1.3 firmware. It will be deprecated
425 * in >= 2.6.31.
426 *
427 * Note that due to firmware limitations, we don't have space to add
428 * an ethernet header, so we need to copy each packet. Firmware
429 * versions >= v1.4 fix this [see i2400m_net_erx()].
430 *
435 * We just clone the skb and set it up so that it's skb->data pointer 431 * We just clone the skb and set it up so that it's skb->data pointer
436 * points to "buf" and it's length. 432 * points to "buf" and it's length.
437 * 433 *
@@ -478,7 +474,7 @@ void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
478 memcpy(skb_put(skb, buf_len), buf, buf_len); 474 memcpy(skb_put(skb, buf_len), buf, buf_len);
479 } 475 }
480 i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, 476 i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
481 skb->data - ETH_HLEN); 477 skb->data - ETH_HLEN, ETH_P_IP);
482 skb_set_mac_header(skb, -ETH_HLEN); 478 skb_set_mac_header(skb, -ETH_HLEN);
483 skb->dev = i2400m->wimax_dev.net_dev; 479 skb->dev = i2400m->wimax_dev.net_dev;
484 skb->protocol = htons(ETH_P_IP); 480 skb->protocol = htons(ETH_P_IP);
@@ -493,6 +489,64 @@ error_skb_realloc:
493 i2400m, buf, buf_len); 489 i2400m, buf, buf_len);
494} 490}
495 491
492
493/*
494 * i2400m_net_erx - pass a network packet to the stack (extended version)
495 *
496 * @i2400m: device descriptor
497 * @skb: the skb where the packet is - the skb should be set to point
498 * at the IP packet; this function will add ethernet headers if
499 * needed.
500 * @cs: packet type
501 *
502 * This is only used now for firmware >= v1.4. Note it is quite
503 * similar to i2400m_net_rx() (used only for v1.3 firmware).
504 *
505 * This function is normally run from a thread context. However, we
506 * still use netif_rx() instead of netif_receive_skb() as was
507 * recommended in the mailing list. Reason is in some stress tests
508 * when sending/receiving a lot of data we seem to hit a softlock in
509 * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
510 * netif_rx() took care of the issue.
511 *
512 * This is, of course, still open to do more research on why running
513 * with netif_receive_skb() hits this softlock. FIXME.
514 */
515void i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb,
516 enum i2400m_cs cs)
517{
518 struct net_device *net_dev = i2400m->wimax_dev.net_dev;
519 struct device *dev = i2400m_dev(i2400m);
520 int protocol;
521
522 d_fnstart(2, dev, "(i2400m %p skb %p [%zu] cs %d)\n",
523 i2400m, skb, skb->len, cs);
524 switch(cs) {
525 case I2400M_CS_IPV4_0:
526 case I2400M_CS_IPV4:
527 protocol = ETH_P_IP;
528 i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
529 skb->data - ETH_HLEN, ETH_P_IP);
530 skb_set_mac_header(skb, -ETH_HLEN);
531 skb->dev = i2400m->wimax_dev.net_dev;
532 skb->protocol = htons(ETH_P_IP);
533 net_dev->stats.rx_packets++;
534 net_dev->stats.rx_bytes += skb->len;
535 break;
536 default:
537 dev_err(dev, "ERX: BUG? CS type %u unsupported\n", cs);
538 goto error;
539
540 }
541 d_printf(3, dev, "ERX: receiving %d bytes to the network stack\n",
542 skb->len);
543 d_dump(4, dev, skb->data, skb->len);
544 netif_rx_ni(skb); /* see notes in function header */
545error:
546 d_fnend(2, dev, "(i2400m %p skb %p [%zu] cs %d) = void\n",
547 i2400m, skb, skb->len, cs);
548}
549
496static const struct net_device_ops i2400m_netdev_ops = { 550static const struct net_device_ops i2400m_netdev_ops = {
497 .ndo_open = i2400m_open, 551 .ndo_open = i2400m_open,
498 .ndo_stop = i2400m_stop, 552 .ndo_stop = i2400m_stop,
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index c62b8c56416..cd525066d4b 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -69,6 +69,22 @@
69 * See tx.c for a deeper description on alignment requirements and 69 * See tx.c for a deeper description on alignment requirements and
70 * other fun facts of it. 70 * other fun facts of it.
71 * 71 *
72 * DATA PACKETS
73 *
74 * In firmwares <= v1.3, data packets have no header for RX, but they
75 * do for TX (currently unused).
76 *
77 * In firmware >= 1.4, RX packets have an extended header (16
78 * bytes). This header conveys information for management of host
79 * reordering of packets (the device offloads storage of the packets
80 * for reordering to the host).
81 *
82 * Currently this information is not used as the current code doesn't
83 * enable host reordering.
84 *
85 * The header is used as dummy space to emulate an ethernet header and
86 * thus be able to act as an ethernet device without having to reallocate.
87 *
72 * ROADMAP 88 * ROADMAP
73 * 89 *
74 * i2400m_rx 90 * i2400m_rx
@@ -76,6 +92,8 @@
76 * i2400m_rx_pl_descr_check 92 * i2400m_rx_pl_descr_check
77 * i2400m_rx_payload 93 * i2400m_rx_payload
78 * i2400m_net_rx 94 * i2400m_net_rx
95 * i2400m_rx_edata
96 * i2400m_net_erx
79 * i2400m_rx_ctl 97 * i2400m_rx_ctl
80 * i2400m_msg_size_check 98 * i2400m_msg_size_check
81 * i2400m_report_hook_work [in a workqueue] 99 * i2400m_report_hook_work [in a workqueue]
@@ -264,8 +282,6 @@ error_check:
264} 282}
265 283
266 284
267
268
269/* 285/*
270 * Receive and send up a trace 286 * Receive and send up a trace
271 * 287 *
@@ -314,32 +330,112 @@ error_check:
314 return; 330 return;
315} 331}
316 332
333/*
334 * Receive and send up an extended data packet
335 *
336 * @i2400m: device descriptor
337 * @skb_rx: skb that contains the extended data packet
338 * @single_last: 1 if the payload is the only one or the last one of
339 * the skb.
340 * @payload: pointer to the packet's data inside the skb
341 * @size: size of the payload
342 *
343 * Starting in v1.4 of the i2400m's firmware, the device can send data
344 * packets to the host in an extended format that; this incudes a 16
345 * byte header (struct i2400m_pl_edata_hdr). Using this header's space
346 * we can fake ethernet headers for ethernet device emulation without
347 * having to copy packets around.
348 *
349 * This function handles said path.
350 */
351static
352void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
353 unsigned single_last, const void *payload, size_t size)
354{
355 struct device *dev = i2400m_dev(i2400m);
356 const struct i2400m_pl_edata_hdr *hdr = payload;
357 struct net_device *net_dev = i2400m->wimax_dev.net_dev;
358 struct sk_buff *skb;
359 enum i2400m_cs cs;
360 unsigned reorder_needed;
361
362 d_fnstart(4, dev, "(i2400m %p skb_rx %p single %u payload %p "
363 "size %zu)\n", i2400m, skb_rx, single_last, payload, size);
364 if (size < sizeof(*hdr)) {
365 dev_err(dev, "ERX: HW BUG? message with short header (%zu "
366 "vs %zu bytes expected)\n", size, sizeof(*hdr));
367 goto error;
368 }
369 reorder_needed = le32_to_cpu(hdr->reorder & I2400M_REORDER_NEEDED);
370 cs = hdr->cs;
371 if (reorder_needed) {
372 dev_err(dev, "ERX: HW BUG? reorder needed, it was disabled\n");
373 goto error;
374 }
375 /* ok, so now decide if we want to clone or reuse the skb,
376 * pull and trim it so the beginning is the space for the eth
377 * header and pass it to i2400m_net_erx() for the stack */
378 if (single_last) {
379 skb = skb_get(skb_rx);
380 d_printf(3, dev, "ERX: reusing single payload skb %p\n", skb);
381 } else {
382 skb = skb_clone(skb_rx, GFP_KERNEL);
383 d_printf(3, dev, "ERX: cloning %p\n", skb);
384 if (skb == NULL) {
385 dev_err(dev, "ERX: no memory to clone skb\n");
386 net_dev->stats.rx_dropped++;
387 goto error_skb_clone;
388 }
389 }
390 /* now we have to pull and trim so that the skb points to the
391 * beginning of the IP packet; the netdev part will add the
392 * ethernet header as needed. */
393 BUILD_BUG_ON(ETH_HLEN > sizeof(*hdr));
394 skb_pull(skb, payload + sizeof(*hdr) - (void *) skb->data);
395 skb_trim(skb, (void *) skb_end_pointer(skb) - payload + sizeof(*hdr));
396 i2400m_net_erx(i2400m, skb, cs);
397error_skb_clone:
398error:
399 d_fnend(4, dev, "(i2400m %p skb_rx %p single %u payload %p "
400 "size %zu) = void\n", i2400m, skb_rx, single_last, payload, size);
401 return;
402}
403
404
405
317 406
318/* 407/*
319 * Act on a received payload 408 * Act on a received payload
320 * 409 *
321 * @i2400m: device instance 410 * @i2400m: device instance
322 * @skb_rx: skb where the transaction was received 411 * @skb_rx: skb where the transaction was received
323 * @single: 1 if there is only one payload, 0 otherwise 412 * @single_last: 1 this is the only payload or the last one (so the
413 * skb can be reused instead of cloned).
324 * @pld: payload descriptor 414 * @pld: payload descriptor
325 * @payload: payload data 415 * @payload: payload data
326 * 416 *
327 * Upon reception of a payload, look at its guts in the payload 417 * Upon reception of a payload, look at its guts in the payload
328 * descriptor and decide what to do with it. 418 * descriptor and decide what to do with it. If it is a single payload
419 * skb or if the last skb is a data packet, the skb will be referenced
420 * and modified (so it doesn't have to be cloned).
329 */ 421 */
330static 422static
331void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx, 423void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx,
332 unsigned single, const struct i2400m_pld *pld, 424 unsigned single_last, const struct i2400m_pld *pld,
333 const void *payload) 425 const void *payload)
334{ 426{
335 struct device *dev = i2400m_dev(i2400m); 427 struct device *dev = i2400m_dev(i2400m);
336 size_t pl_size = i2400m_pld_size(pld); 428 size_t pl_size = i2400m_pld_size(pld);
337 enum i2400m_pt pl_type = i2400m_pld_type(pld); 429 enum i2400m_pt pl_type = i2400m_pld_type(pld);
338 430
431 d_printf(7, dev, "RX: received payload type %u, %zu bytes\n",
432 pl_type, pl_size);
433 d_dump(8, dev, payload, pl_size);
434
339 switch (pl_type) { 435 switch (pl_type) {
340 case I2400M_PT_DATA: 436 case I2400M_PT_DATA:
341 d_printf(3, dev, "RX: data payload %zu bytes\n", pl_size); 437 d_printf(3, dev, "RX: data payload %zu bytes\n", pl_size);
342 i2400m_net_rx(i2400m, skb_rx, single, payload, pl_size); 438 i2400m_net_rx(i2400m, skb_rx, single_last, payload, pl_size);
343 break; 439 break;
344 case I2400M_PT_CTRL: 440 case I2400M_PT_CTRL:
345 i2400m_rx_ctl(i2400m, skb_rx, payload, pl_size); 441 i2400m_rx_ctl(i2400m, skb_rx, payload, pl_size);
@@ -347,6 +443,10 @@ void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx,
347 case I2400M_PT_TRACE: 443 case I2400M_PT_TRACE:
348 i2400m_rx_trace(i2400m, payload, pl_size); 444 i2400m_rx_trace(i2400m, payload, pl_size);
349 break; 445 break;
446 case I2400M_PT_EDATA:
447 d_printf(3, dev, "ERX: data payload %zu bytes\n", pl_size);
448 i2400m_rx_edata(i2400m, skb_rx, single_last, payload, pl_size);
449 break;
350 default: /* Anything else shouldn't come to the host */ 450 default: /* Anything else shouldn't come to the host */
351 if (printk_ratelimit()) 451 if (printk_ratelimit())
352 dev_err(dev, "RX: HW BUG? unexpected payload type %u\n", 452 dev_err(dev, "RX: HW BUG? unexpected payload type %u\n",
@@ -474,7 +574,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
474 const struct i2400m_msg_hdr *msg_hdr; 574 const struct i2400m_msg_hdr *msg_hdr;
475 size_t pl_itr, pl_size, skb_len; 575 size_t pl_itr, pl_size, skb_len;
476 unsigned long flags; 576 unsigned long flags;
477 unsigned num_pls; 577 unsigned num_pls, single_last;
478 578
479 skb_len = skb->len; 579 skb_len = skb->len;
480 d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n", 580 d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n",
@@ -503,7 +603,8 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
503 pl_itr, skb->len); 603 pl_itr, skb->len);
504 if (result < 0) 604 if (result < 0)
505 goto error_pl_descr_check; 605 goto error_pl_descr_check;
506 i2400m_rx_payload(i2400m, skb, num_pls == 1, &msg_hdr->pld[i], 606 single_last = num_pls == 1 || i == num_pls - 1;
607 i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i],
507 skb->data + pl_itr); 608 skb->data + pl_itr);
508 pl_itr += ALIGN(pl_size, I2400M_PL_PAD); 609 pl_itr += ALIGN(pl_size, I2400M_PL_PAD);
509 cond_resched(); /* Don't monopolize */ 610 cond_resched(); /* Don't monopolize */
diff --git a/include/linux/wimax/i2400m.h b/include/linux/wimax/i2400m.h
index 686eeb2b970..ad36e073a70 100644
--- a/include/linux/wimax/i2400m.h
+++ b/include/linux/wimax/i2400m.h
@@ -207,6 +207,7 @@ enum i2400m_pt {
207 I2400M_PT_TRACE, /* For device debug */ 207 I2400M_PT_TRACE, /* For device debug */
208 I2400M_PT_RESET_WARM, /* device reset */ 208 I2400M_PT_RESET_WARM, /* device reset */
209 I2400M_PT_RESET_COLD, /* USB[transport] reset, like reconnect */ 209 I2400M_PT_RESET_COLD, /* USB[transport] reset, like reconnect */
210 I2400M_PT_EDATA, /* Extended RX data */
210 I2400M_PT_ILLEGAL 211 I2400M_PT_ILLEGAL
211}; 212};
212 213
@@ -221,6 +222,32 @@ struct i2400m_pl_data_hdr {
221} __attribute__((packed)); 222} __attribute__((packed));
222 223
223 224
225/*
226 * Payload for an extended data packet
227 *
228 * New in v1.4
229 *
230 * @cs: the type of data in the packet, as defined per (802.16e
231 * T11.13.19.1). Currently only 2 (IPv4 packet) supported.
232 *
233 * This is prefixed to each and every INCOMING DATA packet.
234 */
235struct i2400m_pl_edata_hdr {
236 __le32 reorder;
237 __u8 cs;
238 __u8 reserved[11];
239} __attribute__((packed));
240
241enum i2400m_cs {
242 I2400M_CS_IPV4_0 = 0,
243 I2400M_CS_IPV4 = 2,
244};
245
246enum i2400m_reorder {
247 I2400M_REORDER_NEEDED = 0x01,
248};
249
250
224/* Misc constants */ 251/* Misc constants */
225enum { 252enum {
226 I2400M_PL_PAD = 16, /* Payload data size alignment */ 253 I2400M_PL_PAD = 16, /* Payload data size alignment */
@@ -382,6 +409,7 @@ enum i2400m_tlv {
382 I2400M_TLV_DEVICE_RESET_TYPE = 132, 409 I2400M_TLV_DEVICE_RESET_TYPE = 132,
383 I2400M_TLV_CONFIG_IDLE_PARAMETERS = 601, 410 I2400M_TLV_CONFIG_IDLE_PARAMETERS = 601,
384 I2400M_TLV_CONFIG_IDLE_TIMEOUT = 611, 411 I2400M_TLV_CONFIG_IDLE_TIMEOUT = 611,
412 I2400M_TLV_CONFIG_D2H_DATA_FORMAT = 614,
385}; 413};
386 414
387 415
@@ -518,5 +546,12 @@ struct i2400m_tlv_config_idle_timeout {
518 * 0 disabled */ 546 * 0 disabled */
519} __attribute__((packed)); 547} __attribute__((packed));
520 548
549/* New in v1.4 -- for backward compat, will be removed */
550struct i2400m_tlv_config_d2h_data_format {
551 struct i2400m_tlv_hdr hdr;
552 __u8 format; /* 0 old format, 1 enhanced */
553 __u8 reserved[3];
554} __attribute__((packed));
555
521 556
522#endif /* #ifndef __LINUX__WIMAX__I2400M_H__ */ 557#endif /* #ifndef __LINUX__WIMAX__I2400M_H__ */