Commit 3ee40c376ad3252d13946141588db7e2f435f958
Exists in
master
and in
7 other branches
Merge branch 'linux-2.6.31.y' of git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
Showing 14 changed files Side-by-side Diff
- drivers/net/wimax/i2400m/control.c
- drivers/net/wimax/i2400m/driver.c
- drivers/net/wimax/i2400m/fw.c
- drivers/net/wimax/i2400m/i2400m-sdio.h
- drivers/net/wimax/i2400m/i2400m.h
- drivers/net/wimax/i2400m/op-rfkill.c
- drivers/net/wimax/i2400m/rx.c
- drivers/net/wimax/i2400m/sdio-fw.c
- drivers/net/wimax/i2400m/sdio-rx.c
- drivers/net/wimax/i2400m/sdio.c
- drivers/net/wimax/i2400m/tx.c
- drivers/net/wimax/i2400m/usb.c
- include/linux/wimax/i2400m.h
- net/wimax/op-rfkill.c
drivers/net/wimax/i2400m/control.c
... | ... | @@ -505,8 +505,15 @@ |
505 | 505 | * it. */ |
506 | 506 | case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ |
507 | 507 | if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { |
508 | - d_printf(1, dev, "ready for powersave, requesting\n"); | |
509 | - i2400m_cmd_enter_powersave(i2400m); | |
508 | + if (i2400m_power_save_disabled) | |
509 | + d_printf(1, dev, "ready for powersave, " | |
510 | + "not requesting (disabled by module " | |
511 | + "parameter)\n"); | |
512 | + else { | |
513 | + d_printf(1, dev, "ready for powersave, " | |
514 | + "requesting\n"); | |
515 | + i2400m_cmd_enter_powersave(i2400m); | |
516 | + } | |
510 | 517 | } |
511 | 518 | break; |
512 | 519 | }; |
513 | 520 | |
... | ... | @@ -688,8 +695,9 @@ |
688 | 695 | d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", |
689 | 696 | i2400m, buf, buf_len); |
690 | 697 | |
698 | + rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ | |
691 | 699 | if (i2400m->boot_mode) |
692 | - return ERR_PTR(-ENODEV); | |
700 | + return ERR_PTR(-EL3RST); | |
693 | 701 | |
694 | 702 | msg_l3l4_hdr = buf; |
695 | 703 | /* Check msg & payload consistency */ |
696 | 704 | |
697 | 705 | |
... | ... | @@ -1389,17 +1397,17 @@ |
1389 | 1397 | * |
1390 | 1398 | * @i2400m: device descriptor |
1391 | 1399 | * |
1392 | - * Gracefully stops the device, moving it to the lowest power | |
1393 | - * consumption state possible. | |
1400 | + * Release resources acquired during the running of the device; in | |
1401 | + * theory, should also tell the device to go to sleep, switch off the | |
1402 | + * radio, all that, but at this point, in most cases (driver | |
1403 | + * disconnection, reset handling) we can't even talk to the device. | |
1394 | 1404 | */ |
1395 | 1405 | void i2400m_dev_shutdown(struct i2400m *i2400m) |
1396 | 1406 | { |
1397 | - int result = -ENODEV; | |
1398 | 1407 | struct device *dev = i2400m_dev(i2400m); |
1399 | 1408 | |
1400 | 1409 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
1401 | - result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); | |
1402 | - d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); | |
1410 | + d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | |
1403 | 1411 | return; |
1404 | 1412 | } |
drivers/net/wimax/i2400m/driver.c
... | ... | @@ -82,6 +82,14 @@ |
82 | 82 | MODULE_PARM_DESC(rx_reorder_disabled, |
83 | 83 | "If true, RX reordering will be disabled."); |
84 | 84 | |
85 | +int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */ | |
86 | +module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); | |
87 | +MODULE_PARM_DESC(power_save_disabled, | |
88 | + "If true, the driver will not tell the device to enter " | |
89 | + "power saving mode when it reports it is ready for it. " | |
90 | + "False by default (so the device is told to do power " | |
91 | + "saving)."); | |
92 | + | |
85 | 93 | /** |
86 | 94 | * i2400m_queue_work - schedule work on a i2400m's queue |
87 | 95 | * |
... | ... | @@ -172,7 +180,6 @@ |
172 | 180 | int result; |
173 | 181 | struct i2400m_work *iw; |
174 | 182 | |
175 | - BUG_ON(i2400m->work_queue == NULL); | |
176 | 183 | result = -ENOMEM; |
177 | 184 | iw = kzalloc(sizeof(*iw), gfp_flags); |
178 | 185 | if (iw == NULL) |
... | ... | @@ -377,6 +384,11 @@ |
377 | 384 | * Uploads firmware and brings up all the resources needed to be able |
378 | 385 | * to communicate with the device. |
379 | 386 | * |
387 | + * The workqueue has to be setup early, at least before RX handling | |
388 | + * (it's only real user for now) so it can process reports as they | |
389 | + * arrive. We also want to destroy it if we retry, to make sure it is | |
390 | + * flushed...easier like this. | |
391 | + * | |
380 | 392 | * TX needs to be setup before the bus-specific code (otherwise on |
381 | 393 | * shutdown, the bus-tx code could try to access it). |
382 | 394 | */ |
... | ... | @@ -387,7 +399,7 @@ |
387 | 399 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; |
388 | 400 | struct net_device *net_dev = wimax_dev->net_dev; |
389 | 401 | struct device *dev = i2400m_dev(i2400m); |
390 | - int times = 3; | |
402 | + int times = i2400m->bus_bm_retries; | |
391 | 403 | |
392 | 404 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
393 | 405 | retry: |
394 | 406 | |
... | ... | @@ -402,15 +414,15 @@ |
402 | 414 | result = i2400m_rx_setup(i2400m); |
403 | 415 | if (result < 0) |
404 | 416 | goto error_rx_setup; |
405 | - result = i2400m->bus_dev_start(i2400m); | |
406 | - if (result < 0) | |
407 | - goto error_bus_dev_start; | |
408 | 417 | i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); |
409 | 418 | if (i2400m->work_queue == NULL) { |
410 | 419 | result = -ENOMEM; |
411 | 420 | dev_err(dev, "cannot create workqueue\n"); |
412 | 421 | goto error_create_workqueue; |
413 | 422 | } |
423 | + result = i2400m->bus_dev_start(i2400m); | |
424 | + if (result < 0) | |
425 | + goto error_bus_dev_start; | |
414 | 426 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ |
415 | 427 | if (result < 0) |
416 | 428 | goto error_fw_check; |
417 | 429 | |
418 | 430 | |
... | ... | @@ -432,17 +444,17 @@ |
432 | 444 | error_dev_initialize: |
433 | 445 | error_check_mac_addr: |
434 | 446 | error_fw_check: |
435 | - destroy_workqueue(i2400m->work_queue); | |
436 | -error_create_workqueue: | |
437 | 447 | i2400m->bus_dev_stop(i2400m); |
438 | 448 | error_bus_dev_start: |
449 | + destroy_workqueue(i2400m->work_queue); | |
450 | +error_create_workqueue: | |
439 | 451 | i2400m_rx_release(i2400m); |
440 | 452 | error_rx_setup: |
441 | 453 | i2400m_tx_release(i2400m); |
442 | 454 | error_tx_setup: |
443 | 455 | error_bootstrap: |
444 | - if (result == -ERESTARTSYS && times-- > 0) { | |
445 | - flags = I2400M_BRI_SOFT; | |
456 | + if (result == -EL3RST && times-- > 0) { | |
457 | + flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; | |
446 | 458 | goto retry; |
447 | 459 | } |
448 | 460 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", |
... | ... | @@ -471,7 +483,9 @@ |
471 | 483 | * |
472 | 484 | * Returns: 0 if ok, < 0 errno code on error. |
473 | 485 | * |
474 | - * Releases all the resources allocated to communicate with the device. | |
486 | + * Releases all the resources allocated to communicate with the | |
487 | + * device. Note we cannot destroy the workqueue earlier as until RX is | |
488 | + * fully destroyed, it could still try to schedule jobs. | |
475 | 489 | */ |
476 | 490 | static |
477 | 491 | void __i2400m_dev_stop(struct i2400m *i2400m) |
478 | 492 | |
... | ... | @@ -483,8 +497,8 @@ |
483 | 497 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); |
484 | 498 | i2400m_dev_shutdown(i2400m); |
485 | 499 | i2400m->ready = 0; |
486 | - destroy_workqueue(i2400m->work_queue); | |
487 | 500 | i2400m->bus_dev_stop(i2400m); |
501 | + destroy_workqueue(i2400m->work_queue); | |
488 | 502 | i2400m_rx_release(i2400m); |
489 | 503 | i2400m_tx_release(i2400m); |
490 | 504 | wimax_state_change(wimax_dev, WIMAX_ST_DOWN); |
... | ... | @@ -546,7 +560,7 @@ |
546 | 560 | * i2400m_dev_stop() [we are shutting down anyway, so |
547 | 561 | * ignore it] or we are resetting somewhere else. */ |
548 | 562 | dev_err(dev, "device rebooted\n"); |
549 | - i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); | |
563 | + i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); | |
550 | 564 | complete(&i2400m->msg_completion); |
551 | 565 | goto out; |
552 | 566 | } |
... | ... | @@ -596,6 +610,8 @@ |
596 | 610 | */ |
597 | 611 | int i2400m_dev_reset_handle(struct i2400m *i2400m) |
598 | 612 | { |
613 | + i2400m->boot_mode = 1; | |
614 | + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ | |
599 | 615 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, |
600 | 616 | GFP_ATOMIC); |
601 | 617 | } |
drivers/net/wimax/i2400m/fw.c
... | ... | @@ -397,7 +397,7 @@ |
397 | 397 | unsigned int direct, unsigned int do_csum) |
398 | 398 | { |
399 | 399 | int ret; |
400 | - size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD); | |
400 | + size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); | |
401 | 401 | struct device *dev = i2400m_dev(i2400m); |
402 | 402 | struct { |
403 | 403 | struct i2400m_bootrom_header cmd; |
404 | 404 | |
... | ... | @@ -532,14 +532,14 @@ |
532 | 532 | cmd = (void *) bcf + offset; |
533 | 533 | if (i2400m->sboot == 0) { |
534 | 534 | struct i2400m_bootrom_header jump_ack; |
535 | - d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n", | |
535 | + d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", | |
536 | 536 | le32_to_cpu(cmd->target_addr)); |
537 | 537 | i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); |
538 | 538 | cmd->data_size = 0; |
539 | 539 | ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), |
540 | 540 | &jump_ack, sizeof(jump_ack), 0); |
541 | 541 | } else { |
542 | - d_printf(3, dev, "secure boot, jumping to 0x%08x\n", | |
542 | + d_printf(1, dev, "secure boot, jumping to 0x%08x\n", | |
543 | 543 | le32_to_cpu(cmd->target_addr)); |
544 | 544 | cmd_buf = i2400m->bm_cmd_buf; |
545 | 545 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); |
... | ... | @@ -696,8 +696,7 @@ |
696 | 696 | return result; |
697 | 697 | |
698 | 698 | error_timeout: |
699 | - dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); | |
700 | - i2400m->bus_reset(i2400m, I2400M_RT_BUS); | |
699 | + dev_err(dev, "Timed out waiting for reboot ack\n"); | |
701 | 700 | result = -ETIMEDOUT; |
702 | 701 | goto exit_timeout; |
703 | 702 | } |
704 | 703 | |
705 | 704 | |
... | ... | @@ -770,40 +769,21 @@ |
770 | 769 | static |
771 | 770 | int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) |
772 | 771 | { |
773 | -#define POKE(a, d) { \ | |
774 | - .address = cpu_to_le32(a), \ | |
775 | - .data = cpu_to_le32(d) \ | |
776 | -} | |
777 | - static const struct { | |
778 | - __le32 address; | |
779 | - __le32 data; | |
780 | - } i2400m_pokes[] = { | |
781 | - POKE(0x081A58, 0xA7810230), | |
782 | - POKE(0x080040, 0x00000000), | |
783 | - POKE(0x080048, 0x00000082), | |
784 | - POKE(0x08004C, 0x0000081F), | |
785 | - POKE(0x080054, 0x00000085), | |
786 | - POKE(0x080058, 0x00000180), | |
787 | - POKE(0x08005C, 0x00000018), | |
788 | - POKE(0x080060, 0x00000010), | |
789 | - POKE(0x080574, 0x00000001), | |
790 | - POKE(0x080550, 0x00000005), | |
791 | - POKE(0xAE0000, 0x00000000), | |
792 | - }; | |
793 | -#undef POKE | |
794 | - unsigned i; | |
795 | - int ret; | |
772 | + unsigned i = 0; | |
773 | + int ret = 0; | |
796 | 774 | struct device *dev = i2400m_dev(i2400m); |
797 | - | |
798 | - dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); | |
799 | - | |
800 | 775 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); |
801 | - for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { | |
802 | - ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, | |
803 | - sizeof(i2400m_pokes[i].data), | |
804 | - i2400m_pokes[i].address, 1, 1); | |
805 | - if (ret < 0) | |
806 | - break; | |
776 | + if (i2400m->bus_bm_pokes_table) { | |
777 | + while (i2400m->bus_bm_pokes_table[i].address) { | |
778 | + ret = i2400m_download_chunk( | |
779 | + i2400m, | |
780 | + &i2400m->bus_bm_pokes_table[i].data, | |
781 | + sizeof(i2400m->bus_bm_pokes_table[i].data), | |
782 | + i2400m->bus_bm_pokes_table[i].address, 1, 1); | |
783 | + if (ret < 0) | |
784 | + break; | |
785 | + i++; | |
786 | + } | |
807 | 787 | } |
808 | 788 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); |
809 | 789 | return ret; |
810 | 790 | |
... | ... | @@ -980,11 +960,12 @@ |
980 | 960 | { |
981 | 961 | int ret = 0; |
982 | 962 | struct device *dev = i2400m_dev(i2400m); |
983 | - int count = I2400M_BOOT_RETRIES; | |
963 | + int count = i2400m->bus_bm_retries; | |
984 | 964 | |
985 | 965 | d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", |
986 | 966 | i2400m, bcf, bcf_size); |
987 | 967 | i2400m->boot_mode = 1; |
968 | + wmb(); /* Make sure other readers see it */ | |
988 | 969 | hw_reboot: |
989 | 970 | if (count-- == 0) { |
990 | 971 | ret = -ERESTARTSYS; |
... | ... | @@ -1033,6 +1014,7 @@ |
1033 | 1014 | d_printf(2, dev, "fw %s successfully uploaded\n", |
1034 | 1015 | i2400m->fw_name); |
1035 | 1016 | i2400m->boot_mode = 0; |
1017 | + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ | |
1036 | 1018 | error_dnload_finalize: |
1037 | 1019 | error_dnload_bcf: |
1038 | 1020 | error_dnload_init: |
drivers/net/wimax/i2400m/i2400m-sdio.h
... | ... | @@ -78,6 +78,8 @@ |
78 | 78 | /* The number of ticks to wait for the device to signal that |
79 | 79 | * it is ready */ |
80 | 80 | I2400MS_INIT_SLEEP_INTERVAL = 10, |
81 | + /* How long to wait for the device to settle after reset */ | |
82 | + I2400MS_SETTLE_TIME = 40, | |
81 | 83 | }; |
82 | 84 | |
83 | 85 | |
... | ... | @@ -105,6 +107,10 @@ |
105 | 107 | char tx_wq_name[32]; |
106 | 108 | |
107 | 109 | struct dentry *debugfs_dentry; |
110 | + | |
111 | + wait_queue_head_t bm_wfa_wq; | |
112 | + int bm_wait_result; | |
113 | + size_t bm_ack_size; | |
108 | 114 | }; |
109 | 115 | |
110 | 116 | |
... | ... | @@ -129,5 +135,8 @@ |
129 | 135 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, |
130 | 136 | struct i2400m_bootrom_header *, |
131 | 137 | size_t); |
138 | +extern void i2400ms_bus_bm_release(struct i2400m *); | |
139 | +extern int i2400ms_bus_bm_setup(struct i2400m *); | |
140 | + | |
132 | 141 | #endif /* #ifndef __I2400M_SDIO_H__ */ |
drivers/net/wimax/i2400m/i2400m.h
... | ... | @@ -150,12 +150,34 @@ |
150 | 150 | enum { |
151 | 151 | /* Firmware uploading */ |
152 | 152 | I2400M_BOOT_RETRIES = 3, |
153 | + I3200_BOOT_RETRIES = 3, | |
153 | 154 | /* Size of the Boot Mode Command buffer */ |
154 | 155 | I2400M_BM_CMD_BUF_SIZE = 16 * 1024, |
155 | 156 | I2400M_BM_ACK_BUF_SIZE = 256, |
156 | 157 | }; |
157 | 158 | |
159 | +/** | |
160 | + * struct i2400m_poke_table - Hardware poke table for the Intel 2400m | |
161 | + * | |
162 | + * This structure will be used to create a device specific poke table | |
163 | + * to put the device in a consistant state at boot time. | |
164 | + * | |
165 | + * @address: The device address to poke | |
166 | + * | |
167 | + * @data: The data value to poke to the device address | |
168 | + * | |
169 | + */ | |
170 | +struct i2400m_poke_table{ | |
171 | + __le32 address; | |
172 | + __le32 data; | |
173 | +}; | |
158 | 174 | |
175 | +#define I2400M_FW_POKE(a, d) { \ | |
176 | + .address = cpu_to_le32(a), \ | |
177 | + .data = cpu_to_le32(d) \ | |
178 | +} | |
179 | + | |
180 | + | |
159 | 181 | /** |
160 | 182 | * i2400m_reset_type - methods to reset a device |
161 | 183 | * |
... | ... | @@ -224,6 +246,17 @@ |
224 | 246 | * process, so it cannot rely on common infrastructure being laid |
225 | 247 | * out. |
226 | 248 | * |
249 | + * @bus_bm_retries: [fill] How many times shall a firmware upload / | |
250 | + * device initialization be retried? Different models of the same | |
251 | + * device might need different values, hence it is set by the | |
252 | + * bus-specific driver. Note this value is used in two places, | |
253 | + * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become | |
254 | + * multiplicative (__i2400m_dev_start() calling N times | |
255 | + * i2400m_fw_dnload() and this trying N times to download the | |
256 | + * firmware), as if __i2400m_dev_start() only retries if the | |
257 | + * firmware crashed while initializing the device (not in a | |
258 | + * general case). | |
259 | + * | |
227 | 260 | * @bus_bm_cmd_send: [fill] Function called to send a boot-mode |
228 | 261 | * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This |
229 | 262 | * is synchronous and has to return 0 if ok or < 0 errno code in |
230 | 263 | |
... | ... | @@ -252,7 +285,13 @@ |
252 | 285 | * address provided in boot mode is kind of broken and needs to |
253 | 286 | * be re-read later on. |
254 | 287 | * |
288 | + * @bus_bm_pokes_table: [fill/optional] A table of device addresses | |
289 | + * and values that will be poked at device init time to move the | |
290 | + * device to the correct state for the type of boot/firmware being | |
291 | + * used. This table MUST be terminated with (0x000000, | |
292 | + * 0x00000000) or bad things will happen. | |
255 | 293 | * |
294 | + * | |
256 | 295 | * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX |
257 | 296 | * stack. Due to the way a net_device is allocated, we need to |
258 | 297 | * force this to be the first field so that we can get from |
... | ... | @@ -399,6 +438,8 @@ |
399 | 438 | |
400 | 439 | size_t bus_tx_block_size; |
401 | 440 | size_t bus_pl_size_max; |
441 | + unsigned bus_bm_retries; | |
442 | + | |
402 | 443 | int (*bus_dev_start)(struct i2400m *); |
403 | 444 | void (*bus_dev_stop)(struct i2400m *); |
404 | 445 | void (*bus_tx_kick)(struct i2400m *); |
... | ... | @@ -410,6 +451,7 @@ |
410 | 451 | struct i2400m_bootrom_header *, size_t); |
411 | 452 | const char **bus_fw_names; |
412 | 453 | unsigned bus_bm_mac_addr_impaired:1; |
454 | + const struct i2400m_poke_table *bus_bm_pokes_table; | |
413 | 455 | |
414 | 456 | spinlock_t tx_lock; /* protect TX state */ |
415 | 457 | void *tx_buf; |
... | ... | @@ -709,6 +751,7 @@ |
709 | 751 | cpu_to_le32(I2400M_SBOOT_BARKER) |
710 | 752 | }; |
711 | 753 | |
754 | +extern int i2400m_power_save_disabled; | |
712 | 755 | |
713 | 756 | /* |
714 | 757 | * Utility functions |
drivers/net/wimax/i2400m/op-rfkill.c
drivers/net/wimax/i2400m/rx.c
... | ... | @@ -1148,7 +1148,7 @@ |
1148 | 1148 | num_pls = le16_to_cpu(msg_hdr->num_pls); |
1149 | 1149 | pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ |
1150 | 1150 | num_pls * sizeof(msg_hdr->pld[0]); |
1151 | - pl_itr = ALIGN(pl_itr, I2400M_PL_PAD); | |
1151 | + pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN); | |
1152 | 1152 | if (pl_itr > skb->len) { /* got all the payload descriptors? */ |
1153 | 1153 | dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " |
1154 | 1154 | "%u payload descriptors (%zu each, total %zu)\n", |
... | ... | @@ -1166,7 +1166,7 @@ |
1166 | 1166 | single_last = num_pls == 1 || i == num_pls - 1; |
1167 | 1167 | i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], |
1168 | 1168 | skb->data + pl_itr); |
1169 | - pl_itr += ALIGN(pl_size, I2400M_PL_PAD); | |
1169 | + pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN); | |
1170 | 1170 | cond_resched(); /* Don't monopolize */ |
1171 | 1171 | } |
1172 | 1172 | kfree_skb(skb); |
drivers/net/wimax/i2400m/sdio-fw.c
... | ... | @@ -46,17 +46,24 @@ |
46 | 46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
47 | 47 | * - SDIO rehash for changes in the bus-driver model |
48 | 48 | * |
49 | + * Dirk Brandewie <dirk.j.brandewie@intel.com> | |
50 | + * - Make it IRQ based, not polling | |
51 | + * | |
49 | 52 | * THE PROCEDURE |
50 | 53 | * |
51 | 54 | * See fw.c for the generic description of this procedure. |
52 | 55 | * |
53 | 56 | * This file implements only the SDIO specifics. It boils down to how |
54 | 57 | * to send a command and waiting for an acknowledgement from the |
55 | - * device. We do polled reads. | |
58 | + * device. | |
56 | 59 | * |
60 | + * All this code is sequential -- all i2400ms_bus_bm_*() functions are | |
61 | + * executed in the same thread, except i2400ms_bm_irq() [on its own by | |
62 | + * the SDIO driver]. This makes it possible to avoid locking. | |
63 | + * | |
57 | 64 | * COMMAND EXECUTION |
58 | 65 | * |
59 | - * THe generic firmware upload code will call i2400m_bus_bm_cmd_send() | |
66 | + * The generic firmware upload code will call i2400m_bus_bm_cmd_send() | |
60 | 67 | * to send commands. |
61 | 68 | * |
62 | 69 | * The SDIO devices expects things in 256 byte blocks, so it will pad |
63 | 70 | |
... | ... | @@ -64,12 +71,15 @@ |
64 | 71 | * |
65 | 72 | * ACK RECEPTION |
66 | 73 | * |
67 | - * This works in polling mode -- the fw loader says when to wait for | |
68 | - * data and for that it calls i2400ms_bus_bm_wait_for_ack(). | |
74 | + * This works in IRQ mode -- the fw loader says when to wait for data | |
75 | + * and for that it calls i2400ms_bus_bm_wait_for_ack(). | |
69 | 76 | * |
70 | - * This will poll the device for data until it is received. We need to | |
71 | - * receive at least as much bytes as where asked for (although it'll | |
72 | - * always be a multiple of 256 bytes). | |
77 | + * This checks if there is any data available (RX size > 0); if not, | |
78 | + * waits for the IRQ handler to notify about it. Once there is data, | |
79 | + * it is read and passed to the caller. Doing it this way we don't | |
80 | + * need much coordination/locking, and it makes it much more difficult | |
81 | + * for an interrupt to be lost and the wait_for_ack() function getting | |
82 | + * stuck even when data is pending. | |
73 | 83 | */ |
74 | 84 | #include <linux/mmc/sdio_func.h> |
75 | 85 | #include "i2400m-sdio.h" |
... | ... | @@ -78,6 +88,7 @@ |
78 | 88 | #define D_SUBMODULE fw |
79 | 89 | #include "sdio-debug-levels.h" |
80 | 90 | |
91 | + | |
81 | 92 | /* |
82 | 93 | * Send a boot-mode command to the SDIO function |
83 | 94 | * |
... | ... | @@ -139,7 +150,7 @@ |
139 | 150 | |
140 | 151 | |
141 | 152 | /* |
142 | - * Read an ack from the device's boot-mode (polling) | |
153 | + * Read an ack from the device's boot-mode | |
143 | 154 | * |
144 | 155 | * @i2400m: |
145 | 156 | * @_ack: pointer to where to store the read data |
146 | 157 | |
147 | 158 | |
148 | 159 | |
149 | 160 | |
150 | 161 | |
151 | 162 | |
... | ... | @@ -150,76 +161,50 @@ |
150 | 161 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so |
151 | 162 | * check for that. We don't need to check for device reboots |
152 | 163 | * |
153 | - * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout; | |
154 | - * this way we have control over it...there is no way that I know | |
155 | - * of setting an SDIO transaction timeout. | |
156 | 164 | */ |
157 | 165 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, |
158 | 166 | struct i2400m_bootrom_header *ack, |
159 | 167 | size_t ack_size) |
160 | 168 | { |
161 | - int result; | |
162 | - ssize_t rx_size; | |
163 | - u64 timeout; | |
169 | + ssize_t result; | |
164 | 170 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); |
165 | 171 | struct sdio_func *func = i2400ms->func; |
166 | 172 | struct device *dev = &func->dev; |
173 | + int size; | |
167 | 174 | |
168 | 175 | BUG_ON(sizeof(*ack) > ack_size); |
169 | 176 | |
170 | 177 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", |
171 | 178 | i2400m, ack, ack_size); |
172 | 179 | |
173 | - timeout = get_jiffies_64() + 2 * HZ; | |
174 | - sdio_claim_host(func); | |
175 | - while (1) { | |
176 | - if (time_after64(get_jiffies_64(), timeout)) { | |
177 | - rx_size = -ETIMEDOUT; | |
178 | - dev_err(dev, "timeout waiting for ack data\n"); | |
179 | - goto error_timedout; | |
180 | - } | |
180 | + spin_lock(&i2400m->rx_lock); | |
181 | + i2400ms->bm_ack_size = -EINPROGRESS; | |
182 | + spin_unlock(&i2400m->rx_lock); | |
181 | 183 | |
182 | - /* Find the RX size, check if it fits or not -- it if | |
183 | - * doesn't fit, fail, as we have no way to dispose of | |
184 | - * the extra data. */ | |
185 | - rx_size = __i2400ms_rx_get_size(i2400ms); | |
186 | - if (rx_size < 0) | |
187 | - goto error_rx_get_size; | |
188 | - result = -ENOSPC; /* Check it fits */ | |
189 | - if (rx_size < sizeof(*ack)) { | |
190 | - rx_size = -EIO; | |
191 | - dev_err(dev, "HW BUG? received is too small (%zu vs " | |
192 | - "%zu needed)\n", sizeof(*ack), rx_size); | |
193 | - goto error_too_small; | |
194 | - } | |
195 | - if (rx_size > I2400M_BM_ACK_BUF_SIZE) { | |
196 | - dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs " | |
197 | - "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE, | |
198 | - rx_size); | |
199 | - goto error_too_small; | |
200 | - } | |
184 | + result = wait_event_timeout(i2400ms->bm_wfa_wq, | |
185 | + i2400ms->bm_ack_size != -EINPROGRESS, | |
186 | + 2 * HZ); | |
187 | + if (result == 0) { | |
188 | + result = -ETIMEDOUT; | |
189 | + dev_err(dev, "BM: error waiting for an ack\n"); | |
190 | + goto error_timeout; | |
191 | + } | |
201 | 192 | |
202 | - /* Read it */ | |
203 | - result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, | |
204 | - I2400MS_DATA_ADDR, rx_size); | |
205 | - if (result == -ETIMEDOUT || result == -ETIME) | |
206 | - continue; | |
207 | - if (result < 0) { | |
208 | - dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", | |
209 | - rx_size, result); | |
210 | - goto error_read; | |
211 | - } else | |
212 | - break; | |
193 | + spin_lock(&i2400m->rx_lock); | |
194 | + result = i2400ms->bm_ack_size; | |
195 | + BUG_ON(result == -EINPROGRESS); | |
196 | + if (result < 0) /* so we exit when rx_release() is called */ | |
197 | + dev_err(dev, "BM: %s failed: %zd\n", __func__, result); | |
198 | + else { | |
199 | + size = min(ack_size, i2400ms->bm_ack_size); | |
200 | + memcpy(ack, i2400m->bm_ack_buf, size); | |
213 | 201 | } |
214 | - rx_size = min((ssize_t)ack_size, rx_size); | |
215 | - memcpy(ack, i2400m->bm_ack_buf, rx_size); | |
216 | -error_read: | |
217 | -error_too_small: | |
218 | -error_rx_get_size: | |
219 | -error_timedout: | |
220 | - sdio_release_host(func); | |
221 | - d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n", | |
222 | - i2400m, ack, ack_size, (long) rx_size); | |
223 | - return rx_size; | |
202 | + i2400ms->bm_ack_size = -EINPROGRESS; | |
203 | + spin_unlock(&i2400m->rx_lock); | |
204 | + | |
205 | +error_timeout: | |
206 | + d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", | |
207 | + i2400m, ack, ack_size, result); | |
208 | + return result; | |
224 | 209 | } |
drivers/net/wimax/i2400m/sdio-rx.c
... | ... | @@ -69,7 +69,14 @@ |
69 | 69 | #define D_SUBMODULE rx |
70 | 70 | #include "sdio-debug-levels.h" |
71 | 71 | |
72 | +static const __le32 i2400m_ACK_BARKER[4] = { | |
73 | + __constant_cpu_to_le32(I2400M_ACK_BARKER), | |
74 | + __constant_cpu_to_le32(I2400M_ACK_BARKER), | |
75 | + __constant_cpu_to_le32(I2400M_ACK_BARKER), | |
76 | + __constant_cpu_to_le32(I2400M_ACK_BARKER) | |
77 | +}; | |
72 | 78 | |
79 | + | |
73 | 80 | /* |
74 | 81 | * Read and return the amount of bytes available for RX |
75 | 82 | * |
76 | 83 | |
77 | 84 | |
78 | 85 | |
... | ... | @@ -131,25 +138,35 @@ |
131 | 138 | ret = rx_size; |
132 | 139 | goto error_get_size; |
133 | 140 | } |
141 | + | |
134 | 142 | ret = -ENOMEM; |
135 | 143 | skb = alloc_skb(rx_size, GFP_ATOMIC); |
136 | 144 | if (NULL == skb) { |
137 | 145 | dev_err(dev, "RX: unable to alloc skb\n"); |
138 | 146 | goto error_alloc_skb; |
139 | 147 | } |
140 | - | |
141 | 148 | ret = sdio_memcpy_fromio(func, skb->data, |
142 | 149 | I2400MS_DATA_ADDR, rx_size); |
143 | 150 | if (ret < 0) { |
144 | 151 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); |
145 | 152 | goto error_memcpy_fromio; |
146 | 153 | } |
147 | - /* Check if device has reset */ | |
148 | - if (!memcmp(skb->data, i2400m_NBOOT_BARKER, | |
149 | - sizeof(i2400m_NBOOT_BARKER)) | |
150 | - || !memcmp(skb->data, i2400m_SBOOT_BARKER, | |
151 | - sizeof(i2400m_SBOOT_BARKER))) { | |
154 | + | |
155 | + rmb(); /* make sure we get boot_mode from dev_reset_handle */ | |
156 | + if (i2400m->boot_mode == 1) { | |
157 | + spin_lock(&i2400m->rx_lock); | |
158 | + i2400ms->bm_ack_size = rx_size; | |
159 | + spin_unlock(&i2400m->rx_lock); | |
160 | + memcpy(i2400m->bm_ack_buf, skb->data, rx_size); | |
161 | + wake_up(&i2400ms->bm_wfa_wq); | |
162 | + dev_err(dev, "RX: SDIO boot mode message\n"); | |
163 | + kfree_skb(skb); | |
164 | + } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, | |
165 | + sizeof(i2400m_NBOOT_BARKER)) | |
166 | + || !memcmp(skb->data, i2400m_SBOOT_BARKER, | |
167 | + sizeof(i2400m_SBOOT_BARKER)))) { | |
152 | 168 | ret = i2400m_dev_reset_handle(i2400m); |
169 | + dev_err(dev, "RX: SDIO reboot barker\n"); | |
153 | 170 | kfree_skb(skb); |
154 | 171 | } else { |
155 | 172 | skb_put(skb, rx_size); |
... | ... | @@ -179,7 +196,6 @@ |
179 | 196 | { |
180 | 197 | int ret; |
181 | 198 | struct i2400ms *i2400ms = sdio_get_drvdata(func); |
182 | - struct i2400m *i2400m = &i2400ms->i2400m; | |
183 | 199 | struct device *dev = &func->dev; |
184 | 200 | int val; |
185 | 201 | |
... | ... | @@ -194,10 +210,7 @@ |
194 | 210 | goto error_no_irq; |
195 | 211 | } |
196 | 212 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); |
197 | - if (WARN_ON(i2400m->boot_mode != 0)) | |
198 | - dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n"); | |
199 | - else | |
200 | - i2400ms_rx(i2400ms); | |
213 | + i2400ms_rx(i2400ms); | |
201 | 214 | error_no_irq: |
202 | 215 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); |
203 | 216 | return; |
204 | 217 | |
... | ... | @@ -214,8 +227,15 @@ |
214 | 227 | int result; |
215 | 228 | struct sdio_func *func = i2400ms->func; |
216 | 229 | struct device *dev = &func->dev; |
230 | + struct i2400m *i2400m = &i2400ms->i2400m; | |
217 | 231 | |
218 | 232 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); |
233 | + | |
234 | + init_waitqueue_head(&i2400ms->bm_wfa_wq); | |
235 | + spin_lock(&i2400m->rx_lock); | |
236 | + i2400ms->bm_wait_result = -EINPROGRESS; | |
237 | + spin_unlock(&i2400m->rx_lock); | |
238 | + | |
219 | 239 | sdio_claim_host(func); |
220 | 240 | result = sdio_claim_irq(func, i2400ms_irq); |
221 | 241 | if (result < 0) { |
222 | 242 | |
... | ... | @@ -245,8 +265,13 @@ |
245 | 265 | int result; |
246 | 266 | struct sdio_func *func = i2400ms->func; |
247 | 267 | struct device *dev = &func->dev; |
268 | + struct i2400m *i2400m = &i2400ms->i2400m; | |
248 | 269 | |
249 | 270 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); |
271 | + spin_lock(&i2400m->rx_lock); | |
272 | + i2400ms->bm_ack_size = -EINTR; | |
273 | + spin_unlock(&i2400m->rx_lock); | |
274 | + wake_up_all(&i2400ms->bm_wfa_wq); | |
250 | 275 | sdio_claim_host(func); |
251 | 276 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); |
252 | 277 | sdio_release_irq(func); |
drivers/net/wimax/i2400m/sdio.c
... | ... | @@ -78,6 +78,14 @@ |
78 | 78 | }; |
79 | 79 | |
80 | 80 | |
81 | +static const struct i2400m_poke_table i2400ms_pokes[] = { | |
82 | + I2400M_FW_POKE(0x6BE260, 0x00000088), | |
83 | + I2400M_FW_POKE(0x080550, 0x00000005), | |
84 | + I2400M_FW_POKE(0xAE0000, 0x00000000), | |
85 | + I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad | |
86 | + * things will happen */ | |
87 | +}; | |
88 | + | |
81 | 89 | /* |
82 | 90 | * Enable the SDIO function |
83 | 91 | * |
84 | 92 | |
85 | 93 | |
... | ... | @@ -148,19 +156,14 @@ |
148 | 156 | |
149 | 157 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
150 | 158 | msleep(200); |
151 | - result = i2400ms_rx_setup(i2400ms); | |
152 | - if (result < 0) | |
153 | - goto error_rx_setup; | |
154 | 159 | result = i2400ms_tx_setup(i2400ms); |
155 | 160 | if (result < 0) |
156 | 161 | goto error_tx_setup; |
157 | 162 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); |
158 | 163 | return result; |
159 | 164 | |
160 | - i2400ms_tx_release(i2400ms); | |
161 | 165 | error_tx_setup: |
162 | - i2400ms_rx_release(i2400ms); | |
163 | -error_rx_setup: | |
166 | + i2400ms_tx_release(i2400ms); | |
164 | 167 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
165 | 168 | return result; |
166 | 169 | } |
... | ... | @@ -174,7 +177,6 @@ |
174 | 177 | struct device *dev = &func->dev; |
175 | 178 | |
176 | 179 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
177 | - i2400ms_rx_release(i2400ms); | |
178 | 180 | i2400ms_tx_release(i2400ms); |
179 | 181 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
180 | 182 | } |
... | ... | @@ -255,7 +257,7 @@ |
255 | 257 | static |
256 | 258 | int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) |
257 | 259 | { |
258 | - int result; | |
260 | + int result = 0; | |
259 | 261 | struct i2400ms *i2400ms = |
260 | 262 | container_of(i2400m, struct i2400ms, i2400m); |
261 | 263 | struct device *dev = i2400m_dev(i2400m); |
... | ... | @@ -280,8 +282,25 @@ |
280 | 282 | sizeof(i2400m_COLD_BOOT_BARKER)); |
281 | 283 | else if (rt == I2400M_RT_BUS) { |
282 | 284 | do_bus_reset: |
283 | - dev_err(dev, "FIXME: SDIO bus reset not implemented\n"); | |
284 | - result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS; | |
285 | + /* call netif_tx_disable() before sending IOE disable, | |
286 | + * so that all the tx from network layer are stopped | |
287 | + * while IOE is being reset. Make sure it is called | |
288 | + * only after register_netdev() was issued. | |
289 | + */ | |
290 | + if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) | |
291 | + netif_tx_disable(i2400m->wimax_dev.net_dev); | |
292 | + | |
293 | + i2400ms_rx_release(i2400ms); | |
294 | + sdio_claim_host(i2400ms->func); | |
295 | + sdio_disable_func(i2400ms->func); | |
296 | + sdio_release_host(i2400ms->func); | |
297 | + | |
298 | + /* Wait for the device to settle */ | |
299 | + msleep(40); | |
300 | + | |
301 | + result = i2400ms_enable_function(i2400ms->func); | |
302 | + if (result >= 0) | |
303 | + i2400ms_rx_setup(i2400ms); | |
285 | 304 | } else |
286 | 305 | BUG(); |
287 | 306 | if (result < 0 && rt != I2400M_RT_BUS) { |
288 | 307 | |
... | ... | @@ -404,10 +423,14 @@ |
404 | 423 | i2400m->bus_dev_stop = i2400ms_bus_dev_stop; |
405 | 424 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; |
406 | 425 | i2400m->bus_reset = i2400ms_bus_reset; |
426 | + /* The iwmc3200-wimax sometimes requires the driver to try | |
427 | + * hard when we paint it into a corner. */ | |
428 | + i2400m->bus_bm_retries = I3200_BOOT_RETRIES; | |
407 | 429 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; |
408 | 430 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; |
409 | 431 | i2400m->bus_fw_names = i2400ms_bus_fw_names; |
410 | 432 | i2400m->bus_bm_mac_addr_impaired = 1; |
433 | + i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; | |
411 | 434 | |
412 | 435 | sdio_claim_host(func); |
413 | 436 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); |
... | ... | @@ -423,6 +446,10 @@ |
423 | 446 | goto error_func_enable; |
424 | 447 | } |
425 | 448 | |
449 | + result = i2400ms_rx_setup(i2400ms); | |
450 | + if (result < 0) | |
451 | + goto error_rx_setup; | |
452 | + | |
426 | 453 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); |
427 | 454 | if (result < 0) { |
428 | 455 | dev_err(dev, "cannot setup device: %d\n", result); |
... | ... | @@ -440,6 +467,8 @@ |
440 | 467 | error_debugfs_add: |
441 | 468 | i2400m_release(i2400m); |
442 | 469 | error_setup: |
470 | + i2400ms_rx_release(i2400ms); | |
471 | +error_rx_setup: | |
443 | 472 | sdio_claim_host(func); |
444 | 473 | sdio_disable_func(func); |
445 | 474 | sdio_release_host(func); |
... | ... | @@ -462,6 +491,7 @@ |
462 | 491 | |
463 | 492 | d_fnstart(3, dev, "SDIO func %p\n", func); |
464 | 493 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
494 | + i2400ms_rx_release(i2400ms); | |
465 | 495 | i2400m_release(i2400m); |
466 | 496 | sdio_set_drvdata(func, NULL); |
467 | 497 | sdio_claim_host(func); |
drivers/net/wimax/i2400m/tx.c
... | ... | @@ -278,6 +278,48 @@ |
278 | 278 | #define TAIL_FULL ((void *)~(unsigned long)NULL) |
279 | 279 | |
280 | 280 | /* |
281 | + * Calculate how much tail room is available | |
282 | + * | |
283 | + * Note the trick here. This path is ONLY caleed for Case A (see | |
284 | + * i2400m_tx_fifo_push() below), where we have: | |
285 | + * | |
286 | + * Case A | |
287 | + * N ___________ | |
288 | + * | tail room | | |
289 | + * | | | |
290 | + * |<- IN ->| | |
291 | + * | | | |
292 | + * | data | | |
293 | + * | | | |
294 | + * |<- OUT ->| | |
295 | + * | | | |
296 | + * | head room | | |
297 | + * 0 ----------- | |
298 | + * | |
299 | + * When calculating the tail_room, tx_in might get to be zero if | |
300 | + * i2400m->tx_in is right at the end of the buffer (really full | |
301 | + * buffer) if there is no head room. In this case, tail_room would be | |
302 | + * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final | |
303 | + * mod (%) operation. However, when doing this kind of optimization, | |
304 | + * i2400m->tx_in being zero would fail, so we treat is an a special | |
305 | + * case. | |
306 | + */ | |
307 | +static inline | |
308 | +size_t __i2400m_tx_tail_room(struct i2400m *i2400m) | |
309 | +{ | |
310 | + size_t tail_room; | |
311 | + size_t tx_in; | |
312 | + | |
313 | + if (unlikely(i2400m->tx_in) == 0) | |
314 | + return I2400M_TX_BUF_SIZE; | |
315 | + tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; | |
316 | + tail_room = I2400M_TX_BUF_SIZE - tx_in; | |
317 | + tail_room %= I2400M_TX_BUF_SIZE; | |
318 | + return tail_room; | |
319 | +} | |
320 | + | |
321 | + | |
322 | +/* | |
281 | 323 | * Allocate @size bytes in the TX fifo, return a pointer to it |
282 | 324 | * |
283 | 325 | * @i2400m: device descriptor |
... | ... | @@ -338,7 +380,7 @@ |
338 | 380 | return NULL; |
339 | 381 | } |
340 | 382 | /* Is there space at the tail? */ |
341 | - tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE; | |
383 | + tail_room = __i2400m_tx_tail_room(i2400m); | |
342 | 384 | if (tail_room < needed_size) { |
343 | 385 | if (i2400m->tx_out % I2400M_TX_BUF_SIZE |
344 | 386 | < i2400m->tx_in % I2400M_TX_BUF_SIZE) { |
345 | 387 | |
346 | 388 | |
347 | 389 | |
... | ... | @@ -367,17 +409,29 @@ |
367 | 409 | * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the |
368 | 410 | * header). |
369 | 411 | * |
412 | + * Tail room can get to be zero if a message was opened when there was | |
413 | + * space only for a header. _tx_close() will mark it as to-skip (as it | |
414 | + * will have no payloads) and there will be no more space to flush, so | |
415 | + * nothing has to be done here. This is probably cheaper than ensuring | |
416 | + * in _tx_new() that there is some space for payloads...as we could | |
417 | + * always possibly hit the same problem if the payload wouldn't fit. | |
418 | + * | |
370 | 419 | * Note: |
371 | 420 | * |
372 | 421 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier |
422 | + * | |
423 | + * This path is only taken for Case A FIFO situations [see | |
424 | + * i2400m_tx_fifo_push()] | |
373 | 425 | */ |
374 | 426 | static |
375 | 427 | void i2400m_tx_skip_tail(struct i2400m *i2400m) |
376 | 428 | { |
377 | 429 | struct device *dev = i2400m_dev(i2400m); |
378 | 430 | size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; |
379 | - size_t tail_room = I2400M_TX_BUF_SIZE - tx_in; | |
431 | + size_t tail_room = __i2400m_tx_tail_room(i2400m); | |
380 | 432 | struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; |
433 | + if (unlikely(tail_room == 0)) | |
434 | + return; | |
381 | 435 | BUG_ON(tail_room < sizeof(*msg)); |
382 | 436 | msg->size = tail_room | I2400M_TX_SKIP; |
383 | 437 | d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", |
384 | 438 | |
... | ... | @@ -474,10 +528,18 @@ |
474 | 528 | struct i2400m_msg_hdr *tx_msg_moved; |
475 | 529 | size_t aligned_size, padding, hdr_size; |
476 | 530 | void *pad_buf; |
531 | + unsigned num_pls; | |
477 | 532 | |
478 | 533 | if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ |
479 | 534 | goto out; |
480 | - | |
535 | + num_pls = le16_to_cpu(tx_msg->num_pls); | |
536 | + /* We can get this situation when a new message was started | |
537 | + * and there was no space to add payloads before hitting the | |
538 | + tail (and taking padding into consideration). */ | |
539 | + if (num_pls == 0) { | |
540 | + tx_msg->size |= I2400M_TX_SKIP; | |
541 | + goto out; | |
542 | + } | |
481 | 543 | /* Relocate the message header |
482 | 544 | * |
483 | 545 | * Find the current header size, align it to 16 and if we need |
... | ... | @@ -491,7 +553,7 @@ |
491 | 553 | */ |
492 | 554 | hdr_size = sizeof(*tx_msg) |
493 | 555 | + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); |
494 | - hdr_size = ALIGN(hdr_size, I2400M_PL_PAD); | |
556 | + hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN); | |
495 | 557 | tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; |
496 | 558 | tx_msg_moved = (void *) tx_msg + tx_msg->offset; |
497 | 559 | memmove(tx_msg_moved, tx_msg, hdr_size); |
... | ... | @@ -574,7 +636,7 @@ |
574 | 636 | |
575 | 637 | d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", |
576 | 638 | i2400m, buf, buf_len, pl_type); |
577 | - padded_len = ALIGN(buf_len, I2400M_PL_PAD); | |
639 | + padded_len = ALIGN(buf_len, I2400M_PL_ALIGN); | |
578 | 640 | d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); |
579 | 641 | /* If there is no current TX message, create one; if the |
580 | 642 | * current one is out of payload slots or we have a singleton, |
... | ... | @@ -591,6 +653,8 @@ |
591 | 653 | i2400m_tx_close(i2400m); |
592 | 654 | i2400m_tx_new(i2400m); |
593 | 655 | } |
656 | + if (i2400m->tx_msg == NULL) | |
657 | + goto error_tx_new; | |
594 | 658 | if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { |
595 | 659 | d_printf(2, dev, "TX: message too big, going new\n"); |
596 | 660 | i2400m_tx_close(i2400m); |
... | ... | @@ -773,7 +837,6 @@ |
773 | 837 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; |
774 | 838 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; |
775 | 839 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; |
776 | - netif_start_queue(i2400m->wimax_dev.net_dev); | |
777 | 840 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); |
778 | 841 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
779 | 842 | } |
drivers/net/wimax/i2400m/usb.c
... | ... | @@ -254,8 +254,10 @@ |
254 | 254 | dev_err(dev, "USB reset failed (%d), giving up!\n", |
255 | 255 | result); |
256 | 256 | } |
257 | - } else | |
257 | + } else { | |
258 | + result = -EINVAL; /* shut gcc up in certain arches */ | |
258 | 259 | BUG(); |
260 | + } | |
259 | 261 | if (result < 0 |
260 | 262 | && result != -EINVAL /* device is gone */ |
261 | 263 | && rt != I2400M_RT_BUS) { |
... | ... | @@ -399,6 +401,7 @@ |
399 | 401 | i2400m->bus_dev_stop = i2400mu_bus_dev_stop; |
400 | 402 | i2400m->bus_tx_kick = i2400mu_bus_tx_kick; |
401 | 403 | i2400m->bus_reset = i2400mu_bus_reset; |
404 | + i2400m->bus_bm_retries = I2400M_BOOT_RETRIES; | |
402 | 405 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; |
403 | 406 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; |
404 | 407 | i2400m->bus_fw_names = i2400mu_bus_fw_names; |
include/linux/wimax/i2400m.h
... | ... | @@ -266,7 +266,7 @@ |
266 | 266 | |
267 | 267 | /* Misc constants */ |
268 | 268 | enum { |
269 | - I2400M_PL_PAD = 16, /* Payload data size alignment */ | |
269 | + I2400M_PL_ALIGN = 16, /* Payload data size alignment */ | |
270 | 270 | I2400M_PL_SIZE_MAX = 0x3EFF, |
271 | 271 | I2400M_MAX_PLS_IN_MSG = 60, |
272 | 272 | /* protocol barkers: sync sequences; for notifications they |
net/wimax/op-rfkill.c
... | ... | @@ -113,7 +113,8 @@ |
113 | 113 | else |
114 | 114 | wimax_state = WIMAX_ST_RADIO_OFF; |
115 | 115 | |
116 | - rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | |
116 | + result = rfkill_set_hw_state(wimax_dev->rfkill, | |
117 | + state == WIMAX_RF_OFF); | |
117 | 118 | |
118 | 119 | __wimax_state_change(wimax_dev, wimax_state); |
119 | 120 | } |