diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-11 20:11:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-11 20:11:33 -0400 |
commit | 3ee40c376ad3252d13946141588db7e2f435f958 (patch) | |
tree | 65bd16c024edab1ff74ad165779443edfaa26467 /drivers/net | |
parent | 670025478c2a687453cd1bac697d7d765843f59d (diff) | |
parent | 98eb0f53e2fc66482e2ea8033c58b20a079e5260 (diff) |
Merge branch 'linux-2.6.31.y' of git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wimax/i2400m/control.c | 24 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/driver.c | 40 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/fw.c | 58 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m-sdio.h | 9 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m.h | 43 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/op-rfkill.c | 4 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/rx.c | 4 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio-fw.c | 109 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio-rx.c | 47 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 50 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/tx.c | 75 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/usb.c | 5 |
12 files changed, 317 insertions, 151 deletions
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index bd193ae2178b..07308686dbcf 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c | |||
@@ -505,8 +505,15 @@ void i2400m_report_hook(struct i2400m *i2400m, | |||
505 | * it. */ | 505 | * it. */ |
506 | case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ | 506 | case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ |
507 | if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { | 507 | if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { |
508 | d_printf(1, dev, "ready for powersave, requesting\n"); | 508 | if (i2400m_power_save_disabled) |
509 | i2400m_cmd_enter_powersave(i2400m); | 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 | break; | 518 | break; |
512 | }; | 519 | }; |
@@ -688,8 +695,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, | |||
688 | d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", | 695 | d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", |
689 | i2400m, buf, buf_len); | 696 | i2400m, buf, buf_len); |
690 | 697 | ||
698 | rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ | ||
691 | if (i2400m->boot_mode) | 699 | if (i2400m->boot_mode) |
692 | return ERR_PTR(-ENODEV); | 700 | return ERR_PTR(-EL3RST); |
693 | 701 | ||
694 | msg_l3l4_hdr = buf; | 702 | msg_l3l4_hdr = buf; |
695 | /* Check msg & payload consistency */ | 703 | /* Check msg & payload consistency */ |
@@ -1389,16 +1397,16 @@ error: | |||
1389 | * | 1397 | * |
1390 | * @i2400m: device descriptor | 1398 | * @i2400m: device descriptor |
1391 | * | 1399 | * |
1392 | * Gracefully stops the device, moving it to the lowest power | 1400 | * Release resources acquired during the running of the device; in |
1393 | * consumption state possible. | 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 | void i2400m_dev_shutdown(struct i2400m *i2400m) | 1405 | void i2400m_dev_shutdown(struct i2400m *i2400m) |
1396 | { | 1406 | { |
1397 | int result = -ENODEV; | ||
1398 | struct device *dev = i2400m_dev(i2400m); | 1407 | struct device *dev = i2400m_dev(i2400m); |
1399 | 1408 | ||
1400 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 1409 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
1401 | result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 1410 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
1402 | d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); | ||
1403 | return; | 1411 | return; |
1404 | } | 1412 | } |
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index ef16c573bb22..304f0443ca4b 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -82,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); | |||
82 | MODULE_PARM_DESC(rx_reorder_disabled, | 82 | MODULE_PARM_DESC(rx_reorder_disabled, |
83 | "If true, RX reordering will be disabled."); | 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 | * i2400m_queue_work - schedule work on a i2400m's queue | 94 | * i2400m_queue_work - schedule work on a i2400m's queue |
87 | * | 95 | * |
@@ -172,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, | |||
172 | int result; | 180 | int result; |
173 | struct i2400m_work *iw; | 181 | struct i2400m_work *iw; |
174 | 182 | ||
175 | BUG_ON(i2400m->work_queue == NULL); | ||
176 | result = -ENOMEM; | 183 | result = -ENOMEM; |
177 | iw = kzalloc(sizeof(*iw), gfp_flags); | 184 | iw = kzalloc(sizeof(*iw), gfp_flags); |
178 | if (iw == NULL) | 185 | if (iw == NULL) |
@@ -377,6 +384,11 @@ error: | |||
377 | * Uploads firmware and brings up all the resources needed to be able | 384 | * Uploads firmware and brings up all the resources needed to be able |
378 | * to communicate with the device. | 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 | * TX needs to be setup before the bus-specific code (otherwise on | 392 | * TX needs to be setup before the bus-specific code (otherwise on |
381 | * shutdown, the bus-tx code could try to access it). | 393 | * shutdown, the bus-tx code could try to access it). |
382 | */ | 394 | */ |
@@ -387,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) | |||
387 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; | 399 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; |
388 | struct net_device *net_dev = wimax_dev->net_dev; | 400 | struct net_device *net_dev = wimax_dev->net_dev; |
389 | struct device *dev = i2400m_dev(i2400m); | 401 | struct device *dev = i2400m_dev(i2400m); |
390 | int times = 3; | 402 | int times = i2400m->bus_bm_retries; |
391 | 403 | ||
392 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 404 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
393 | retry: | 405 | retry: |
@@ -402,15 +414,15 @@ retry: | |||
402 | result = i2400m_rx_setup(i2400m); | 414 | result = i2400m_rx_setup(i2400m); |
403 | if (result < 0) | 415 | if (result < 0) |
404 | goto error_rx_setup; | 416 | goto error_rx_setup; |
405 | result = i2400m->bus_dev_start(i2400m); | ||
406 | if (result < 0) | ||
407 | goto error_bus_dev_start; | ||
408 | i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); | 417 | i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); |
409 | if (i2400m->work_queue == NULL) { | 418 | if (i2400m->work_queue == NULL) { |
410 | result = -ENOMEM; | 419 | result = -ENOMEM; |
411 | dev_err(dev, "cannot create workqueue\n"); | 420 | dev_err(dev, "cannot create workqueue\n"); |
412 | goto error_create_workqueue; | 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 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ | 426 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ |
415 | if (result < 0) | 427 | if (result < 0) |
416 | goto error_fw_check; | 428 | goto error_fw_check; |
@@ -432,17 +444,17 @@ retry: | |||
432 | error_dev_initialize: | 444 | error_dev_initialize: |
433 | error_check_mac_addr: | 445 | error_check_mac_addr: |
434 | error_fw_check: | 446 | error_fw_check: |
435 | destroy_workqueue(i2400m->work_queue); | ||
436 | error_create_workqueue: | ||
437 | i2400m->bus_dev_stop(i2400m); | 447 | i2400m->bus_dev_stop(i2400m); |
438 | error_bus_dev_start: | 448 | error_bus_dev_start: |
449 | destroy_workqueue(i2400m->work_queue); | ||
450 | error_create_workqueue: | ||
439 | i2400m_rx_release(i2400m); | 451 | i2400m_rx_release(i2400m); |
440 | error_rx_setup: | 452 | error_rx_setup: |
441 | i2400m_tx_release(i2400m); | 453 | i2400m_tx_release(i2400m); |
442 | error_tx_setup: | 454 | error_tx_setup: |
443 | error_bootstrap: | 455 | error_bootstrap: |
444 | if (result == -ERESTARTSYS && times-- > 0) { | 456 | if (result == -EL3RST && times-- > 0) { |
445 | flags = I2400M_BRI_SOFT; | 457 | flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; |
446 | goto retry; | 458 | goto retry; |
447 | } | 459 | } |
448 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", | 460 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", |
@@ -471,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
471 | * | 483 | * |
472 | * Returns: 0 if ok, < 0 errno code on error. | 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 | static | 490 | static |
477 | void __i2400m_dev_stop(struct i2400m *i2400m) | 491 | void __i2400m_dev_stop(struct i2400m *i2400m) |
@@ -483,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) | |||
483 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); | 497 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); |
484 | i2400m_dev_shutdown(i2400m); | 498 | i2400m_dev_shutdown(i2400m); |
485 | i2400m->ready = 0; | 499 | i2400m->ready = 0; |
486 | destroy_workqueue(i2400m->work_queue); | ||
487 | i2400m->bus_dev_stop(i2400m); | 500 | i2400m->bus_dev_stop(i2400m); |
501 | destroy_workqueue(i2400m->work_queue); | ||
488 | i2400m_rx_release(i2400m); | 502 | i2400m_rx_release(i2400m); |
489 | i2400m_tx_release(i2400m); | 503 | i2400m_tx_release(i2400m); |
490 | wimax_state_change(wimax_dev, WIMAX_ST_DOWN); | 504 | wimax_state_change(wimax_dev, WIMAX_ST_DOWN); |
@@ -546,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) | |||
546 | * i2400m_dev_stop() [we are shutting down anyway, so | 560 | * i2400m_dev_stop() [we are shutting down anyway, so |
547 | * ignore it] or we are resetting somewhere else. */ | 561 | * ignore it] or we are resetting somewhere else. */ |
548 | dev_err(dev, "device rebooted\n"); | 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 | complete(&i2400m->msg_completion); | 564 | complete(&i2400m->msg_completion); |
551 | goto out; | 565 | goto out; |
552 | } | 566 | } |
@@ -596,6 +610,8 @@ out: | |||
596 | */ | 610 | */ |
597 | int i2400m_dev_reset_handle(struct i2400m *i2400m) | 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 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, | 615 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, |
600 | GFP_ATOMIC); | 616 | GFP_ATOMIC); |
601 | } | 617 | } |
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 675c6ce810c0..e81750e54452 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c | |||
@@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, | |||
397 | unsigned int direct, unsigned int do_csum) | 397 | unsigned int direct, unsigned int do_csum) |
398 | { | 398 | { |
399 | int ret; | 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 | struct device *dev = i2400m_dev(i2400m); | 401 | struct device *dev = i2400m_dev(i2400m); |
402 | struct { | 402 | struct { |
403 | struct i2400m_bootrom_header cmd; | 403 | struct i2400m_bootrom_header cmd; |
@@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, | |||
532 | cmd = (void *) bcf + offset; | 532 | cmd = (void *) bcf + offset; |
533 | if (i2400m->sboot == 0) { | 533 | if (i2400m->sboot == 0) { |
534 | struct i2400m_bootrom_header jump_ack; | 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 | le32_to_cpu(cmd->target_addr)); | 536 | le32_to_cpu(cmd->target_addr)); |
537 | i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); | 537 | i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); |
538 | cmd->data_size = 0; | 538 | cmd->data_size = 0; |
539 | ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), | 539 | ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), |
540 | &jump_ack, sizeof(jump_ack), 0); | 540 | &jump_ack, sizeof(jump_ack), 0); |
541 | } else { | 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 | le32_to_cpu(cmd->target_addr)); | 543 | le32_to_cpu(cmd->target_addr)); |
544 | cmd_buf = i2400m->bm_cmd_buf; | 544 | cmd_buf = i2400m->bm_cmd_buf; |
545 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); | 545 | memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); |
@@ -696,8 +696,7 @@ error_dev_gone: | |||
696 | return result; | 696 | return result; |
697 | 697 | ||
698 | error_timeout: | 698 | error_timeout: |
699 | dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); | 699 | dev_err(dev, "Timed out waiting for reboot ack\n"); |
700 | i2400m->bus_reset(i2400m, I2400M_RT_BUS); | ||
701 | result = -ETIMEDOUT; | 700 | result = -ETIMEDOUT; |
702 | goto exit_timeout; | 701 | goto exit_timeout; |
703 | } | 702 | } |
@@ -770,40 +769,21 @@ error_read_mac: | |||
770 | static | 769 | static |
771 | int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) | 770 | int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) |
772 | { | 771 | { |
773 | #define POKE(a, d) { \ | 772 | unsigned i = 0; |
774 | .address = cpu_to_le32(a), \ | 773 | int ret = 0; |
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; | ||
796 | struct device *dev = i2400m_dev(i2400m); | 774 | struct device *dev = i2400m_dev(i2400m); |
797 | |||
798 | dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); | ||
799 | |||
800 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); | 775 | d_fnstart(5, dev, "(i2400m %p)\n", i2400m); |
801 | for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { | 776 | if (i2400m->bus_bm_pokes_table) { |
802 | ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, | 777 | while (i2400m->bus_bm_pokes_table[i].address) { |
803 | sizeof(i2400m_pokes[i].data), | 778 | ret = i2400m_download_chunk( |
804 | i2400m_pokes[i].address, 1, 1); | 779 | i2400m, |
805 | if (ret < 0) | 780 | &i2400m->bus_bm_pokes_table[i].data, |
806 | break; | 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 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); | 788 | d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); |
809 | return ret; | 789 | return ret; |
@@ -980,11 +960,12 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, | |||
980 | { | 960 | { |
981 | int ret = 0; | 961 | int ret = 0; |
982 | struct device *dev = i2400m_dev(i2400m); | 962 | struct device *dev = i2400m_dev(i2400m); |
983 | int count = I2400M_BOOT_RETRIES; | 963 | int count = i2400m->bus_bm_retries; |
984 | 964 | ||
985 | d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", | 965 | d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", |
986 | i2400m, bcf, bcf_size); | 966 | i2400m, bcf, bcf_size); |
987 | i2400m->boot_mode = 1; | 967 | i2400m->boot_mode = 1; |
968 | wmb(); /* Make sure other readers see it */ | ||
988 | hw_reboot: | 969 | hw_reboot: |
989 | if (count-- == 0) { | 970 | if (count-- == 0) { |
990 | ret = -ERESTARTSYS; | 971 | ret = -ERESTARTSYS; |
@@ -1033,6 +1014,7 @@ hw_reboot: | |||
1033 | d_printf(2, dev, "fw %s successfully uploaded\n", | 1014 | d_printf(2, dev, "fw %s successfully uploaded\n", |
1034 | i2400m->fw_name); | 1015 | i2400m->fw_name); |
1035 | i2400m->boot_mode = 0; | 1016 | i2400m->boot_mode = 0; |
1017 | wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ | ||
1036 | error_dnload_finalize: | 1018 | error_dnload_finalize: |
1037 | error_dnload_bcf: | 1019 | error_dnload_bcf: |
1038 | error_dnload_init: | 1020 | error_dnload_init: |
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 08c2fb739234..9c4e3189f7b5 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h | |||
@@ -78,6 +78,8 @@ enum { | |||
78 | /* The number of ticks to wait for the device to signal that | 78 | /* The number of ticks to wait for the device to signal that |
79 | * it is ready */ | 79 | * it is ready */ |
80 | I2400MS_INIT_SLEEP_INTERVAL = 10, | 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 @@ struct i2400ms { | |||
105 | char tx_wq_name[32]; | 107 | char tx_wq_name[32]; |
106 | 108 | ||
107 | struct dentry *debugfs_dentry; | 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,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, | |||
129 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, | 135 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, |
130 | struct i2400m_bootrom_header *, | 136 | struct i2400m_bootrom_header *, |
131 | size_t); | 137 | size_t); |
138 | extern void i2400ms_bus_bm_release(struct i2400m *); | ||
139 | extern int i2400ms_bus_bm_setup(struct i2400m *); | ||
140 | |||
132 | #endif /* #ifndef __I2400M_SDIO_H__ */ | 141 | #endif /* #ifndef __I2400M_SDIO_H__ */ |
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 434ba310c2fe..1fe5da4cf0a0 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -150,11 +150,33 @@ | |||
150 | enum { | 150 | enum { |
151 | /* Firmware uploading */ | 151 | /* Firmware uploading */ |
152 | I2400M_BOOT_RETRIES = 3, | 152 | I2400M_BOOT_RETRIES = 3, |
153 | I3200_BOOT_RETRIES = 3, | ||
153 | /* Size of the Boot Mode Command buffer */ | 154 | /* Size of the Boot Mode Command buffer */ |
154 | I2400M_BM_CMD_BUF_SIZE = 16 * 1024, | 155 | I2400M_BM_CMD_BUF_SIZE = 16 * 1024, |
155 | I2400M_BM_ACK_BUF_SIZE = 256, | 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 | }; | ||
174 | |||
175 | #define I2400M_FW_POKE(a, d) { \ | ||
176 | .address = cpu_to_le32(a), \ | ||
177 | .data = cpu_to_le32(d) \ | ||
178 | } | ||
179 | |||
158 | 180 | ||
159 | /** | 181 | /** |
160 | * i2400m_reset_type - methods to reset a device | 182 | * i2400m_reset_type - methods to reset a device |
@@ -224,6 +246,17 @@ struct i2400m_roq; | |||
224 | * process, so it cannot rely on common infrastructure being laid | 246 | * process, so it cannot rely on common infrastructure being laid |
225 | * out. | 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 | * @bus_bm_cmd_send: [fill] Function called to send a boot-mode | 260 | * @bus_bm_cmd_send: [fill] Function called to send a boot-mode |
228 | * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This | 261 | * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This |
229 | * is synchronous and has to return 0 if ok or < 0 errno code in | 262 | * is synchronous and has to return 0 if ok or < 0 errno code in |
@@ -252,6 +285,12 @@ struct i2400m_roq; | |||
252 | * address provided in boot mode is kind of broken and needs to | 285 | * address provided in boot mode is kind of broken and needs to |
253 | * be re-read later on. | 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. | ||
293 | * | ||
255 | * | 294 | * |
256 | * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX | 295 | * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX |
257 | * stack. Due to the way a net_device is allocated, we need to | 296 | * stack. Due to the way a net_device is allocated, we need to |
@@ -399,6 +438,8 @@ struct i2400m { | |||
399 | 438 | ||
400 | size_t bus_tx_block_size; | 439 | size_t bus_tx_block_size; |
401 | size_t bus_pl_size_max; | 440 | size_t bus_pl_size_max; |
441 | unsigned bus_bm_retries; | ||
442 | |||
402 | int (*bus_dev_start)(struct i2400m *); | 443 | int (*bus_dev_start)(struct i2400m *); |
403 | void (*bus_dev_stop)(struct i2400m *); | 444 | void (*bus_dev_stop)(struct i2400m *); |
404 | void (*bus_tx_kick)(struct i2400m *); | 445 | void (*bus_tx_kick)(struct i2400m *); |
@@ -410,6 +451,7 @@ struct i2400m { | |||
410 | struct i2400m_bootrom_header *, size_t); | 451 | struct i2400m_bootrom_header *, size_t); |
411 | const char **bus_fw_names; | 452 | const char **bus_fw_names; |
412 | unsigned bus_bm_mac_addr_impaired:1; | 453 | unsigned bus_bm_mac_addr_impaired:1; |
454 | const struct i2400m_poke_table *bus_bm_pokes_table; | ||
413 | 455 | ||
414 | spinlock_t tx_lock; /* protect TX state */ | 456 | spinlock_t tx_lock; /* protect TX state */ |
415 | void *tx_buf; | 457 | void *tx_buf; |
@@ -709,6 +751,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = { | |||
709 | cpu_to_le32(I2400M_SBOOT_BARKER) | 751 | cpu_to_le32(I2400M_SBOOT_BARKER) |
710 | }; | 752 | }; |
711 | 753 | ||
754 | extern int i2400m_power_save_disabled; | ||
712 | 755 | ||
713 | /* | 756 | /* |
714 | * Utility functions | 757 | * Utility functions |
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 487ec58cea46..43927b5d7ad6 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c | |||
@@ -54,8 +54,10 @@ int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state) | |||
54 | /* state == WIMAX_RF_ON */ | 54 | /* state == WIMAX_RF_ON */ |
55 | return i2400m->state != I2400M_SS_RF_OFF | 55 | return i2400m->state != I2400M_SS_RF_OFF |
56 | && i2400m->state != I2400M_SS_RF_SHUTDOWN; | 56 | && i2400m->state != I2400M_SS_RF_SHUTDOWN; |
57 | else | 57 | else { |
58 | BUG(); | 58 | BUG(); |
59 | return -EINVAL; /* shut gcc warnings on certain arches */ | ||
60 | } | ||
59 | } | 61 | } |
60 | 62 | ||
61 | 63 | ||
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 7643850a6fb8..07c32e68909f 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c | |||
@@ -1148,7 +1148,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) | |||
1148 | num_pls = le16_to_cpu(msg_hdr->num_pls); | 1148 | num_pls = le16_to_cpu(msg_hdr->num_pls); |
1149 | pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ | 1149 | pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ |
1150 | num_pls * sizeof(msg_hdr->pld[0]); | 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 | if (pl_itr > skb->len) { /* got all the payload descriptors? */ | 1152 | if (pl_itr > skb->len) { /* got all the payload descriptors? */ |
1153 | dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " | 1153 | dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " |
1154 | "%u payload descriptors (%zu each, total %zu)\n", | 1154 | "%u payload descriptors (%zu each, total %zu)\n", |
@@ -1166,7 +1166,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) | |||
1166 | single_last = num_pls == 1 || i == num_pls - 1; | 1166 | single_last = num_pls == 1 || i == num_pls - 1; |
1167 | i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], | 1167 | i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], |
1168 | skb->data + pl_itr); | 1168 | skb->data + pl_itr); |
1169 | pl_itr += ALIGN(pl_size, I2400M_PL_PAD); | 1169 | pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN); |
1170 | cond_resched(); /* Don't monopolize */ | 1170 | cond_resched(); /* Don't monopolize */ |
1171 | } | 1171 | } |
1172 | kfree_skb(skb); | 1172 | kfree_skb(skb); |
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c index 3487205d8f50..7d6ec0f475f8 100644 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ b/drivers/net/wimax/i2400m/sdio-fw.c | |||
@@ -46,17 +46,24 @@ | |||
46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
47 | * - SDIO rehash for changes in the bus-driver model | 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 | * THE PROCEDURE | 52 | * THE PROCEDURE |
50 | * | 53 | * |
51 | * See fw.c for the generic description of this procedure. | 54 | * See fw.c for the generic description of this procedure. |
52 | * | 55 | * |
53 | * This file implements only the SDIO specifics. It boils down to how | 56 | * This file implements only the SDIO specifics. It boils down to how |
54 | * to send a command and waiting for an acknowledgement from the | 57 | * to send a command and waiting for an acknowledgement from the |
55 | * device. We do polled reads. | 58 | * device. |
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. | ||
56 | * | 63 | * |
57 | * COMMAND EXECUTION | 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 | * to send commands. | 67 | * to send commands. |
61 | * | 68 | * |
62 | * The SDIO devices expects things in 256 byte blocks, so it will pad | 69 | * The SDIO devices expects things in 256 byte blocks, so it will pad |
@@ -64,12 +71,15 @@ | |||
64 | * | 71 | * |
65 | * ACK RECEPTION | 72 | * ACK RECEPTION |
66 | * | 73 | * |
67 | * This works in polling mode -- the fw loader says when to wait for | 74 | * This works in IRQ mode -- the fw loader says when to wait for data |
68 | * data and for that it calls i2400ms_bus_bm_wait_for_ack(). | 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 | 77 | * This checks if there is any data available (RX size > 0); if not, |
71 | * receive at least as much bytes as where asked for (although it'll | 78 | * waits for the IRQ handler to notify about it. Once there is data, |
72 | * always be a multiple of 256 bytes). | 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 | #include <linux/mmc/sdio_func.h> | 84 | #include <linux/mmc/sdio_func.h> |
75 | #include "i2400m-sdio.h" | 85 | #include "i2400m-sdio.h" |
@@ -78,6 +88,7 @@ | |||
78 | #define D_SUBMODULE fw | 88 | #define D_SUBMODULE fw |
79 | #include "sdio-debug-levels.h" | 89 | #include "sdio-debug-levels.h" |
80 | 90 | ||
91 | |||
81 | /* | 92 | /* |
82 | * Send a boot-mode command to the SDIO function | 93 | * Send a boot-mode command to the SDIO function |
83 | * | 94 | * |
@@ -139,7 +150,7 @@ error_too_big: | |||
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 | * @i2400m: | 155 | * @i2400m: |
145 | * @_ack: pointer to where to store the read data | 156 | * @_ack: pointer to where to store the read data |
@@ -150,75 +161,49 @@ error_too_big: | |||
150 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so | 161 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so |
151 | * check for that. We don't need to check for device reboots | 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 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, | 165 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, |
158 | struct i2400m_bootrom_header *ack, | 166 | struct i2400m_bootrom_header *ack, |
159 | size_t ack_size) | 167 | size_t ack_size) |
160 | { | 168 | { |
161 | int result; | 169 | ssize_t result; |
162 | ssize_t rx_size; | ||
163 | u64 timeout; | ||
164 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | 170 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); |
165 | struct sdio_func *func = i2400ms->func; | 171 | struct sdio_func *func = i2400ms->func; |
166 | struct device *dev = &func->dev; | 172 | struct device *dev = &func->dev; |
173 | int size; | ||
167 | 174 | ||
168 | BUG_ON(sizeof(*ack) > ack_size); | 175 | BUG_ON(sizeof(*ack) > ack_size); |
169 | 176 | ||
170 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", | 177 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", |
171 | i2400m, ack, ack_size); | 178 | i2400m, ack, ack_size); |
172 | 179 | ||
173 | timeout = get_jiffies_64() + 2 * HZ; | 180 | spin_lock(&i2400m->rx_lock); |
174 | sdio_claim_host(func); | 181 | i2400ms->bm_ack_size = -EINPROGRESS; |
175 | while (1) { | 182 | spin_unlock(&i2400m->rx_lock); |
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 | } | ||
181 | 183 | ||
182 | /* Find the RX size, check if it fits or not -- it if | 184 | result = wait_event_timeout(i2400ms->bm_wfa_wq, |
183 | * doesn't fit, fail, as we have no way to dispose of | 185 | i2400ms->bm_ack_size != -EINPROGRESS, |
184 | * the extra data. */ | 186 | 2 * HZ); |
185 | rx_size = __i2400ms_rx_get_size(i2400ms); | 187 | if (result == 0) { |
186 | if (rx_size < 0) | 188 | result = -ETIMEDOUT; |
187 | goto error_rx_get_size; | 189 | dev_err(dev, "BM: error waiting for an ack\n"); |
188 | result = -ENOSPC; /* Check it fits */ | 190 | goto error_timeout; |
189 | if (rx_size < sizeof(*ack)) { | 191 | } |
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 | } | ||
201 | 192 | ||
202 | /* Read it */ | 193 | spin_lock(&i2400m->rx_lock); |
203 | result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, | 194 | result = i2400ms->bm_ack_size; |
204 | I2400MS_DATA_ADDR, rx_size); | 195 | BUG_ON(result == -EINPROGRESS); |
205 | if (result == -ETIMEDOUT || result == -ETIME) | 196 | if (result < 0) /* so we exit when rx_release() is called */ |
206 | continue; | 197 | dev_err(dev, "BM: %s failed: %zd\n", __func__, result); |
207 | if (result < 0) { | 198 | else { |
208 | dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", | 199 | size = min(ack_size, i2400ms->bm_ack_size); |
209 | rx_size, result); | 200 | memcpy(ack, i2400m->bm_ack_buf, size); |
210 | goto error_read; | ||
211 | } else | ||
212 | break; | ||
213 | } | 201 | } |
214 | rx_size = min((ssize_t)ack_size, rx_size); | 202 | i2400ms->bm_ack_size = -EINPROGRESS; |
215 | memcpy(ack, i2400m->bm_ack_buf, rx_size); | 203 | spin_unlock(&i2400m->rx_lock); |
216 | error_read: | 204 | |
217 | error_too_small: | 205 | error_timeout: |
218 | error_rx_get_size: | 206 | d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", |
219 | error_timedout: | 207 | i2400m, ack, ack_size, result); |
220 | sdio_release_host(func); | 208 | return result; |
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; | ||
224 | } | 209 | } |
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index a3008b904f7d..321beadf6e47 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c | |||
@@ -69,6 +69,13 @@ | |||
69 | #define D_SUBMODULE rx | 69 | #define D_SUBMODULE rx |
70 | #include "sdio-debug-levels.h" | 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 | }; | ||
78 | |||
72 | 79 | ||
73 | /* | 80 | /* |
74 | * Read and return the amount of bytes available for RX | 81 | * Read and return the amount of bytes available for RX |
@@ -131,25 +138,35 @@ void i2400ms_rx(struct i2400ms *i2400ms) | |||
131 | ret = rx_size; | 138 | ret = rx_size; |
132 | goto error_get_size; | 139 | goto error_get_size; |
133 | } | 140 | } |
141 | |||
134 | ret = -ENOMEM; | 142 | ret = -ENOMEM; |
135 | skb = alloc_skb(rx_size, GFP_ATOMIC); | 143 | skb = alloc_skb(rx_size, GFP_ATOMIC); |
136 | if (NULL == skb) { | 144 | if (NULL == skb) { |
137 | dev_err(dev, "RX: unable to alloc skb\n"); | 145 | dev_err(dev, "RX: unable to alloc skb\n"); |
138 | goto error_alloc_skb; | 146 | goto error_alloc_skb; |
139 | } | 147 | } |
140 | |||
141 | ret = sdio_memcpy_fromio(func, skb->data, | 148 | ret = sdio_memcpy_fromio(func, skb->data, |
142 | I2400MS_DATA_ADDR, rx_size); | 149 | I2400MS_DATA_ADDR, rx_size); |
143 | if (ret < 0) { | 150 | if (ret < 0) { |
144 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); | 151 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); |
145 | goto error_memcpy_fromio; | 152 | goto error_memcpy_fromio; |
146 | } | 153 | } |
147 | /* Check if device has reset */ | 154 | |
148 | if (!memcmp(skb->data, i2400m_NBOOT_BARKER, | 155 | rmb(); /* make sure we get boot_mode from dev_reset_handle */ |
149 | sizeof(i2400m_NBOOT_BARKER)) | 156 | if (i2400m->boot_mode == 1) { |
150 | || !memcmp(skb->data, i2400m_SBOOT_BARKER, | 157 | spin_lock(&i2400m->rx_lock); |
151 | sizeof(i2400m_SBOOT_BARKER))) { | 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 | ret = i2400m_dev_reset_handle(i2400m); | 168 | ret = i2400m_dev_reset_handle(i2400m); |
169 | dev_err(dev, "RX: SDIO reboot barker\n"); | ||
153 | kfree_skb(skb); | 170 | kfree_skb(skb); |
154 | } else { | 171 | } else { |
155 | skb_put(skb, rx_size); | 172 | skb_put(skb, rx_size); |
@@ -179,7 +196,6 @@ void i2400ms_irq(struct sdio_func *func) | |||
179 | { | 196 | { |
180 | int ret; | 197 | int ret; |
181 | struct i2400ms *i2400ms = sdio_get_drvdata(func); | 198 | struct i2400ms *i2400ms = sdio_get_drvdata(func); |
182 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
183 | struct device *dev = &func->dev; | 199 | struct device *dev = &func->dev; |
184 | int val; | 200 | int val; |
185 | 201 | ||
@@ -194,10 +210,7 @@ void i2400ms_irq(struct sdio_func *func) | |||
194 | goto error_no_irq; | 210 | goto error_no_irq; |
195 | } | 211 | } |
196 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); | 212 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); |
197 | if (WARN_ON(i2400m->boot_mode != 0)) | 213 | i2400ms_rx(i2400ms); |
198 | dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n"); | ||
199 | else | ||
200 | i2400ms_rx(i2400ms); | ||
201 | error_no_irq: | 214 | error_no_irq: |
202 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); | 215 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); |
203 | return; | 216 | return; |
@@ -214,8 +227,15 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms) | |||
214 | int result; | 227 | int result; |
215 | struct sdio_func *func = i2400ms->func; | 228 | struct sdio_func *func = i2400ms->func; |
216 | struct device *dev = &func->dev; | 229 | struct device *dev = &func->dev; |
230 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
217 | 231 | ||
218 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | 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 | sdio_claim_host(func); | 239 | sdio_claim_host(func); |
220 | result = sdio_claim_irq(func, i2400ms_irq); | 240 | result = sdio_claim_irq(func, i2400ms_irq); |
221 | if (result < 0) { | 241 | if (result < 0) { |
@@ -245,8 +265,13 @@ void i2400ms_rx_release(struct i2400ms *i2400ms) | |||
245 | int result; | 265 | int result; |
246 | struct sdio_func *func = i2400ms->func; | 266 | struct sdio_func *func = i2400ms->func; |
247 | struct device *dev = &func->dev; | 267 | struct device *dev = &func->dev; |
268 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
248 | 269 | ||
249 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | 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 | sdio_claim_host(func); | 275 | sdio_claim_host(func); |
251 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); | 276 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); |
252 | sdio_release_irq(func); | 277 | sdio_release_irq(func); |
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 777c981676fc..2538825d1c66 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -78,6 +78,14 @@ static const char *i2400ms_bus_fw_names[] = { | |||
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 | * Enable the SDIO function | 90 | * Enable the SDIO function |
83 | * | 91 | * |
@@ -148,19 +156,14 @@ int i2400ms_bus_dev_start(struct i2400m *i2400m) | |||
148 | 156 | ||
149 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 157 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
150 | msleep(200); | 158 | msleep(200); |
151 | result = i2400ms_rx_setup(i2400ms); | ||
152 | if (result < 0) | ||
153 | goto error_rx_setup; | ||
154 | result = i2400ms_tx_setup(i2400ms); | 159 | result = i2400ms_tx_setup(i2400ms); |
155 | if (result < 0) | 160 | if (result < 0) |
156 | goto error_tx_setup; | 161 | goto error_tx_setup; |
157 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); | 162 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); |
158 | return result; | 163 | return result; |
159 | 164 | ||
160 | i2400ms_tx_release(i2400ms); | ||
161 | error_tx_setup: | 165 | error_tx_setup: |
162 | i2400ms_rx_release(i2400ms); | 166 | i2400ms_tx_release(i2400ms); |
163 | error_rx_setup: | ||
164 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 167 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
165 | return result; | 168 | return result; |
166 | } | 169 | } |
@@ -174,7 +177,6 @@ void i2400ms_bus_dev_stop(struct i2400m *i2400m) | |||
174 | struct device *dev = &func->dev; | 177 | struct device *dev = &func->dev; |
175 | 178 | ||
176 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 179 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
177 | i2400ms_rx_release(i2400ms); | ||
178 | i2400ms_tx_release(i2400ms); | 180 | i2400ms_tx_release(i2400ms); |
179 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 181 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
180 | } | 182 | } |
@@ -255,7 +257,7 @@ error_kzalloc: | |||
255 | static | 257 | static |
256 | int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | 258 | int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) |
257 | { | 259 | { |
258 | int result; | 260 | int result = 0; |
259 | struct i2400ms *i2400ms = | 261 | struct i2400ms *i2400ms = |
260 | container_of(i2400m, struct i2400ms, i2400m); | 262 | container_of(i2400m, struct i2400ms, i2400m); |
261 | struct device *dev = i2400m_dev(i2400m); | 263 | struct device *dev = i2400m_dev(i2400m); |
@@ -280,8 +282,25 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | |||
280 | sizeof(i2400m_COLD_BOOT_BARKER)); | 282 | sizeof(i2400m_COLD_BOOT_BARKER)); |
281 | else if (rt == I2400M_RT_BUS) { | 283 | else if (rt == I2400M_RT_BUS) { |
282 | do_bus_reset: | 284 | do_bus_reset: |
283 | dev_err(dev, "FIXME: SDIO bus reset not implemented\n"); | 285 | /* call netif_tx_disable() before sending IOE disable, |
284 | result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS; | 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 | } else | 304 | } else |
286 | BUG(); | 305 | BUG(); |
287 | if (result < 0 && rt != I2400M_RT_BUS) { | 306 | if (result < 0 && rt != I2400M_RT_BUS) { |
@@ -404,10 +423,14 @@ int i2400ms_probe(struct sdio_func *func, | |||
404 | i2400m->bus_dev_stop = i2400ms_bus_dev_stop; | 423 | i2400m->bus_dev_stop = i2400ms_bus_dev_stop; |
405 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; | 424 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; |
406 | i2400m->bus_reset = i2400ms_bus_reset; | 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 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; | 429 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; |
408 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; | 430 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; |
409 | i2400m->bus_fw_names = i2400ms_bus_fw_names; | 431 | i2400m->bus_fw_names = i2400ms_bus_fw_names; |
410 | i2400m->bus_bm_mac_addr_impaired = 1; | 432 | i2400m->bus_bm_mac_addr_impaired = 1; |
433 | i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; | ||
411 | 434 | ||
412 | sdio_claim_host(func); | 435 | sdio_claim_host(func); |
413 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | 436 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); |
@@ -423,6 +446,10 @@ int i2400ms_probe(struct sdio_func *func, | |||
423 | goto error_func_enable; | 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 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); | 453 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); |
427 | if (result < 0) { | 454 | if (result < 0) { |
428 | dev_err(dev, "cannot setup device: %d\n", result); | 455 | dev_err(dev, "cannot setup device: %d\n", result); |
@@ -440,6 +467,8 @@ int i2400ms_probe(struct sdio_func *func, | |||
440 | error_debugfs_add: | 467 | error_debugfs_add: |
441 | i2400m_release(i2400m); | 468 | i2400m_release(i2400m); |
442 | error_setup: | 469 | error_setup: |
470 | i2400ms_rx_release(i2400ms); | ||
471 | error_rx_setup: | ||
443 | sdio_claim_host(func); | 472 | sdio_claim_host(func); |
444 | sdio_disable_func(func); | 473 | sdio_disable_func(func); |
445 | sdio_release_host(func); | 474 | sdio_release_host(func); |
@@ -462,6 +491,7 @@ void i2400ms_remove(struct sdio_func *func) | |||
462 | 491 | ||
463 | d_fnstart(3, dev, "SDIO func %p\n", func); | 492 | d_fnstart(3, dev, "SDIO func %p\n", func); |
464 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | 493 | debugfs_remove_recursive(i2400ms->debugfs_dentry); |
494 | i2400ms_rx_release(i2400ms); | ||
465 | i2400m_release(i2400m); | 495 | i2400m_release(i2400m); |
466 | sdio_set_drvdata(func, NULL); | 496 | sdio_set_drvdata(func, NULL); |
467 | sdio_claim_host(func); | 497 | sdio_claim_host(func); |
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 613a88ffd651..fa16ccf8e26a 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c | |||
@@ -278,6 +278,48 @@ enum { | |||
278 | #define TAIL_FULL ((void *)~(unsigned long)NULL) | 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 | * Allocate @size bytes in the TX fifo, return a pointer to it | 323 | * Allocate @size bytes in the TX fifo, return a pointer to it |
282 | * | 324 | * |
283 | * @i2400m: device descriptor | 325 | * @i2400m: device descriptor |
@@ -338,7 +380,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) | |||
338 | return NULL; | 380 | return NULL; |
339 | } | 381 | } |
340 | /* Is there space at the tail? */ | 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 | if (tail_room < needed_size) { | 384 | if (tail_room < needed_size) { |
343 | if (i2400m->tx_out % I2400M_TX_BUF_SIZE | 385 | if (i2400m->tx_out % I2400M_TX_BUF_SIZE |
344 | < i2400m->tx_in % I2400M_TX_BUF_SIZE) { | 386 | < i2400m->tx_in % I2400M_TX_BUF_SIZE) { |
@@ -367,17 +409,29 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) | |||
367 | * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the | 409 | * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the |
368 | * header). | 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 | * Note: | 419 | * Note: |
371 | * | 420 | * |
372 | * Assumes i2400m->tx_lock is taken, and we use that as a barrier | 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 | static | 426 | static |
375 | void i2400m_tx_skip_tail(struct i2400m *i2400m) | 427 | void i2400m_tx_skip_tail(struct i2400m *i2400m) |
376 | { | 428 | { |
377 | struct device *dev = i2400m_dev(i2400m); | 429 | struct device *dev = i2400m_dev(i2400m); |
378 | size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; | 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 | struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; | 432 | struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; |
433 | if (unlikely(tail_room == 0)) | ||
434 | return; | ||
381 | BUG_ON(tail_room < sizeof(*msg)); | 435 | BUG_ON(tail_room < sizeof(*msg)); |
382 | msg->size = tail_room | I2400M_TX_SKIP; | 436 | msg->size = tail_room | I2400M_TX_SKIP; |
383 | d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", | 437 | d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", |
@@ -474,10 +528,18 @@ void i2400m_tx_close(struct i2400m *i2400m) | |||
474 | struct i2400m_msg_hdr *tx_msg_moved; | 528 | struct i2400m_msg_hdr *tx_msg_moved; |
475 | size_t aligned_size, padding, hdr_size; | 529 | size_t aligned_size, padding, hdr_size; |
476 | void *pad_buf; | 530 | void *pad_buf; |
531 | unsigned num_pls; | ||
477 | 532 | ||
478 | if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ | 533 | if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ |
479 | goto out; | 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 | /* Relocate the message header | 543 | /* Relocate the message header |
482 | * | 544 | * |
483 | * Find the current header size, align it to 16 and if we need | 545 | * Find the current header size, align it to 16 and if we need |
@@ -491,7 +553,7 @@ void i2400m_tx_close(struct i2400m *i2400m) | |||
491 | */ | 553 | */ |
492 | hdr_size = sizeof(*tx_msg) | 554 | hdr_size = sizeof(*tx_msg) |
493 | + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); | 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 | tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; | 557 | tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; |
496 | tx_msg_moved = (void *) tx_msg + tx_msg->offset; | 558 | tx_msg_moved = (void *) tx_msg + tx_msg->offset; |
497 | memmove(tx_msg_moved, tx_msg, hdr_size); | 559 | memmove(tx_msg_moved, tx_msg, hdr_size); |
@@ -574,7 +636,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, | |||
574 | 636 | ||
575 | d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", | 637 | d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", |
576 | i2400m, buf, buf_len, pl_type); | 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 | d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); | 640 | d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); |
579 | /* If there is no current TX message, create one; if the | 641 | /* If there is no current TX message, create one; if the |
580 | * current one is out of payload slots or we have a singleton, | 642 | * current one is out of payload slots or we have a singleton, |
@@ -591,6 +653,8 @@ try_new: | |||
591 | i2400m_tx_close(i2400m); | 653 | i2400m_tx_close(i2400m); |
592 | i2400m_tx_new(i2400m); | 654 | i2400m_tx_new(i2400m); |
593 | } | 655 | } |
656 | if (i2400m->tx_msg == NULL) | ||
657 | goto error_tx_new; | ||
594 | if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { | 658 | if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { |
595 | d_printf(2, dev, "TX: message too big, going new\n"); | 659 | d_printf(2, dev, "TX: message too big, going new\n"); |
596 | i2400m_tx_close(i2400m); | 660 | i2400m_tx_close(i2400m); |
@@ -773,7 +837,6 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m) | |||
773 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; | 837 | n = i2400m->tx_out / I2400M_TX_BUF_SIZE; |
774 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; | 838 | i2400m->tx_out %= I2400M_TX_BUF_SIZE; |
775 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; | 839 | i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; |
776 | netif_start_queue(i2400m->wimax_dev.net_dev); | ||
777 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | 840 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); |
778 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | 841 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); |
779 | } | 842 | } |
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 17851321b7fd..cfdaf69da9d1 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c | |||
@@ -254,8 +254,10 @@ do_bus_reset: | |||
254 | dev_err(dev, "USB reset failed (%d), giving up!\n", | 254 | dev_err(dev, "USB reset failed (%d), giving up!\n", |
255 | result); | 255 | result); |
256 | } | 256 | } |
257 | } else | 257 | } else { |
258 | result = -EINVAL; /* shut gcc up in certain arches */ | ||
258 | BUG(); | 259 | BUG(); |
260 | } | ||
259 | if (result < 0 | 261 | if (result < 0 |
260 | && result != -EINVAL /* device is gone */ | 262 | && result != -EINVAL /* device is gone */ |
261 | && rt != I2400M_RT_BUS) { | 263 | && rt != I2400M_RT_BUS) { |
@@ -399,6 +401,7 @@ int i2400mu_probe(struct usb_interface *iface, | |||
399 | i2400m->bus_dev_stop = i2400mu_bus_dev_stop; | 401 | i2400m->bus_dev_stop = i2400mu_bus_dev_stop; |
400 | i2400m->bus_tx_kick = i2400mu_bus_tx_kick; | 402 | i2400m->bus_tx_kick = i2400mu_bus_tx_kick; |
401 | i2400m->bus_reset = i2400mu_bus_reset; | 403 | i2400m->bus_reset = i2400mu_bus_reset; |
404 | i2400m->bus_bm_retries = I2400M_BOOT_RETRIES; | ||
402 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; | 405 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; |
403 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; | 406 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; |
404 | i2400m->bus_fw_names = i2400mu_bus_fw_names; | 407 | i2400m->bus_fw_names = i2400mu_bus_fw_names; |