This source file includes following definitions.
- i2400m_tlv_match
- i2400m_tlv_buffer_walk
- i2400m_tlv_find
- i2400m_msg_check_status
- i2400m_report_tlv_system_state
- i2400m_report_tlv_media_status
- i2400m_report_state_parse_tlv
- i2400m_report_state_hook
- i2400m_report_hook
- i2400m_msg_ack_hook
- i2400m_msg_size_check
- i2400m_msg_to_dev_cancel_wait
- i2400m_msg_to_dev
- i2400m_cmd_enter_powersave
- i2400m_get_device_info
- i2400m_firmware_check
- i2400m_cmd_exit_idle
- i2400m_cmd_get_state
- i2400m_set_init_config
- i2400m_set_idle_timeout
- i2400m_dev_initialize
- i2400m_dev_shutdown
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
88 static int i2400m_idle_mode_disabled;
89 module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
90 MODULE_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
95 static int i2400m_power_save_disabled;
96 module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
97 MODULE_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
103 static int i2400m_passive_mode;
104 module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
105 MODULE_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
123 static
124 ssize_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
160 static
161 const 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 }
202 error_short_header:
203 error_beyond_end:
204 return tlv_pos;
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223 static
224 const 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
245 static 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
282 int 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
310 static
311 void 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
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
387 static
388 void 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
432 static
433 void 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
480 static
481 void 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
514 void 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
564 static 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
598 int 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;
622 error_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
640 void 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
707 struct 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
819 error_bad_ack_type:
820 error_bad_ack_len:
821 kfree_skb(ack_skb);
822 error_ack_status:
823 error_wait_for_completion:
824 error_tx:
825 mutex_unlock(&i2400m->msg_mutex);
826 error_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
844 enum {
845 I2400M_WAKEUP_ENABLED = 0x01,
846 I2400M_WAKEUP_DISABLED = 0x02,
847 I2400M_TLV_TYPE_WAKEUP_MODE = 144,
848 };
849
850 struct 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
863 int 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);
900 error_msg_to_dev:
901 kfree(cmd);
902 error_alloc:
903 return result;
904 }
905 EXPORT_SYMBOL_GPL(i2400m_cmd_enter_powersave);
906
907
908
909
910
911 enum {
912 I2400M_TLV_DETAILED_DEVICE_INFO = 140
913 };
914
915
916
917
918
919
920
921
922
923
924
925
926
927 struct 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);
971 error_msg_to_dev:
972 kfree(cmd);
973 error_alloc:
974 return ack_skb;
975
976 error_no_tlv:
977 error_cmd_failed:
978 kfree_skb(ack_skb);
979 kfree(cmd);
980 return ERR_PTR(result);
981 }
982
983
984
985 enum {
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
1009 int 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);
1071 error_bad_major:
1072 error_no_tlv:
1073 error_cmd_failed:
1074 kfree_skb(ack_skb);
1075 error_msg_to_dev:
1076 kfree(cmd);
1077 error_alloc:
1078 return result;
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093 int 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);
1119 error_msg_to_dev:
1120 kfree(cmd);
1121 error_alloc:
1122 return result;
1123
1124 }
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141 static 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);
1177 error_cmd_failed:
1178 error_msg_to_dev:
1179 kfree(cmd);
1180 error_alloc:
1181 return result;
1182 }
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194 static 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);
1254 error_msg_to_dev:
1255 kfree(buf);
1256 error_alloc:
1257 none:
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
1282 int 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);
1327 error_cmd_failed:
1328 error_msg_to_dev:
1329 kfree(cmd);
1330 error_alloc:
1331 return result;
1332 }
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348 int 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;
1404 out_passive:
1405
1406
1407
1408
1409
1410
1411 result = i2400m_cmd_get_state(i2400m);
1412 error:
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
1430 void 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 }