1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76#include <stdarg.h>
77#include "i2400m.h"
78#include <linux/kernel.h>
79#include <linux/slab.h>
80#include <linux/wimax/i2400m.h>
81#include <linux/export.h>
82#include <linux/moduleparam.h>
83
84
85#define D_SUBMODULE control
86#include "debug-levels.h"
87
88static int i2400m_idle_mode_disabled;
89module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
90MODULE_PARM_DESC(idle_mode_disabled,
91 "If true, the device will not enable idle mode negotiation "
92 "with the base station (when connected) to save power.");
93
94
95static int i2400m_power_save_disabled;
96module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
97MODULE_PARM_DESC(power_save_disabled,
98 "If true, the driver will not tell the device to enter "
99 "power saving mode when it reports it is ready for it. "
100 "False by default (so the device is told to do power "
101 "saving).");
102
103static int i2400m_passive_mode;
104module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
105MODULE_PARM_DESC(passive_mode,
106 "If true, the driver will not do any device setup "
107 "and leave it up to user space, who must be properly "
108 "setup.");
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123static
124ssize_t i2400m_tlv_match(const struct i2400m_tlv_hdr *tlv,
125 enum i2400m_tlv tlv_type, ssize_t tlv_size)
126{
127 if (le16_to_cpu(tlv->type) != tlv_type)
128 return -1;
129 if (tlv_size != -1
130 && le16_to_cpu(tlv->length) + sizeof(*tlv) != tlv_size) {
131 size_t size = le16_to_cpu(tlv->length) + sizeof(*tlv);
132 printk(KERN_WARNING "W: tlv type 0x%x mismatched because of "
133 "size (got %zu vs %zd expected)\n",
134 tlv_type, size, tlv_size);
135 return size;
136 }
137 return 0;
138}
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160static
161const struct i2400m_tlv_hdr *i2400m_tlv_buffer_walk(
162 struct i2400m *i2400m,
163 const void *tlv_buf, size_t buf_size,
164 const struct i2400m_tlv_hdr *tlv_pos)
165{
166 struct device *dev = i2400m_dev(i2400m);
167 const struct i2400m_tlv_hdr *tlv_top = tlv_buf + buf_size;
168 size_t offset, length, avail_size;
169 unsigned type;
170
171 if (tlv_pos == NULL)
172 tlv_pos = tlv_buf;
173 else
174 tlv_pos = (void *) tlv_pos
175 + le16_to_cpu(tlv_pos->length) + sizeof(*tlv_pos);
176 if (tlv_pos == tlv_top) {
177 tlv_pos = NULL;
178 goto error_beyond_end;
179 }
180 if (tlv_pos > tlv_top) {
181 tlv_pos = NULL;
182 WARN_ON(1);
183 goto error_beyond_end;
184 }
185 offset = (void *) tlv_pos - (void *) tlv_buf;
186 avail_size = buf_size - offset;
187 if (avail_size < sizeof(*tlv_pos)) {
188 dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], tlv @%zu: "
189 "short header\n", tlv_buf, buf_size, offset);
190 goto error_short_header;
191 }
192 type = le16_to_cpu(tlv_pos->type);
193 length = le16_to_cpu(tlv_pos->length);
194 if (avail_size < sizeof(*tlv_pos) + length) {
195 dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], "
196 "tlv type 0x%04x @%zu: "
197 "short data (%zu bytes vs %zu needed)\n",
198 tlv_buf, buf_size, type, offset, avail_size,
199 sizeof(*tlv_pos) + length);
200 goto error_short_header;
201 }
202error_short_header:
203error_beyond_end:
204 return tlv_pos;
205}
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223static
224const struct i2400m_tlv_hdr *i2400m_tlv_find(
225 struct i2400m *i2400m,
226 const struct i2400m_tlv_hdr *tlv_hdr, size_t size,
227 enum i2400m_tlv tlv_type, ssize_t tlv_size)
228{
229 ssize_t match;
230 struct device *dev = i2400m_dev(i2400m);
231 const struct i2400m_tlv_hdr *tlv = NULL;
232 while ((tlv = i2400m_tlv_buffer_walk(i2400m, tlv_hdr, size, tlv))) {
233 match = i2400m_tlv_match(tlv, tlv_type, tlv_size);
234 if (match == 0)
235 break;
236 if (match > 0)
237 dev_warn(dev, "TLV type 0x%04x found with size "
238 "mismatch (%zu vs %zd needed)\n",
239 tlv_type, match, tlv_size);
240 }
241 return tlv;
242}
243
244
245static const struct
246{
247 char *msg;
248 int errno;
249} ms_to_errno[I2400M_MS_MAX] = {
250 [I2400M_MS_DONE_OK] = { "", 0 },
251 [I2400M_MS_DONE_IN_PROGRESS] = { "", 0 },
252 [I2400M_MS_INVALID_OP] = { "invalid opcode", -ENOSYS },
253 [I2400M_MS_BAD_STATE] = { "invalid state", -EILSEQ },
254 [I2400M_MS_ILLEGAL_VALUE] = { "illegal value", -EINVAL },
255 [I2400M_MS_MISSING_PARAMS] = { "missing parameters", -ENOMSG },
256 [I2400M_MS_VERSION_ERROR] = { "bad version", -EIO },
257 [I2400M_MS_ACCESSIBILITY_ERROR] = { "accesibility error", -EIO },
258 [I2400M_MS_BUSY] = { "busy", -EBUSY },
259 [I2400M_MS_CORRUPTED_TLV] = { "corrupted TLV", -EILSEQ },
260 [I2400M_MS_UNINITIALIZED] = { "not unitialized", -EILSEQ },
261 [I2400M_MS_UNKNOWN_ERROR] = { "unknown error", -EIO },
262 [I2400M_MS_PRODUCTION_ERROR] = { "production error", -EIO },
263 [I2400M_MS_NO_RF] = { "no RF", -EIO },
264 [I2400M_MS_NOT_READY_FOR_POWERSAVE] =
265 { "not ready for powersave", -EACCES },
266 [I2400M_MS_THERMAL_CRITICAL] = { "thermal critical", -EL3HLT },
267};
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr,
283 char *strbuf, size_t strbuf_size)
284{
285 int result;
286 enum i2400m_ms status = le16_to_cpu(l3l4_hdr->status);
287 const char *str;
288
289 if (status == 0)
290 return 0;
291 if (status >= ARRAY_SIZE(ms_to_errno)) {
292 str = "unknown status code";
293 result = -EBADR;
294 } else {
295 str = ms_to_errno[status].msg;
296 result = ms_to_errno[status].errno;
297 }
298 if (strbuf)
299 snprintf(strbuf, strbuf_size, "%s (%d)", str, status);
300 return result;
301}
302
303
304
305
306
307
308
309
310static
311void i2400m_report_tlv_system_state(struct i2400m *i2400m,
312 const struct i2400m_tlv_system_state *ss)
313{
314 struct device *dev = i2400m_dev(i2400m);
315 struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
316 enum i2400m_system_state i2400m_state = le32_to_cpu(ss->state);
317
318 d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);
319
320 if (i2400m->state != i2400m_state) {
321 i2400m->state = i2400m_state;
322 wake_up_all(&i2400m->state_wq);
323 }
324 switch (i2400m_state) {
325 case I2400M_SS_UNINITIALIZED:
326 case I2400M_SS_INIT:
327 case I2400M_SS_CONFIG:
328 case I2400M_SS_PRODUCTION:
329 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
330 break;
331
332 case I2400M_SS_RF_OFF:
333 case I2400M_SS_RF_SHUTDOWN:
334 wimax_state_change(wimax_dev, WIMAX_ST_RADIO_OFF);
335 break;
336
337 case I2400M_SS_READY:
338 case I2400M_SS_STANDBY:
339 case I2400M_SS_SLEEPACTIVE:
340 wimax_state_change(wimax_dev, WIMAX_ST_READY);
341 break;
342
343 case I2400M_SS_CONNECTING:
344 case I2400M_SS_WIMAX_CONNECTED:
345 wimax_state_change(wimax_dev, WIMAX_ST_READY);
346 break;
347
348 case I2400M_SS_SCAN:
349 case I2400M_SS_OUT_OF_ZONE:
350 wimax_state_change(wimax_dev, WIMAX_ST_SCANNING);
351 break;
352
353 case I2400M_SS_IDLE:
354 d_printf(1, dev, "entering BS-negotiated idle mode\n");
355 case I2400M_SS_DISCONNECTING:
356 case I2400M_SS_DATA_PATH_CONNECTED:
357 wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED);
358 break;
359
360 default:
361
362 dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
363 i2400m_state);
364 i2400m_reset(i2400m, I2400M_RT_WARM);
365 break;
366 }
367 d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
368 i2400m, ss, i2400m_state);
369}
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386static
387void i2400m_report_tlv_media_status(struct i2400m *i2400m,
388 const struct i2400m_tlv_media_status *ms)
389{
390 struct device *dev = i2400m_dev(i2400m);
391 struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
392 struct net_device *net_dev = wimax_dev->net_dev;
393 enum i2400m_media_status status = le32_to_cpu(ms->media_status);
394
395 d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
396
397 switch (status) {
398 case I2400M_MEDIA_STATUS_LINK_UP:
399 netif_carrier_on(net_dev);
400 break;
401 case I2400M_MEDIA_STATUS_LINK_DOWN:
402 netif_carrier_off(net_dev);
403 break;
404
405
406
407
408
409 case I2400M_MEDIA_STATUS_LINK_RENEW:
410 netif_carrier_on(net_dev);
411 break;
412 default:
413 dev_err(dev, "HW BUG? unknown media status %u\n",
414 status);
415 }
416 d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
417 i2400m, ms, status);
418}
419
420
421
422
423
424
425
426
427
428
429
430
431static
432void i2400m_report_state_parse_tlv(struct i2400m *i2400m,
433 const struct i2400m_tlv_hdr *tlv,
434 const char *tag)
435{
436 struct device *dev = i2400m_dev(i2400m);
437 const struct i2400m_tlv_media_status *ms;
438 const struct i2400m_tlv_system_state *ss;
439 const struct i2400m_tlv_rf_switches_status *rfss;
440
441 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) {
442 ss = container_of(tlv, typeof(*ss), hdr);
443 d_printf(2, dev, "%s: system state TLV "
444 "found (0x%04x), state 0x%08x\n",
445 tag, I2400M_TLV_SYSTEM_STATE,
446 le32_to_cpu(ss->state));
447 i2400m_report_tlv_system_state(i2400m, ss);
448 }
449 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) {
450 rfss = container_of(tlv, typeof(*rfss), hdr);
451 d_printf(2, dev, "%s: RF status TLV "
452 "found (0x%04x), sw 0x%02x hw 0x%02x\n",
453 tag, I2400M_TLV_RF_STATUS,
454 le32_to_cpu(rfss->sw_rf_switch),
455 le32_to_cpu(rfss->hw_rf_switch));
456 i2400m_report_tlv_rf_switches_status(i2400m, rfss);
457 }
458 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) {
459 ms = container_of(tlv, typeof(*ms), hdr);
460 d_printf(2, dev, "%s: Media Status TLV: %u\n",
461 tag, le32_to_cpu(ms->media_status));
462 i2400m_report_tlv_media_status(i2400m, ms);
463 }
464}
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479static
480void i2400m_report_state_hook(struct i2400m *i2400m,
481 const struct i2400m_l3l4_hdr *l3l4_hdr,
482 size_t size, const char *tag)
483{
484 struct device *dev = i2400m_dev(i2400m);
485 const struct i2400m_tlv_hdr *tlv;
486 size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
487
488 d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
489 i2400m, l3l4_hdr, size, tag);
490 tlv = NULL;
491
492 while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
493 tlv_size, tlv)))
494 i2400m_report_state_parse_tlv(i2400m, tlv, tag);
495 d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
496 i2400m, l3l4_hdr, size, tag);
497}
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513void i2400m_report_hook(struct i2400m *i2400m,
514 const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size)
515{
516 struct device *dev = i2400m_dev(i2400m);
517 unsigned msg_type;
518
519 d_fnstart(3, dev, "(i2400m %p l3l4_hdr %p size %zu)\n",
520 i2400m, l3l4_hdr, size);
521
522
523 msg_type = le16_to_cpu(l3l4_hdr->type);
524 switch (msg_type) {
525 case I2400M_MT_REPORT_STATE:
526 i2400m_report_state_hook(i2400m,
527 l3l4_hdr, size, "REPORT STATE");
528 break;
529
530
531 case I2400M_MT_REPORT_POWERSAVE_READY:
532 if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) {
533 if (i2400m_power_save_disabled)
534 d_printf(1, dev, "ready for powersave, "
535 "not requesting (disabled by module "
536 "parameter)\n");
537 else {
538 d_printf(1, dev, "ready for powersave, "
539 "requesting\n");
540 i2400m_cmd_enter_powersave(i2400m);
541 }
542 }
543 break;
544 }
545 d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n",
546 i2400m, l3l4_hdr, size);
547}
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563static void i2400m_msg_ack_hook(struct i2400m *i2400m,
564 const struct i2400m_l3l4_hdr *l3l4_hdr,
565 size_t size)
566{
567 int result;
568 struct device *dev = i2400m_dev(i2400m);
569 unsigned ack_type, ack_status;
570 char strerr[32];
571
572
573
574 ack_type = le16_to_cpu(l3l4_hdr->type);
575 ack_status = le16_to_cpu(l3l4_hdr->status);
576 switch (ack_type) {
577 case I2400M_MT_CMD_ENTER_POWERSAVE:
578
579
580 if (0) {
581 result = i2400m_msg_check_status(
582 l3l4_hdr, strerr, sizeof(strerr));
583 if (result >= 0)
584 d_printf(1, dev, "ready for power save: %zd\n",
585 size);
586 }
587 break;
588 }
589}
590
591
592
593
594
595
596
597
598int i2400m_msg_size_check(struct i2400m *i2400m,
599 const struct i2400m_l3l4_hdr *l3l4_hdr,
600 size_t msg_size)
601{
602 int result;
603 struct device *dev = i2400m_dev(i2400m);
604 size_t expected_size;
605 d_fnstart(4, dev, "(i2400m %p l3l4_hdr %p msg_size %zu)\n",
606 i2400m, l3l4_hdr, msg_size);
607 if (msg_size < sizeof(*l3l4_hdr)) {
608 dev_err(dev, "bad size for message header "
609 "(expected at least %zu, got %zu)\n",
610 (size_t) sizeof(*l3l4_hdr), msg_size);
611 result = -EIO;
612 goto error_hdr_size;
613 }
614 expected_size = le16_to_cpu(l3l4_hdr->length) + sizeof(*l3l4_hdr);
615 if (msg_size < expected_size) {
616 dev_err(dev, "bad size for message code 0x%04x (expected %zu, "
617 "got %zu)\n", le16_to_cpu(l3l4_hdr->type),
618 expected_size, msg_size);
619 result = -EIO;
620 } else
621 result = 0;
622error_hdr_size:
623 d_fnend(4, dev,
624 "(i2400m %p l3l4_hdr %p msg_size %zu) = %d\n",
625 i2400m, l3l4_hdr, msg_size, result);
626 return result;
627}
628
629
630
631
632
633
634
635
636
637
638
639
640void i2400m_msg_to_dev_cancel_wait(struct i2400m *i2400m, int code)
641{
642 struct sk_buff *ack_skb;
643 unsigned long flags;
644
645 spin_lock_irqsave(&i2400m->rx_lock, flags);
646 ack_skb = i2400m->ack_skb;
647 if (ack_skb && !IS_ERR(ack_skb))
648 kfree_skb(ack_skb);
649 i2400m->ack_skb = ERR_PTR(code);
650 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
651}
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
708 const void *buf, size_t buf_len)
709{
710 int result;
711 struct device *dev = i2400m_dev(i2400m);
712 const struct i2400m_l3l4_hdr *msg_l3l4_hdr;
713 struct sk_buff *ack_skb;
714 const struct i2400m_l3l4_hdr *ack_l3l4_hdr;
715 size_t ack_len;
716 int ack_timeout;
717 unsigned msg_type;
718 unsigned long flags;
719
720 d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
721 i2400m, buf, buf_len);
722
723 rmb();
724 if (i2400m->boot_mode)
725 return ERR_PTR(-EL3RST);
726
727 msg_l3l4_hdr = buf;
728
729 result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len);
730 if (result < 0)
731 goto error_bad_msg;
732 msg_type = le16_to_cpu(msg_l3l4_hdr->type);
733 d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n",
734 msg_type, buf_len);
735 d_dump(2, dev, buf, buf_len);
736
737
738
739 mutex_lock(&i2400m->msg_mutex);
740 spin_lock_irqsave(&i2400m->rx_lock, flags);
741 i2400m->ack_skb = ERR_PTR(-EINPROGRESS);
742 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
743 init_completion(&i2400m->msg_completion);
744 result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL);
745 if (result < 0) {
746 dev_err(dev, "can't send message 0x%04x: %d\n",
747 le16_to_cpu(msg_l3l4_hdr->type), result);
748 goto error_tx;
749 }
750
751
752
753 switch (msg_type) {
754 case I2400M_MT_GET_TLS_OPERATION_RESULT:
755 case I2400M_MT_CMD_SEND_EAP_RESPONSE:
756 ack_timeout = 5 * HZ;
757 break;
758 default:
759 ack_timeout = HZ;
760 }
761
762 if (unlikely(i2400m->trace_msg_from_user))
763 wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
764
765
766
767
768 result = wait_for_completion_interruptible_timeout(
769 &i2400m->msg_completion, ack_timeout);
770 if (result == 0) {
771 dev_err(dev, "timeout waiting for reply to message 0x%04x\n",
772 msg_type);
773 result = -ETIMEDOUT;
774 i2400m_msg_to_dev_cancel_wait(i2400m, result);
775 goto error_wait_for_completion;
776 } else if (result < 0) {
777 dev_err(dev, "error waiting for reply to message 0x%04x: %d\n",
778 msg_type, result);
779 i2400m_msg_to_dev_cancel_wait(i2400m, result);
780 goto error_wait_for_completion;
781 }
782
783
784
785 spin_lock_irqsave(&i2400m->rx_lock, flags);
786 ack_skb = i2400m->ack_skb;
787 if (IS_ERR(ack_skb))
788 result = PTR_ERR(ack_skb);
789 else
790 result = 0;
791 i2400m->ack_skb = NULL;
792 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
793 if (result < 0)
794 goto error_ack_status;
795 ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
796
797
798 if (unlikely(i2400m->trace_msg_from_user))
799 wimax_msg(&i2400m->wimax_dev, "echo",
800 ack_l3l4_hdr, ack_len, GFP_KERNEL);
801 result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
802 if (result < 0) {
803 dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
804 msg_type, result);
805 goto error_bad_ack_len;
806 }
807 if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) {
808 dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n",
809 le16_to_cpu(ack_l3l4_hdr->type), msg_type);
810 result = -EIO;
811 goto error_bad_ack_type;
812 }
813 i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len);
814 mutex_unlock(&i2400m->msg_mutex);
815 d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n",
816 i2400m, buf, buf_len, ack_skb);
817 return ack_skb;
818
819error_bad_ack_type:
820error_bad_ack_len:
821 kfree_skb(ack_skb);
822error_ack_status:
823error_wait_for_completion:
824error_tx:
825 mutex_unlock(&i2400m->msg_mutex);
826error_bad_msg:
827 d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n",
828 i2400m, buf, buf_len, result);
829 return ERR_PTR(result);
830}
831
832
833
834
835
836
837
838
839
840
841
842
843
844enum {
845 I2400M_WAKEUP_ENABLED = 0x01,
846 I2400M_WAKEUP_DISABLED = 0x02,
847 I2400M_TLV_TYPE_WAKEUP_MODE = 144,
848};
849
850struct i2400m_cmd_enter_power_save {
851 struct i2400m_l3l4_hdr hdr;
852 struct i2400m_tlv_hdr tlv;
853 __le32 val;
854} __packed;
855
856
857
858
859
860
861
862
863int i2400m_cmd_enter_powersave(struct i2400m *i2400m)
864{
865 int result;
866 struct device *dev = i2400m_dev(i2400m);
867 struct sk_buff *ack_skb;
868 struct i2400m_cmd_enter_power_save *cmd;
869 char strerr[32];
870
871 result = -ENOMEM;
872 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
873 if (cmd == NULL)
874 goto error_alloc;
875 cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_ENTER_POWERSAVE);
876 cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
877 cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
878 cmd->tlv.type = cpu_to_le16(I2400M_TLV_TYPE_WAKEUP_MODE);
879 cmd->tlv.length = cpu_to_le16(sizeof(cmd->val));
880 cmd->val = cpu_to_le32(I2400M_WAKEUP_ENABLED);
881
882 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
883 result = PTR_ERR(ack_skb);
884 if (IS_ERR(ack_skb)) {
885 dev_err(dev, "Failed to issue 'Enter power save' command: %d\n",
886 result);
887 goto error_msg_to_dev;
888 }
889 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
890 strerr, sizeof(strerr));
891 if (result == -EACCES)
892 d_printf(1, dev, "Cannot enter power save mode\n");
893 else if (result < 0)
894 dev_err(dev, "'Enter power save' (0x%04x) command failed: "
895 "%d - %s\n", I2400M_MT_CMD_ENTER_POWERSAVE,
896 result, strerr);
897 else
898 d_printf(1, dev, "device ready to power save\n");
899 kfree_skb(ack_skb);
900error_msg_to_dev:
901 kfree(cmd);
902error_alloc:
903 return result;
904}
905EXPORT_SYMBOL_GPL(i2400m_cmd_enter_powersave);
906
907
908
909
910
911enum {
912 I2400M_TLV_DETAILED_DEVICE_INFO = 140
913};
914
915
916
917
918
919
920
921
922
923
924
925
926
927struct sk_buff *i2400m_get_device_info(struct i2400m *i2400m)
928{
929 int result;
930 struct device *dev = i2400m_dev(i2400m);
931 struct sk_buff *ack_skb;
932 struct i2400m_l3l4_hdr *cmd;
933 const struct i2400m_l3l4_hdr *ack;
934 size_t ack_len;
935 const struct i2400m_tlv_hdr *tlv;
936 const struct i2400m_tlv_detailed_device_info *ddi;
937 char strerr[32];
938
939 ack_skb = ERR_PTR(-ENOMEM);
940 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
941 if (cmd == NULL)
942 goto error_alloc;
943 cmd->type = cpu_to_le16(I2400M_MT_GET_DEVICE_INFO);
944 cmd->length = 0;
945 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
946
947 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
948 if (IS_ERR(ack_skb)) {
949 dev_err(dev, "Failed to issue 'get device info' command: %ld\n",
950 PTR_ERR(ack_skb));
951 goto error_msg_to_dev;
952 }
953 ack = wimax_msg_data_len(ack_skb, &ack_len);
954 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
955 if (result < 0) {
956 dev_err(dev, "'get device info' (0x%04x) command failed: "
957 "%d - %s\n", I2400M_MT_GET_DEVICE_INFO, result,
958 strerr);
959 goto error_cmd_failed;
960 }
961 tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
962 I2400M_TLV_DETAILED_DEVICE_INFO, sizeof(*ddi));
963 if (tlv == NULL) {
964 dev_err(dev, "GET DEVICE INFO: "
965 "detailed device info TLV not found (0x%04x)\n",
966 I2400M_TLV_DETAILED_DEVICE_INFO);
967 result = -EIO;
968 goto error_no_tlv;
969 }
970 skb_pull(ack_skb, (void *) tlv - (void *) ack_skb->data);
971error_msg_to_dev:
972 kfree(cmd);
973error_alloc:
974 return ack_skb;
975
976error_no_tlv:
977error_cmd_failed:
978 kfree_skb(ack_skb);
979 kfree(cmd);
980 return ERR_PTR(result);
981}
982
983
984
985enum {
986 I2400M_HDIv_MAJOR = 9,
987 I2400M_HDIv_MINOR = 1,
988 I2400M_HDIv_MINOR_2 = 2,
989};
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009int i2400m_firmware_check(struct i2400m *i2400m)
1010{
1011 int result;
1012 struct device *dev = i2400m_dev(i2400m);
1013 struct sk_buff *ack_skb;
1014 struct i2400m_l3l4_hdr *cmd;
1015 const struct i2400m_l3l4_hdr *ack;
1016 size_t ack_len;
1017 const struct i2400m_tlv_hdr *tlv;
1018 const struct i2400m_tlv_l4_message_versions *l4mv;
1019 char strerr[32];
1020 unsigned major, minor, branch;
1021
1022 result = -ENOMEM;
1023 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1024 if (cmd == NULL)
1025 goto error_alloc;
1026 cmd->type = cpu_to_le16(I2400M_MT_GET_LM_VERSION);
1027 cmd->length = 0;
1028 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1029
1030 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1031 if (IS_ERR(ack_skb)) {
1032 result = PTR_ERR(ack_skb);
1033 dev_err(dev, "Failed to issue 'get lm version' command: %-d\n",
1034 result);
1035 goto error_msg_to_dev;
1036 }
1037 ack = wimax_msg_data_len(ack_skb, &ack_len);
1038 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1039 if (result < 0) {
1040 dev_err(dev, "'get lm version' (0x%04x) command failed: "
1041 "%d - %s\n", I2400M_MT_GET_LM_VERSION, result,
1042 strerr);
1043 goto error_cmd_failed;
1044 }
1045 tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
1046 I2400M_TLV_L4_MESSAGE_VERSIONS, sizeof(*l4mv));
1047 if (tlv == NULL) {
1048 dev_err(dev, "get lm version: TLV not found (0x%04x)\n",
1049 I2400M_TLV_L4_MESSAGE_VERSIONS);
1050 result = -EIO;
1051 goto error_no_tlv;
1052 }
1053 l4mv = container_of(tlv, typeof(*l4mv), hdr);
1054 major = le16_to_cpu(l4mv->major);
1055 minor = le16_to_cpu(l4mv->minor);
1056 branch = le16_to_cpu(l4mv->branch);
1057 result = -EINVAL;
1058 if (major != I2400M_HDIv_MAJOR) {
1059 dev_err(dev, "unsupported major fw version "
1060 "%u.%u.%u\n", major, minor, branch);
1061 goto error_bad_major;
1062 }
1063 result = 0;
1064 if (minor > I2400M_HDIv_MINOR_2 || minor < I2400M_HDIv_MINOR)
1065 dev_warn(dev, "untested minor fw version %u.%u.%u\n",
1066 major, minor, branch);
1067
1068 i2400m->fw_version = major << 16 | minor;
1069 dev_info(dev, "firmware interface version %u.%u.%u\n",
1070 major, minor, branch);
1071error_bad_major:
1072error_no_tlv:
1073error_cmd_failed:
1074 kfree_skb(ack_skb);
1075error_msg_to_dev:
1076 kfree(cmd);
1077error_alloc:
1078 return result;
1079}
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093int i2400m_cmd_exit_idle(struct i2400m *i2400m)
1094{
1095 int result;
1096 struct device *dev = i2400m_dev(i2400m);
1097 struct sk_buff *ack_skb;
1098 struct i2400m_l3l4_hdr *cmd;
1099 char strerr[32];
1100
1101 result = -ENOMEM;
1102 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1103 if (cmd == NULL)
1104 goto error_alloc;
1105 cmd->type = cpu_to_le16(I2400M_MT_CMD_EXIT_IDLE);
1106 cmd->length = 0;
1107 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1108
1109 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1110 result = PTR_ERR(ack_skb);
1111 if (IS_ERR(ack_skb)) {
1112 dev_err(dev, "Failed to issue 'exit idle' command: %d\n",
1113 result);
1114 goto error_msg_to_dev;
1115 }
1116 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
1117 strerr, sizeof(strerr));
1118 kfree_skb(ack_skb);
1119error_msg_to_dev:
1120 kfree(cmd);
1121error_alloc:
1122 return result;
1123
1124}
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141static int i2400m_cmd_get_state(struct i2400m *i2400m)
1142{
1143 int result;
1144 struct device *dev = i2400m_dev(i2400m);
1145 struct sk_buff *ack_skb;
1146 struct i2400m_l3l4_hdr *cmd;
1147 const struct i2400m_l3l4_hdr *ack;
1148 size_t ack_len;
1149 char strerr[32];
1150
1151 result = -ENOMEM;
1152 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1153 if (cmd == NULL)
1154 goto error_alloc;
1155 cmd->type = cpu_to_le16(I2400M_MT_GET_STATE);
1156 cmd->length = 0;
1157 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1158
1159 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1160 if (IS_ERR(ack_skb)) {
1161 dev_err(dev, "Failed to issue 'get state' command: %ld\n",
1162 PTR_ERR(ack_skb));
1163 result = PTR_ERR(ack_skb);
1164 goto error_msg_to_dev;
1165 }
1166 ack = wimax_msg_data_len(ack_skb, &ack_len);
1167 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1168 if (result < 0) {
1169 dev_err(dev, "'get state' (0x%04x) command failed: "
1170 "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
1171 goto error_cmd_failed;
1172 }
1173 i2400m_report_state_hook(i2400m, ack, ack_len - sizeof(*ack),
1174 "GET STATE");
1175 result = 0;
1176 kfree_skb(ack_skb);
1177error_cmd_failed:
1178error_msg_to_dev:
1179 kfree(cmd);
1180error_alloc:
1181 return result;
1182}
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194static int i2400m_set_init_config(struct i2400m *i2400m,
1195 const struct i2400m_tlv_hdr **arg,
1196 size_t args)
1197{
1198 int result;
1199 struct device *dev = i2400m_dev(i2400m);
1200 struct sk_buff *ack_skb;
1201 struct i2400m_l3l4_hdr *cmd;
1202 char strerr[32];
1203 unsigned argc, argsize, tlv_size;
1204 const struct i2400m_tlv_hdr *tlv_hdr;
1205 void *buf, *itr;
1206
1207 d_fnstart(3, dev, "(i2400m %p arg %p args %zu)\n", i2400m, arg, args);
1208 result = 0;
1209 if (args == 0)
1210 goto none;
1211
1212
1213 argsize = 0;
1214 for (argc = 0; argc < args; argc++) {
1215 tlv_hdr = arg[argc];
1216 argsize += sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
1217 }
1218 WARN_ON(argc >= 9);
1219
1220
1221 result = -ENOMEM;
1222 buf = kzalloc(sizeof(*cmd) + argsize, GFP_KERNEL);
1223 if (buf == NULL)
1224 goto error_alloc;
1225 cmd = buf;
1226 cmd->type = cpu_to_le16(I2400M_MT_SET_INIT_CONFIG);
1227 cmd->length = cpu_to_le16(argsize);
1228 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1229
1230
1231 itr = buf + sizeof(*cmd);
1232 for (argc = 0; argc < args; argc++) {
1233 tlv_hdr = arg[argc];
1234 tlv_size = sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
1235 memcpy(itr, tlv_hdr, tlv_size);
1236 itr += tlv_size;
1237 }
1238
1239
1240 ack_skb = i2400m_msg_to_dev(i2400m, buf, sizeof(*cmd) + argsize);
1241 result = PTR_ERR(ack_skb);
1242 if (IS_ERR(ack_skb)) {
1243 dev_err(dev, "Failed to issue 'init config' command: %d\n",
1244 result);
1245
1246 goto error_msg_to_dev;
1247 }
1248 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
1249 strerr, sizeof(strerr));
1250 if (result < 0)
1251 dev_err(dev, "'init config' (0x%04x) command failed: %d - %s\n",
1252 I2400M_MT_SET_INIT_CONFIG, result, strerr);
1253 kfree_skb(ack_skb);
1254error_msg_to_dev:
1255 kfree(buf);
1256error_alloc:
1257none:
1258 d_fnend(3, dev, "(i2400m %p arg %p args %zu) = %d\n",
1259 i2400m, arg, args, result);
1260 return result;
1261
1262}
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282int i2400m_set_idle_timeout(struct i2400m *i2400m, unsigned msecs)
1283{
1284 int result;
1285 struct device *dev = i2400m_dev(i2400m);
1286 struct sk_buff *ack_skb;
1287 struct {
1288 struct i2400m_l3l4_hdr hdr;
1289 struct i2400m_tlv_config_idle_timeout cit;
1290 } *cmd;
1291 const struct i2400m_l3l4_hdr *ack;
1292 size_t ack_len;
1293 char strerr[32];
1294
1295 result = -ENOSYS;
1296 if (i2400m_le_v1_3(i2400m))
1297 goto error_alloc;
1298 result = -ENOMEM;
1299 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1300 if (cmd == NULL)
1301 goto error_alloc;
1302 cmd->hdr.type = cpu_to_le16(I2400M_MT_GET_STATE);
1303 cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
1304 cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
1305
1306 cmd->cit.hdr.type =
1307 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1308 cmd->cit.hdr.length = cpu_to_le16(sizeof(cmd->cit.timeout));
1309 cmd->cit.timeout = cpu_to_le32(msecs);
1310
1311 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1312 if (IS_ERR(ack_skb)) {
1313 dev_err(dev, "Failed to issue 'set idle timeout' command: "
1314 "%ld\n", PTR_ERR(ack_skb));
1315 result = PTR_ERR(ack_skb);
1316 goto error_msg_to_dev;
1317 }
1318 ack = wimax_msg_data_len(ack_skb, &ack_len);
1319 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1320 if (result < 0) {
1321 dev_err(dev, "'set idle timeout' (0x%04x) command failed: "
1322 "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
1323 goto error_cmd_failed;
1324 }
1325 result = 0;
1326 kfree_skb(ack_skb);
1327error_cmd_failed:
1328error_msg_to_dev:
1329 kfree(cmd);
1330error_alloc:
1331 return result;
1332}
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348int i2400m_dev_initialize(struct i2400m *i2400m)
1349{
1350 int result;
1351 struct device *dev = i2400m_dev(i2400m);
1352 struct i2400m_tlv_config_idle_parameters idle_params;
1353 struct i2400m_tlv_config_idle_timeout idle_timeout;
1354 struct i2400m_tlv_config_d2h_data_format df;
1355 struct i2400m_tlv_config_dl_host_reorder dlhr;
1356 const struct i2400m_tlv_hdr *args[9];
1357 unsigned argc = 0;
1358
1359 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
1360 if (i2400m_passive_mode)
1361 goto out_passive;
1362
1363 if (i2400m_idle_mode_disabled) {
1364 if (i2400m_le_v1_3(i2400m)) {
1365 idle_params.hdr.type =
1366 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
1367 idle_params.hdr.length = cpu_to_le16(
1368 sizeof(idle_params) - sizeof(idle_params.hdr));
1369 idle_params.idle_timeout = 0;
1370 idle_params.idle_paging_interval = 0;
1371 args[argc++] = &idle_params.hdr;
1372 } else {
1373 idle_timeout.hdr.type =
1374 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1375 idle_timeout.hdr.length = cpu_to_le16(
1376 sizeof(idle_timeout) - sizeof(idle_timeout.hdr));
1377 idle_timeout.timeout = 0;
1378 args[argc++] = &idle_timeout.hdr;
1379 }
1380 }
1381 if (i2400m_ge_v1_4(i2400m)) {
1382
1383 df.hdr.type =
1384 cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT);
1385 df.hdr.length = cpu_to_le16(
1386 sizeof(df) - sizeof(df.hdr));
1387 df.format = 1;
1388 args[argc++] = &df.hdr;
1389
1390
1391
1392 if (i2400m->rx_reorder) {
1393 dlhr.hdr.type =
1394 cpu_to_le16(I2400M_TLV_CONFIG_DL_HOST_REORDER);
1395 dlhr.hdr.length = cpu_to_le16(
1396 sizeof(dlhr) - sizeof(dlhr.hdr));
1397 dlhr.reorder = 1;
1398 args[argc++] = &dlhr.hdr;
1399 }
1400 }
1401 result = i2400m_set_init_config(i2400m, args, argc);
1402 if (result < 0)
1403 goto error;
1404out_passive:
1405
1406
1407
1408
1409
1410
1411 result = i2400m_cmd_get_state(i2400m);
1412error:
1413 if (result < 0)
1414 dev_err(dev, "failed to initialize the device: %d\n", result);
1415 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
1416 return result;
1417}
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430void i2400m_dev_shutdown(struct i2400m *i2400m)
1431{
1432 struct device *dev = i2400m_dev(i2400m);
1433
1434 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
1435 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
1436}
1437