diff options
Diffstat (limited to 'drivers/net/wimax/i2400m/driver.c')
-rw-r--r-- | drivers/net/wimax/i2400m/driver.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 07a54bad237b..304f0443ca4b 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -62,6 +62,7 @@ | |||
62 | * unregister_netdev() | 62 | * unregister_netdev() |
63 | */ | 63 | */ |
64 | #include "i2400m.h" | 64 | #include "i2400m.h" |
65 | #include <linux/etherdevice.h> | ||
65 | #include <linux/wimax/i2400m.h> | 66 | #include <linux/wimax/i2400m.h> |
66 | #include <linux/module.h> | 67 | #include <linux/module.h> |
67 | #include <linux/moduleparam.h> | 68 | #include <linux/moduleparam.h> |
@@ -81,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); | |||
81 | MODULE_PARM_DESC(rx_reorder_disabled, | 82 | MODULE_PARM_DESC(rx_reorder_disabled, |
82 | "If true, RX reordering will be disabled."); | 83 | "If true, RX reordering will be disabled."); |
83 | 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 | |||
84 | /** | 93 | /** |
85 | * i2400m_queue_work - schedule work on a i2400m's queue | 94 | * i2400m_queue_work - schedule work on a i2400m's queue |
86 | * | 95 | * |
@@ -171,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, | |||
171 | int result; | 180 | int result; |
172 | struct i2400m_work *iw; | 181 | struct i2400m_work *iw; |
173 | 182 | ||
174 | BUG_ON(i2400m->work_queue == NULL); | ||
175 | result = -ENOMEM; | 183 | result = -ENOMEM; |
176 | iw = kzalloc(sizeof(*iw), gfp_flags); | 184 | iw = kzalloc(sizeof(*iw), gfp_flags); |
177 | if (iw == NULL) | 185 | if (iw == NULL) |
@@ -234,9 +242,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, | |||
234 | result = PTR_ERR(ack_skb); | 242 | result = PTR_ERR(ack_skb); |
235 | if (IS_ERR(ack_skb)) | 243 | if (IS_ERR(ack_skb)) |
236 | goto error_msg_to_dev; | 244 | goto error_msg_to_dev; |
237 | if (unlikely(i2400m->trace_msg_from_user)) | ||
238 | wimax_msg(&i2400m->wimax_dev, "trace", | ||
239 | msg_buf, msg_len, GFP_KERNEL); | ||
240 | result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); | 245 | result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); |
241 | error_msg_to_dev: | 246 | error_msg_to_dev: |
242 | d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " | 247 | d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " |
@@ -379,6 +384,11 @@ error: | |||
379 | * 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 |
380 | * to communicate with the device. | 385 | * to communicate with the device. |
381 | * | 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 | * | ||
382 | * 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 |
383 | * shutdown, the bus-tx code could try to access it). | 393 | * shutdown, the bus-tx code could try to access it). |
384 | */ | 394 | */ |
@@ -389,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) | |||
389 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; | 399 | struct wimax_dev *wimax_dev = &i2400m->wimax_dev; |
390 | struct net_device *net_dev = wimax_dev->net_dev; | 400 | struct net_device *net_dev = wimax_dev->net_dev; |
391 | struct device *dev = i2400m_dev(i2400m); | 401 | struct device *dev = i2400m_dev(i2400m); |
392 | int times = 3; | 402 | int times = i2400m->bus_bm_retries; |
393 | 403 | ||
394 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | 404 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); |
395 | retry: | 405 | retry: |
@@ -404,15 +414,15 @@ retry: | |||
404 | result = i2400m_rx_setup(i2400m); | 414 | result = i2400m_rx_setup(i2400m); |
405 | if (result < 0) | 415 | if (result < 0) |
406 | goto error_rx_setup; | 416 | goto error_rx_setup; |
407 | result = i2400m->bus_dev_start(i2400m); | ||
408 | if (result < 0) | ||
409 | goto error_bus_dev_start; | ||
410 | i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); | 417 | i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); |
411 | if (i2400m->work_queue == NULL) { | 418 | if (i2400m->work_queue == NULL) { |
412 | result = -ENOMEM; | 419 | result = -ENOMEM; |
413 | dev_err(dev, "cannot create workqueue\n"); | 420 | dev_err(dev, "cannot create workqueue\n"); |
414 | goto error_create_workqueue; | 421 | goto error_create_workqueue; |
415 | } | 422 | } |
423 | result = i2400m->bus_dev_start(i2400m); | ||
424 | if (result < 0) | ||
425 | goto error_bus_dev_start; | ||
416 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ | 426 | result = i2400m_firmware_check(i2400m); /* fw versions ok? */ |
417 | if (result < 0) | 427 | if (result < 0) |
418 | goto error_fw_check; | 428 | goto error_fw_check; |
@@ -434,17 +444,17 @@ retry: | |||
434 | error_dev_initialize: | 444 | error_dev_initialize: |
435 | error_check_mac_addr: | 445 | error_check_mac_addr: |
436 | error_fw_check: | 446 | error_fw_check: |
437 | destroy_workqueue(i2400m->work_queue); | ||
438 | error_create_workqueue: | ||
439 | i2400m->bus_dev_stop(i2400m); | 447 | i2400m->bus_dev_stop(i2400m); |
440 | error_bus_dev_start: | 448 | error_bus_dev_start: |
449 | destroy_workqueue(i2400m->work_queue); | ||
450 | error_create_workqueue: | ||
441 | i2400m_rx_release(i2400m); | 451 | i2400m_rx_release(i2400m); |
442 | error_rx_setup: | 452 | error_rx_setup: |
443 | i2400m_tx_release(i2400m); | 453 | i2400m_tx_release(i2400m); |
444 | error_tx_setup: | 454 | error_tx_setup: |
445 | error_bootstrap: | 455 | error_bootstrap: |
446 | if (result == -ERESTARTSYS && times-- > 0) { | 456 | if (result == -EL3RST && times-- > 0) { |
447 | flags = I2400M_BRI_SOFT; | 457 | flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; |
448 | goto retry; | 458 | goto retry; |
449 | } | 459 | } |
450 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", | 460 | d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", |
@@ -473,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
473 | * | 483 | * |
474 | * Returns: 0 if ok, < 0 errno code on error. | 484 | * Returns: 0 if ok, < 0 errno code on error. |
475 | * | 485 | * |
476 | * 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. | ||
477 | */ | 489 | */ |
478 | static | 490 | static |
479 | void __i2400m_dev_stop(struct i2400m *i2400m) | 491 | void __i2400m_dev_stop(struct i2400m *i2400m) |
@@ -485,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) | |||
485 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); | 497 | wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); |
486 | i2400m_dev_shutdown(i2400m); | 498 | i2400m_dev_shutdown(i2400m); |
487 | i2400m->ready = 0; | 499 | i2400m->ready = 0; |
488 | destroy_workqueue(i2400m->work_queue); | ||
489 | i2400m->bus_dev_stop(i2400m); | 500 | i2400m->bus_dev_stop(i2400m); |
501 | destroy_workqueue(i2400m->work_queue); | ||
490 | i2400m_rx_release(i2400m); | 502 | i2400m_rx_release(i2400m); |
491 | i2400m_tx_release(i2400m); | 503 | i2400m_tx_release(i2400m); |
492 | wimax_state_change(wimax_dev, WIMAX_ST_DOWN); | 504 | wimax_state_change(wimax_dev, WIMAX_ST_DOWN); |
@@ -548,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) | |||
548 | * i2400m_dev_stop() [we are shutting down anyway, so | 560 | * i2400m_dev_stop() [we are shutting down anyway, so |
549 | * ignore it] or we are resetting somewhere else. */ | 561 | * ignore it] or we are resetting somewhere else. */ |
550 | dev_err(dev, "device rebooted\n"); | 562 | dev_err(dev, "device rebooted\n"); |
551 | i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); | 563 | i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); |
552 | complete(&i2400m->msg_completion); | 564 | complete(&i2400m->msg_completion); |
553 | goto out; | 565 | goto out; |
554 | } | 566 | } |
@@ -598,6 +610,8 @@ out: | |||
598 | */ | 610 | */ |
599 | int i2400m_dev_reset_handle(struct i2400m *i2400m) | 611 | int i2400m_dev_reset_handle(struct i2400m *i2400m) |
600 | { | 612 | { |
613 | i2400m->boot_mode = 1; | ||
614 | wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ | ||
601 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, | 615 | return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, |
602 | GFP_ATOMIC); | 616 | GFP_ATOMIC); |
603 | } | 617 | } |
@@ -650,6 +664,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
650 | result = i2400m_read_mac_addr(i2400m); | 664 | result = i2400m_read_mac_addr(i2400m); |
651 | if (result < 0) | 665 | if (result < 0) |
652 | goto error_read_mac_addr; | 666 | goto error_read_mac_addr; |
667 | random_ether_addr(i2400m->src_mac_addr); | ||
653 | 668 | ||
654 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | 669 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ |
655 | if (result < 0) { | 670 | if (result < 0) { |