aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wimax/i2400m/driver.c44
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h23
-rw-r--r--drivers/net/wimax/i2400m/rx.c16
-rw-r--r--drivers/net/wimax/i2400m/usb.c7
-rw-r--r--include/net/wimax.h6
5 files changed, 70 insertions, 26 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index a0ae19966c0c..6280646d7d7f 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -455,6 +455,8 @@ retry:
455 result = i2400m->bus_dev_start(i2400m); 455 result = i2400m->bus_dev_start(i2400m);
456 if (result < 0) 456 if (result < 0)
457 goto error_bus_dev_start; 457 goto error_bus_dev_start;
458 i2400m->ready = 1;
459 wmb(); /* see i2400m->ready's documentation */
458 result = i2400m_firmware_check(i2400m); /* fw versions ok? */ 460 result = i2400m_firmware_check(i2400m); /* fw versions ok? */
459 if (result < 0) 461 if (result < 0)
460 goto error_fw_check; 462 goto error_fw_check;
@@ -462,7 +464,6 @@ retry:
462 result = i2400m_check_mac_addr(i2400m); 464 result = i2400m_check_mac_addr(i2400m);
463 if (result < 0) 465 if (result < 0)
464 goto error_check_mac_addr; 466 goto error_check_mac_addr;
465 i2400m->ready = 1;
466 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); 467 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
467 result = i2400m_dev_initialize(i2400m); 468 result = i2400m_dev_initialize(i2400m);
468 if (result < 0) 469 if (result < 0)
@@ -475,6 +476,9 @@ retry:
475 476
476error_dev_initialize: 477error_dev_initialize:
477error_check_mac_addr: 478error_check_mac_addr:
479 i2400m->ready = 0;
480 wmb(); /* see i2400m->ready's documentation */
481 flush_workqueue(i2400m->work_queue);
478error_fw_check: 482error_fw_check:
479 i2400m->bus_dev_stop(i2400m); 483 i2400m->bus_dev_stop(i2400m);
480error_bus_dev_start: 484error_bus_dev_start:
@@ -498,11 +502,15 @@ error_bootstrap:
498static 502static
499int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) 503int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
500{ 504{
501 int result; 505 int result = 0;
502 mutex_lock(&i2400m->init_mutex); /* Well, start the device */ 506 mutex_lock(&i2400m->init_mutex); /* Well, start the device */
503 result = __i2400m_dev_start(i2400m, bm_flags); 507 if (i2400m->updown == 0) {
504 if (result >= 0) 508 result = __i2400m_dev_start(i2400m, bm_flags);
505 i2400m->updown = 1; 509 if (result >= 0) {
510 i2400m->updown = 1;
511 wmb(); /* see i2400m->updown's documentation */
512 }
513 }
506 mutex_unlock(&i2400m->init_mutex); 514 mutex_unlock(&i2400m->init_mutex);
507 return result; 515 return result;
508} 516}
@@ -529,7 +537,14 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
529 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); 537 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
530 i2400m_net_wake_stop(i2400m); 538 i2400m_net_wake_stop(i2400m);
531 i2400m_dev_shutdown(i2400m); 539 i2400m_dev_shutdown(i2400m);
532 i2400m->ready = 0; 540 /*
541 * Make sure no report hooks are running *before* we stop the
542 * communication infrastructure with the device.
543 */
544 i2400m->ready = 0; /* nobody can queue work anymore */
545 wmb(); /* see i2400m->ready's documentation */
546 flush_workqueue(i2400m->work_queue);
547
533 i2400m->bus_dev_stop(i2400m); 548 i2400m->bus_dev_stop(i2400m);
534 destroy_workqueue(i2400m->work_queue); 549 destroy_workqueue(i2400m->work_queue);
535 i2400m_rx_release(i2400m); 550 i2400m_rx_release(i2400m);
@@ -551,6 +566,7 @@ void i2400m_dev_stop(struct i2400m *i2400m)
551 if (i2400m->updown) { 566 if (i2400m->updown) {
552 __i2400m_dev_stop(i2400m); 567 __i2400m_dev_stop(i2400m);
553 i2400m->updown = 0; 568 i2400m->updown = 0;
569 wmb(); /* see i2400m->updown's documentation */
554 } 570 }
555 mutex_unlock(&i2400m->init_mutex); 571 mutex_unlock(&i2400m->init_mutex);
556} 572}
@@ -632,7 +648,6 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
632 const char *reason; 648 const char *reason;
633 struct i2400m *i2400m = iw->i2400m; 649 struct i2400m *i2400m = iw->i2400m;
634 struct device *dev = i2400m_dev(i2400m); 650 struct device *dev = i2400m_dev(i2400m);
635 enum wimax_st wimax_state;
636 struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; 651 struct i2400m_reset_ctx *ctx = i2400m->reset_ctx;
637 652
638 if (WARN_ON(iw->pl_size != sizeof(reason))) 653 if (WARN_ON(iw->pl_size != sizeof(reason)))
@@ -647,29 +662,28 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
647 /* We are still in i2400m_dev_start() [let it fail] or 662 /* We are still in i2400m_dev_start() [let it fail] or
648 * i2400m_dev_stop() [we are shutting down anyway, so 663 * i2400m_dev_stop() [we are shutting down anyway, so
649 * ignore it] or we are resetting somewhere else. */ 664 * ignore it] or we are resetting somewhere else. */
650 dev_err(dev, "device rebooted\n"); 665 dev_err(dev, "device rebooted somewhere else?\n");
651 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); 666 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST);
652 complete(&i2400m->msg_completion); 667 complete(&i2400m->msg_completion);
653 goto out; 668 goto out;
654 } 669 }
655 wimax_state = wimax_state_get(&i2400m->wimax_dev); 670 if (i2400m->updown == 0) {
656 if (wimax_state < WIMAX_ST_UNINITIALIZED) { 671 dev_info(dev, "%s: device is down, doing nothing\n", reason);
657 dev_info(dev, "%s: it is down, ignoring\n", reason); 672 goto out_unlock;
658 goto out_unlock; /* ifconfig up/down wasn't called */
659 } 673 }
660 dev_err(dev, "%s: reinitializing driver\n", reason); 674 dev_err(dev, "%s: reinitializing driver\n", reason);
661 __i2400m_dev_stop(i2400m); 675 __i2400m_dev_stop(i2400m);
662 i2400m->updown = 0;
663 result = __i2400m_dev_start(i2400m, 676 result = __i2400m_dev_start(i2400m,
664 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); 677 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
665 if (result < 0) { 678 if (result < 0) {
679 i2400m->updown = 0;
680 wmb(); /* see i2400m->updown's documentation */
666 dev_err(dev, "%s: cannot start the device: %d\n", 681 dev_err(dev, "%s: cannot start the device: %d\n",
667 reason, result); 682 reason, result);
668 result = i2400m->bus_reset(i2400m, I2400M_RT_BUS); 683 result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
669 if (result >= 0) 684 if (result >= 0)
670 result = -ENODEV; 685 result = -ENODEV;
671 } else 686 }
672 i2400m->updown = 1;
673out_unlock: 687out_unlock:
674 if (i2400m->reset_ctx) { 688 if (i2400m->reset_ctx) {
675 ctx->result = result; 689 ctx->result = result;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 2b9c400810b5..fbc156db5bfd 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -307,6 +307,27 @@ struct i2400m_barker_db;
307 * force this to be the first field so that we can get from 307 * force this to be the first field so that we can get from
308 * netdev_priv() the right pointer. 308 * netdev_priv() the right pointer.
309 * 309 *
310 * @updown: the device is up and ready for transmitting control and
311 * data packets. This implies @ready (communication infrastructure
312 * with the device is ready) and the device's firmware has been
313 * loaded and the device initialized.
314 *
315 * Write to it only inside a i2400m->init_mutex protected area
316 * followed with a wmb(); rmb() before accesing (unless locked
317 * inside i2400m->init_mutex). Read access can be loose like that
318 * [just using rmb()] because the paths that use this also do
319 * other error checks later on.
320 *
321 * @ready: Communication infrastructure with the device is ready, data
322 * frames can start to be passed around (this is lighter than
323 * using the WiMAX state for certain hot paths).
324 *
325 * Write to it only inside a i2400m->init_mutex protected area
326 * followed with a wmb(); rmb() before accesing (unless locked
327 * inside i2400m->init_mutex). Read access can be loose like that
328 * [just using rmb()] because the paths that use this also do
329 * other error checks later on.
330 *
310 * @rx_reorder: 1 if RX reordering is enabled; this can only be 331 * @rx_reorder: 1 if RX reordering is enabled; this can only be
311 * set at probe time. 332 * set at probe time.
312 * 333 *
@@ -458,7 +479,7 @@ struct i2400m {
458 unsigned updown:1; /* Network device is up or down */ 479 unsigned updown:1; /* Network device is up or down */
459 unsigned boot_mode:1; /* is the device in boot mode? */ 480 unsigned boot_mode:1; /* is the device in boot mode? */
460 unsigned sboot:1; /* signed or unsigned fw boot */ 481 unsigned sboot:1; /* signed or unsigned fw boot */
461 unsigned ready:1; /* all probing steps done */ 482 unsigned ready:1; /* Device comm infrastructure ready */
462 unsigned rx_reorder:1; /* RX reorder is enabled */ 483 unsigned rx_reorder:1; /* RX reorder is enabled */
463 u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */ 484 u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */
464 /* typed u8 so /sys/kernel/debug/u8 can tweak */ 485 /* typed u8 so /sys/kernel/debug/u8 can tweak */
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index bcd411f1a854..82c200ad9fdc 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -177,8 +177,7 @@ void i2400m_report_hook_work(struct work_struct *ws)
177 struct i2400m_work *iw = 177 struct i2400m_work *iw =
178 container_of(ws, struct i2400m_work, ws); 178 container_of(ws, struct i2400m_work, ws);
179 struct i2400m_report_hook_args *args = (void *) iw->pl; 179 struct i2400m_report_hook_args *args = (void *) iw->pl;
180 if (iw->i2400m->ready) 180 i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
181 i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
182 kfree_skb(args->skb_rx); 181 kfree_skb(args->skb_rx);
183 i2400m_put(iw->i2400m); 182 i2400m_put(iw->i2400m);
184 kfree(iw); 183 kfree(iw);
@@ -305,11 +304,12 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
305 .l3l4_hdr = l3l4_hdr, 304 .l3l4_hdr = l3l4_hdr,
306 .size = size 305 .size = size
307 }; 306 };
308 if (unlikely(i2400m->ready == 0)) /* only send if up */ 307 rmb(); /* see i2400m->ready's documentation */
309 return; 308 if (likely(i2400m->ready)) { /* only send if up */
310 skb_get(skb_rx); 309 skb_get(skb_rx);
311 i2400m_queue_work(i2400m, i2400m_report_hook_work, 310 i2400m_queue_work(i2400m, i2400m_report_hook_work,
312 GFP_KERNEL, &args, sizeof(args)); 311 GFP_KERNEL, &args, sizeof(args));
312 }
313 if (unlikely(i2400m->trace_msg_from_user)) 313 if (unlikely(i2400m->trace_msg_from_user))
314 wimax_msg(&i2400m->wimax_dev, "echo", 314 wimax_msg(&i2400m->wimax_dev, "echo",
315 l3l4_hdr, size, GFP_KERNEL); 315 l3l4_hdr, size, GFP_KERNEL);
@@ -363,8 +363,6 @@ void i2400m_rx_trace(struct i2400m *i2400m,
363 msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET", 363 msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET",
364 msg_type, size); 364 msg_type, size);
365 d_dump(2, dev, l3l4_hdr, size); 365 d_dump(2, dev, l3l4_hdr, size);
366 if (unlikely(i2400m->ready == 0)) /* only send if up */
367 return;
368 result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL); 366 result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL);
369 if (result < 0) 367 if (result < 0)
370 dev_err(dev, "error sending trace to userspace: %d\n", 368 dev_err(dev, "error sending trace to userspace: %d\n",
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 07653ded6c59..f4dfb60bb628 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -516,7 +516,10 @@ void i2400mu_disconnect(struct usb_interface *iface)
516 * So at the end, the three cases require common handling. 516 * So at the end, the three cases require common handling.
517 * 517 *
518 * If at the time of this call the device's firmware is not loaded, 518 * If at the time of this call the device's firmware is not loaded,
519 * nothing has to be done. 519 * nothing has to be done. Note we can be "loose" about not reading
520 * i2400m->updown under i2400m->init_mutex. If it happens to change
521 * inmediately, other parts of the call flow will fail and effectively
522 * catch it.
520 * 523 *
521 * If the firmware is loaded, we need to: 524 * If the firmware is loaded, we need to:
522 * 525 *
@@ -555,6 +558,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
555#endif 558#endif
556 559
557 d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); 560 d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
561 rmb(); /* see i2400m->updown's documentation */
558 if (i2400m->updown == 0) 562 if (i2400m->updown == 0)
559 goto no_firmware; 563 goto no_firmware;
560 if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { 564 if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
@@ -608,6 +612,7 @@ int i2400mu_resume(struct usb_interface *iface)
608 struct i2400m *i2400m = &i2400mu->i2400m; 612 struct i2400m *i2400m = &i2400mu->i2400m;
609 613
610 d_fnstart(3, dev, "(iface %p)\n", iface); 614 d_fnstart(3, dev, "(iface %p)\n", iface);
615 rmb(); /* see i2400m->updown's documentation */
611 if (i2400m->updown == 0) { 616 if (i2400m->updown == 0) {
612 d_printf(1, dev, "fw was down, no resume neeed\n"); 617 d_printf(1, dev, "fw was down, no resume neeed\n");
613 goto out; 618 goto out;
diff --git a/include/net/wimax.h b/include/net/wimax.h
index 2af7bf839f23..d69c4a7a1267 100644
--- a/include/net/wimax.h
+++ b/include/net/wimax.h
@@ -195,6 +195,12 @@
195 * defining the `struct nla_policy` for each message, it has to have 195 * defining the `struct nla_policy` for each message, it has to have
196 * an array size of WIMAX_GNL_ATTR_MAX+1. 196 * an array size of WIMAX_GNL_ATTR_MAX+1.
197 * 197 *
198 * The op_*() function pointers will not be called if the wimax_dev is
199 * in a state <= %WIMAX_ST_UNINITIALIZED. The exception is:
200 *
201 * - op_reset: can be called at any time after wimax_dev_add() has
202 * been called.
203 *
198 * THE PIPE INTERFACE: 204 * THE PIPE INTERFACE:
199 * 205 *
200 * This interface is kept intentionally simple. The driver can send 206 * This interface is kept intentionally simple. The driver can send