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] = { "uninitialized", -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 fallthrough;
356 case I2400M_SS_DISCONNECTING:
357 case I2400M_SS_DATA_PATH_CONNECTED:
358 wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED);
359 break;
360
361 default:
362
363 dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
364 i2400m_state);
365 i2400m_reset(i2400m, I2400M_RT_WARM);
366 break;
367 }
368 d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
369 i2400m, ss, i2400m_state);
370}
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387static
388void i2400m_report_tlv_media_status(struct i2400m *i2400m,
389 const struct i2400m_tlv_media_status *ms)
390{
391 struct device *dev = i2400m_dev(i2400m);
392 struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
393 struct net_device *net_dev = wimax_dev->net_dev;
394 enum i2400m_media_status status = le32_to_cpu(ms->media_status);
395
396 d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
397
398 switch (status) {
399 case I2400M_MEDIA_STATUS_LINK_UP:
400 netif_carrier_on(net_dev);
401 break;
402 case I2400M_MEDIA_STATUS_LINK_DOWN:
403 netif_carrier_off(net_dev);
404 break;
405
406
407
408
409
410 case I2400M_MEDIA_STATUS_LINK_RENEW:
411 netif_carrier_on(net_dev);
412 break;
413 default:
414 dev_err(dev, "HW BUG? unknown media status %u\n",
415 status);
416 }
417 d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
418 i2400m, ms, status);
419}
420
421
422
423
424
425
426
427
428
429
430
431
432static
433void i2400m_report_state_parse_tlv(struct i2400m *i2400m,
434 const struct i2400m_tlv_hdr *tlv,
435 const char *tag)
436{
437 struct device *dev = i2400m_dev(i2400m);
438 const struct i2400m_tlv_media_status *ms;
439 const struct i2400m_tlv_system_state *ss;
440 const struct i2400m_tlv_rf_switches_status *rfss;
441
442 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) {
443 ss = container_of(tlv, typeof(*ss), hdr);
444 d_printf(2, dev, "%s: system state TLV "
445 "found (0x%04x), state 0x%08x\n",
446 tag, I2400M_TLV_SYSTEM_STATE,
447 le32_to_cpu(ss->state));
448 i2400m_report_tlv_system_state(i2400m, ss);
449 }
450 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) {
451 rfss = container_of(tlv, typeof(*rfss), hdr);
452 d_printf(2, dev, "%s: RF status TLV "
453 "found (0x%04x), sw 0x%02x hw 0x%02x\n",
454 tag, I2400M_TLV_RF_STATUS,
455 le32_to_cpu(rfss->sw_rf_switch),
456 le32_to_cpu(rfss->hw_rf_switch));
457 i2400m_report_tlv_rf_switches_status(i2400m, rfss);
458 }
459 if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) {
460 ms = container_of(tlv, typeof(*ms), hdr);
461 d_printf(2, dev, "%s: Media Status TLV: %u\n",
462 tag, le32_to_cpu(ms->media_status));
463 i2400m_report_tlv_media_status(i2400m, ms);
464 }
465}
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480static
481void i2400m_report_state_hook(struct i2400m *i2400m,
482 const struct i2400m_l3l4_hdr *l3l4_hdr,
483 size_t size, const char *tag)
484{
485 struct device *dev = i2400m_dev(i2400m);
486 const struct i2400m_tlv_hdr *tlv;
487 size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
488
489 d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
490 i2400m, l3l4_hdr, size, tag);
491 tlv = NULL;
492
493 while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
494 tlv_size, tlv)))
495 i2400m_report_state_parse_tlv(i2400m, tlv, tag);
496 d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
497 i2400m, l3l4_hdr, size, tag);
498}
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514void i2400m_report_hook(struct i2400m *i2400m,
515 const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size)
516{
517 struct device *dev = i2400m_dev(i2400m);
518 unsigned msg_type;
519
520 d_fnstart(3, dev, "(i2400m %p l3l4_hdr %p size %zu)\n",
521 i2400m, l3l4_hdr, size);
522
523
524 msg_type = le16_to_cpu(l3l4_hdr->type);
525 switch (msg_type) {
526 case I2400M_MT_REPORT_STATE:
527 i2400m_report_state_hook(i2400m,
528 l3l4_hdr, size, "REPORT STATE");
529 break;
530
531
532 case I2400M_MT_REPORT_POWERSAVE_READY:
533 if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) {
534 if (i2400m_power_save_disabled)
535 d_printf(1, dev, "ready for powersave, "
536 "not requesting (disabled by module "
537 "parameter)\n");
538 else {
539 d_printf(1, dev, "ready for powersave, "
540 "requesting\n");
541 i2400m_cmd_enter_powersave(i2400m);
542 }
543 }
544 break;
545 }
546 d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n",
547 i2400m, l3l4_hdr, size);
548}
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564static void i2400m_msg_ack_hook(struct i2400m *i2400m,
565 const struct i2400m_l3l4_hdr *l3l4_hdr,
566 size_t size)
567{
568 int result;
569 struct device *dev = i2400m_dev(i2400m);
570 unsigned int ack_type;
571 char strerr[32];
572
573
574
575 ack_type = le16_to_cpu(l3l4_hdr->type);
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
705struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
706 const void *buf, size_t buf_len)
707{
708 int result;
709 struct device *dev = i2400m_dev(i2400m);
710 const struct i2400m_l3l4_hdr *msg_l3l4_hdr;
711 struct sk_buff *ack_skb;
712 const struct i2400m_l3l4_hdr *ack_l3l4_hdr;
713 size_t ack_len;
714 int ack_timeout;
715 unsigned msg_type;
716 unsigned long flags;
717
718 d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
719 i2400m, buf, buf_len);
720
721 rmb();
722 if (i2400m->boot_mode)
723 return ERR_PTR(-EL3RST);
724
725 msg_l3l4_hdr = buf;
726
727 result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len);
728 if (result < 0)
729 goto error_bad_msg;
730 msg_type = le16_to_cpu(msg_l3l4_hdr->type);
731 d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n",
732 msg_type, buf_len);
733 d_dump(2, dev, buf, buf_len);
734
735
736
737 mutex_lock(&i2400m->msg_mutex);
738 spin_lock_irqsave(&i2400m->rx_lock, flags);
739 i2400m->ack_skb = ERR_PTR(-EINPROGRESS);
740 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
741 init_completion(&i2400m->msg_completion);
742 result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL);
743 if (result < 0) {
744 dev_err(dev, "can't send message 0x%04x: %d\n",
745 le16_to_cpu(msg_l3l4_hdr->type), result);
746 goto error_tx;
747 }
748
749
750
751 switch (msg_type) {
752 case I2400M_MT_GET_TLS_OPERATION_RESULT:
753 case I2400M_MT_CMD_SEND_EAP_RESPONSE:
754 ack_timeout = 5 * HZ;
755 break;
756 default:
757 ack_timeout = HZ;
758 }
759
760 if (unlikely(i2400m->trace_msg_from_user))
761 wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
762
763
764
765
766 result = wait_for_completion_interruptible_timeout(
767 &i2400m->msg_completion, ack_timeout);
768 if (result == 0) {
769 dev_err(dev, "timeout waiting for reply to message 0x%04x\n",
770 msg_type);
771 result = -ETIMEDOUT;
772 i2400m_msg_to_dev_cancel_wait(i2400m, result);
773 goto error_wait_for_completion;
774 } else if (result < 0) {
775 dev_err(dev, "error waiting for reply to message 0x%04x: %d\n",
776 msg_type, result);
777 i2400m_msg_to_dev_cancel_wait(i2400m, result);
778 goto error_wait_for_completion;
779 }
780
781
782
783 spin_lock_irqsave(&i2400m->rx_lock, flags);
784 ack_skb = i2400m->ack_skb;
785 if (IS_ERR(ack_skb))
786 result = PTR_ERR(ack_skb);
787 else
788 result = 0;
789 i2400m->ack_skb = NULL;
790 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
791 if (result < 0)
792 goto error_ack_status;
793 ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
794
795
796 if (unlikely(i2400m->trace_msg_from_user))
797 wimax_msg(&i2400m->wimax_dev, "echo",
798 ack_l3l4_hdr, ack_len, GFP_KERNEL);
799 result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
800 if (result < 0) {
801 dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
802 msg_type, result);
803 goto error_bad_ack_len;
804 }
805 if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) {
806 dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n",
807 le16_to_cpu(ack_l3l4_hdr->type), msg_type);
808 result = -EIO;
809 goto error_bad_ack_type;
810 }
811 i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len);
812 mutex_unlock(&i2400m->msg_mutex);
813 d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n",
814 i2400m, buf, buf_len, ack_skb);
815 return ack_skb;
816
817error_bad_ack_type:
818error_bad_ack_len:
819 kfree_skb(ack_skb);
820error_ack_status:
821error_wait_for_completion:
822error_tx:
823 mutex_unlock(&i2400m->msg_mutex);
824error_bad_msg:
825 d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n",
826 i2400m, buf, buf_len, result);
827 return ERR_PTR(result);
828}
829
830
831
832
833
834
835
836
837
838
839
840
841
842enum {
843 I2400M_WAKEUP_ENABLED = 0x01,
844 I2400M_WAKEUP_DISABLED = 0x02,
845 I2400M_TLV_TYPE_WAKEUP_MODE = 144,
846};
847
848struct i2400m_cmd_enter_power_save {
849 struct i2400m_l3l4_hdr hdr;
850 struct i2400m_tlv_hdr tlv;
851 __le32 val;
852} __packed;
853
854
855
856
857
858
859
860
861int i2400m_cmd_enter_powersave(struct i2400m *i2400m)
862{
863 int result;
864 struct device *dev = i2400m_dev(i2400m);
865 struct sk_buff *ack_skb;
866 struct i2400m_cmd_enter_power_save *cmd;
867 char strerr[32];
868
869 result = -ENOMEM;
870 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
871 if (cmd == NULL)
872 goto error_alloc;
873 cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_ENTER_POWERSAVE);
874 cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
875 cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
876 cmd->tlv.type = cpu_to_le16(I2400M_TLV_TYPE_WAKEUP_MODE);
877 cmd->tlv.length = cpu_to_le16(sizeof(cmd->val));
878 cmd->val = cpu_to_le32(I2400M_WAKEUP_ENABLED);
879
880 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
881 result = PTR_ERR(ack_skb);
882 if (IS_ERR(ack_skb)) {
883 dev_err(dev, "Failed to issue 'Enter power save' command: %d\n",
884 result);
885 goto error_msg_to_dev;
886 }
887 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
888 strerr, sizeof(strerr));
889 if (result == -EACCES)
890 d_printf(1, dev, "Cannot enter power save mode\n");
891 else if (result < 0)
892 dev_err(dev, "'Enter power save' (0x%04x) command failed: "
893 "%d - %s\n", I2400M_MT_CMD_ENTER_POWERSAVE,
894 result, strerr);
895 else
896 d_printf(1, dev, "device ready to power save\n");
897 kfree_skb(ack_skb);
898error_msg_to_dev:
899 kfree(cmd);
900error_alloc:
901 return result;
902}
903EXPORT_SYMBOL_GPL(i2400m_cmd_enter_powersave);
904
905
906
907
908
909enum {
910 I2400M_TLV_DETAILED_DEVICE_INFO = 140
911};
912
913
914
915
916
917
918
919
920
921
922
923
924
925struct sk_buff *i2400m_get_device_info(struct i2400m *i2400m)
926{
927 int result;
928 struct device *dev = i2400m_dev(i2400m);
929 struct sk_buff *ack_skb;
930 struct i2400m_l3l4_hdr *cmd;
931 const struct i2400m_l3l4_hdr *ack;
932 size_t ack_len;
933 const struct i2400m_tlv_hdr *tlv;
934 const struct i2400m_tlv_detailed_device_info *ddi;
935 char strerr[32];
936
937 ack_skb = ERR_PTR(-ENOMEM);
938 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
939 if (cmd == NULL)
940 goto error_alloc;
941 cmd->type = cpu_to_le16(I2400M_MT_GET_DEVICE_INFO);
942 cmd->length = 0;
943 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
944
945 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
946 if (IS_ERR(ack_skb)) {
947 dev_err(dev, "Failed to issue 'get device info' command: %ld\n",
948 PTR_ERR(ack_skb));
949 goto error_msg_to_dev;
950 }
951 ack = wimax_msg_data_len(ack_skb, &ack_len);
952 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
953 if (result < 0) {
954 dev_err(dev, "'get device info' (0x%04x) command failed: "
955 "%d - %s\n", I2400M_MT_GET_DEVICE_INFO, result,
956 strerr);
957 goto error_cmd_failed;
958 }
959 tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
960 I2400M_TLV_DETAILED_DEVICE_INFO, sizeof(*ddi));
961 if (tlv == NULL) {
962 dev_err(dev, "GET DEVICE INFO: "
963 "detailed device info TLV not found (0x%04x)\n",
964 I2400M_TLV_DETAILED_DEVICE_INFO);
965 result = -EIO;
966 goto error_no_tlv;
967 }
968 skb_pull(ack_skb, (void *) tlv - (void *) ack_skb->data);
969error_msg_to_dev:
970 kfree(cmd);
971error_alloc:
972 return ack_skb;
973
974error_no_tlv:
975error_cmd_failed:
976 kfree_skb(ack_skb);
977 kfree(cmd);
978 return ERR_PTR(result);
979}
980
981
982
983enum {
984 I2400M_HDIv_MAJOR = 9,
985 I2400M_HDIv_MINOR = 1,
986 I2400M_HDIv_MINOR_2 = 2,
987};
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007int i2400m_firmware_check(struct i2400m *i2400m)
1008{
1009 int result;
1010 struct device *dev = i2400m_dev(i2400m);
1011 struct sk_buff *ack_skb;
1012 struct i2400m_l3l4_hdr *cmd;
1013 const struct i2400m_l3l4_hdr *ack;
1014 size_t ack_len;
1015 const struct i2400m_tlv_hdr *tlv;
1016 const struct i2400m_tlv_l4_message_versions *l4mv;
1017 char strerr[32];
1018 unsigned major, minor, branch;
1019
1020 result = -ENOMEM;
1021 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1022 if (cmd == NULL)
1023 goto error_alloc;
1024 cmd->type = cpu_to_le16(I2400M_MT_GET_LM_VERSION);
1025 cmd->length = 0;
1026 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1027
1028 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1029 if (IS_ERR(ack_skb)) {
1030 result = PTR_ERR(ack_skb);
1031 dev_err(dev, "Failed to issue 'get lm version' command: %-d\n",
1032 result);
1033 goto error_msg_to_dev;
1034 }
1035 ack = wimax_msg_data_len(ack_skb, &ack_len);
1036 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1037 if (result < 0) {
1038 dev_err(dev, "'get lm version' (0x%04x) command failed: "
1039 "%d - %s\n", I2400M_MT_GET_LM_VERSION, result,
1040 strerr);
1041 goto error_cmd_failed;
1042 }
1043 tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
1044 I2400M_TLV_L4_MESSAGE_VERSIONS, sizeof(*l4mv));
1045 if (tlv == NULL) {
1046 dev_err(dev, "get lm version: TLV not found (0x%04x)\n",
1047 I2400M_TLV_L4_MESSAGE_VERSIONS);
1048 result = -EIO;
1049 goto error_no_tlv;
1050 }
1051 l4mv = container_of(tlv, typeof(*l4mv), hdr);
1052 major = le16_to_cpu(l4mv->major);
1053 minor = le16_to_cpu(l4mv->minor);
1054 branch = le16_to_cpu(l4mv->branch);
1055 result = -EINVAL;
1056 if (major != I2400M_HDIv_MAJOR) {
1057 dev_err(dev, "unsupported major fw version "
1058 "%u.%u.%u\n", major, minor, branch);
1059 goto error_bad_major;
1060 }
1061 result = 0;
1062 if (minor > I2400M_HDIv_MINOR_2 || minor < I2400M_HDIv_MINOR)
1063 dev_warn(dev, "untested minor fw version %u.%u.%u\n",
1064 major, minor, branch);
1065
1066 i2400m->fw_version = major << 16 | minor;
1067 dev_info(dev, "firmware interface version %u.%u.%u\n",
1068 major, minor, branch);
1069error_bad_major:
1070error_no_tlv:
1071error_cmd_failed:
1072 kfree_skb(ack_skb);
1073error_msg_to_dev:
1074 kfree(cmd);
1075error_alloc:
1076 return result;
1077}
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091int i2400m_cmd_exit_idle(struct i2400m *i2400m)
1092{
1093 int result;
1094 struct device *dev = i2400m_dev(i2400m);
1095 struct sk_buff *ack_skb;
1096 struct i2400m_l3l4_hdr *cmd;
1097 char strerr[32];
1098
1099 result = -ENOMEM;
1100 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1101 if (cmd == NULL)
1102 goto error_alloc;
1103 cmd->type = cpu_to_le16(I2400M_MT_CMD_EXIT_IDLE);
1104 cmd->length = 0;
1105 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1106
1107 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1108 result = PTR_ERR(ack_skb);
1109 if (IS_ERR(ack_skb)) {
1110 dev_err(dev, "Failed to issue 'exit idle' command: %d\n",
1111 result);
1112 goto error_msg_to_dev;
1113 }
1114 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
1115 strerr, sizeof(strerr));
1116 kfree_skb(ack_skb);
1117error_msg_to_dev:
1118 kfree(cmd);
1119error_alloc:
1120 return result;
1121
1122}
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139static int i2400m_cmd_get_state(struct i2400m *i2400m)
1140{
1141 int result;
1142 struct device *dev = i2400m_dev(i2400m);
1143 struct sk_buff *ack_skb;
1144 struct i2400m_l3l4_hdr *cmd;
1145 const struct i2400m_l3l4_hdr *ack;
1146 size_t ack_len;
1147 char strerr[32];
1148
1149 result = -ENOMEM;
1150 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1151 if (cmd == NULL)
1152 goto error_alloc;
1153 cmd->type = cpu_to_le16(I2400M_MT_GET_STATE);
1154 cmd->length = 0;
1155 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1156
1157 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1158 if (IS_ERR(ack_skb)) {
1159 dev_err(dev, "Failed to issue 'get state' command: %ld\n",
1160 PTR_ERR(ack_skb));
1161 result = PTR_ERR(ack_skb);
1162 goto error_msg_to_dev;
1163 }
1164 ack = wimax_msg_data_len(ack_skb, &ack_len);
1165 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1166 if (result < 0) {
1167 dev_err(dev, "'get state' (0x%04x) command failed: "
1168 "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
1169 goto error_cmd_failed;
1170 }
1171 i2400m_report_state_hook(i2400m, ack, ack_len - sizeof(*ack),
1172 "GET STATE");
1173 result = 0;
1174 kfree_skb(ack_skb);
1175error_cmd_failed:
1176error_msg_to_dev:
1177 kfree(cmd);
1178error_alloc:
1179 return result;
1180}
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192static int i2400m_set_init_config(struct i2400m *i2400m,
1193 const struct i2400m_tlv_hdr **arg,
1194 size_t args)
1195{
1196 int result;
1197 struct device *dev = i2400m_dev(i2400m);
1198 struct sk_buff *ack_skb;
1199 struct i2400m_l3l4_hdr *cmd;
1200 char strerr[32];
1201 unsigned argc, argsize, tlv_size;
1202 const struct i2400m_tlv_hdr *tlv_hdr;
1203 void *buf, *itr;
1204
1205 d_fnstart(3, dev, "(i2400m %p arg %p args %zu)\n", i2400m, arg, args);
1206 result = 0;
1207 if (args == 0)
1208 goto none;
1209
1210
1211 argsize = 0;
1212 for (argc = 0; argc < args; argc++) {
1213 tlv_hdr = arg[argc];
1214 argsize += sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
1215 }
1216 WARN_ON(argc >= 9);
1217
1218
1219 result = -ENOMEM;
1220 buf = kzalloc(sizeof(*cmd) + argsize, GFP_KERNEL);
1221 if (buf == NULL)
1222 goto error_alloc;
1223 cmd = buf;
1224 cmd->type = cpu_to_le16(I2400M_MT_SET_INIT_CONFIG);
1225 cmd->length = cpu_to_le16(argsize);
1226 cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
1227
1228
1229 itr = buf + sizeof(*cmd);
1230 for (argc = 0; argc < args; argc++) {
1231 tlv_hdr = arg[argc];
1232 tlv_size = sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
1233 memcpy(itr, tlv_hdr, tlv_size);
1234 itr += tlv_size;
1235 }
1236
1237
1238 ack_skb = i2400m_msg_to_dev(i2400m, buf, sizeof(*cmd) + argsize);
1239 result = PTR_ERR(ack_skb);
1240 if (IS_ERR(ack_skb)) {
1241 dev_err(dev, "Failed to issue 'init config' command: %d\n",
1242 result);
1243
1244 goto error_msg_to_dev;
1245 }
1246 result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
1247 strerr, sizeof(strerr));
1248 if (result < 0)
1249 dev_err(dev, "'init config' (0x%04x) command failed: %d - %s\n",
1250 I2400M_MT_SET_INIT_CONFIG, result, strerr);
1251 kfree_skb(ack_skb);
1252error_msg_to_dev:
1253 kfree(buf);
1254error_alloc:
1255none:
1256 d_fnend(3, dev, "(i2400m %p arg %p args %zu) = %d\n",
1257 i2400m, arg, args, result);
1258 return result;
1259
1260}
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280int i2400m_set_idle_timeout(struct i2400m *i2400m, unsigned msecs)
1281{
1282 int result;
1283 struct device *dev = i2400m_dev(i2400m);
1284 struct sk_buff *ack_skb;
1285 struct {
1286 struct i2400m_l3l4_hdr hdr;
1287 struct i2400m_tlv_config_idle_timeout cit;
1288 } *cmd;
1289 const struct i2400m_l3l4_hdr *ack;
1290 size_t ack_len;
1291 char strerr[32];
1292
1293 result = -ENOSYS;
1294 if (i2400m_le_v1_3(i2400m))
1295 goto error_alloc;
1296 result = -ENOMEM;
1297 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1298 if (cmd == NULL)
1299 goto error_alloc;
1300 cmd->hdr.type = cpu_to_le16(I2400M_MT_GET_STATE);
1301 cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
1302 cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
1303
1304 cmd->cit.hdr.type =
1305 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1306 cmd->cit.hdr.length = cpu_to_le16(sizeof(cmd->cit.timeout));
1307 cmd->cit.timeout = cpu_to_le32(msecs);
1308
1309 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1310 if (IS_ERR(ack_skb)) {
1311 dev_err(dev, "Failed to issue 'set idle timeout' command: "
1312 "%ld\n", PTR_ERR(ack_skb));
1313 result = PTR_ERR(ack_skb);
1314 goto error_msg_to_dev;
1315 }
1316 ack = wimax_msg_data_len(ack_skb, &ack_len);
1317 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1318 if (result < 0) {
1319 dev_err(dev, "'set idle timeout' (0x%04x) command failed: "
1320 "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
1321 goto error_cmd_failed;
1322 }
1323 result = 0;
1324 kfree_skb(ack_skb);
1325error_cmd_failed:
1326error_msg_to_dev:
1327 kfree(cmd);
1328error_alloc:
1329 return result;
1330}
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346int i2400m_dev_initialize(struct i2400m *i2400m)
1347{
1348 int result;
1349 struct device *dev = i2400m_dev(i2400m);
1350 struct i2400m_tlv_config_idle_parameters idle_params;
1351 struct i2400m_tlv_config_idle_timeout idle_timeout;
1352 struct i2400m_tlv_config_d2h_data_format df;
1353 struct i2400m_tlv_config_dl_host_reorder dlhr;
1354 const struct i2400m_tlv_hdr *args[9];
1355 unsigned argc = 0;
1356
1357 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
1358 if (i2400m_passive_mode)
1359 goto out_passive;
1360
1361 if (i2400m_idle_mode_disabled) {
1362 if (i2400m_le_v1_3(i2400m)) {
1363 idle_params.hdr.type =
1364 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
1365 idle_params.hdr.length = cpu_to_le16(
1366 sizeof(idle_params) - sizeof(idle_params.hdr));
1367 idle_params.idle_timeout = 0;
1368 idle_params.idle_paging_interval = 0;
1369 args[argc++] = &idle_params.hdr;
1370 } else {
1371 idle_timeout.hdr.type =
1372 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1373 idle_timeout.hdr.length = cpu_to_le16(
1374 sizeof(idle_timeout) - sizeof(idle_timeout.hdr));
1375 idle_timeout.timeout = 0;
1376 args[argc++] = &idle_timeout.hdr;
1377 }
1378 }
1379 if (i2400m_ge_v1_4(i2400m)) {
1380
1381 df.hdr.type =
1382 cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT);
1383 df.hdr.length = cpu_to_le16(
1384 sizeof(df) - sizeof(df.hdr));
1385 df.format = 1;
1386 args[argc++] = &df.hdr;
1387
1388
1389
1390 if (i2400m->rx_reorder) {
1391 dlhr.hdr.type =
1392 cpu_to_le16(I2400M_TLV_CONFIG_DL_HOST_REORDER);
1393 dlhr.hdr.length = cpu_to_le16(
1394 sizeof(dlhr) - sizeof(dlhr.hdr));
1395 dlhr.reorder = 1;
1396 args[argc++] = &dlhr.hdr;
1397 }
1398 }
1399 result = i2400m_set_init_config(i2400m, args, argc);
1400 if (result < 0)
1401 goto error;
1402out_passive:
1403
1404
1405
1406
1407
1408
1409 result = i2400m_cmd_get_state(i2400m);
1410error:
1411 if (result < 0)
1412 dev_err(dev, "failed to initialize the device: %d\n", result);
1413 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
1414 return result;
1415}
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428void i2400m_dev_shutdown(struct i2400m *i2400m)
1429{
1430 struct device *dev = i2400m_dev(i2400m);
1431
1432 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
1433 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
1434}
1435