aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-17 18:20:45 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:56:10 -0400
commit3725d8c97436aeaa03eeb0c25361a7ec0f3f5bd2 (patch)
treec773759b4757473172ff6ba3ec26c134f5fc3d42 /drivers/net
parent2869da8587604e3fea5f85aeade486a08e8313bf (diff)
wimax/i2400m: Implement pre/post reset support in the USB driver
The USB stack can callback a driver is about to be reset by an external entity and right after it, so the driver can save state and then restore it. This commit implements said support; it is implemented actually in the core, bus-generic driver [i2400m_{pre,post}_reset()] and used by the bus-specific drivers. This way the SDIO driver can also use it once said support is brought to the SDIO stack. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wimax/i2400m/driver.c81
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h2
-rw-r--r--drivers/net/wimax/i2400m/usb.c33
3 files changed, 116 insertions, 0 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 4fcdb18261fd..1f6aa2a55429 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -620,6 +620,87 @@ int i2400m_pm_notifier(struct notifier_block *notifier,
620 620
621 621
622/* 622/*
623 * pre-reset is called before a device is going on reset
624 *
625 * This has to be followed by a call to i2400m_post_reset(), otherwise
626 * bad things might happen.
627 */
628int i2400m_pre_reset(struct i2400m *i2400m)
629{
630 int result;
631 struct device *dev = i2400m_dev(i2400m);
632
633 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
634 d_printf(1, dev, "pre-reset shut down\n");
635
636 result = 0;
637 mutex_lock(&i2400m->init_mutex);
638 if (i2400m->updown) {
639 netif_tx_disable(i2400m->wimax_dev.net_dev);
640 __i2400m_dev_stop(i2400m);
641 result = 0;
642 /* down't set updown to zero -- this way
643 * post_reset can restore properly */
644 }
645 mutex_unlock(&i2400m->init_mutex);
646 if (i2400m->bus_release)
647 i2400m->bus_release(i2400m);
648 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
649 return result;
650}
651EXPORT_SYMBOL_GPL(i2400m_pre_reset);
652
653
654/*
655 * Restore device state after a reset
656 *
657 * Do the work needed after a device reset to bring it up to the same
658 * state as it was before the reset.
659 *
660 * NOTE: this requires i2400m->init_mutex taken
661 */
662int i2400m_post_reset(struct i2400m *i2400m)
663{
664 int result = 0;
665 struct device *dev = i2400m_dev(i2400m);
666
667 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
668 d_printf(1, dev, "post-reset start\n");
669 if (i2400m->bus_setup) {
670 result = i2400m->bus_setup(i2400m);
671 if (result < 0) {
672 dev_err(dev, "bus-specific setup failed: %d\n",
673 result);
674 goto error_bus_setup;
675 }
676 }
677 mutex_lock(&i2400m->init_mutex);
678 if (i2400m->updown) {
679 result = __i2400m_dev_start(
680 i2400m, I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
681 if (result < 0)
682 goto error_dev_start;
683 }
684 mutex_unlock(&i2400m->init_mutex);
685 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
686 return result;
687
688error_dev_start:
689 if (i2400m->bus_release)
690 i2400m->bus_release(i2400m);
691error_bus_setup:
692 /* even if the device was up, it could not be recovered, so we
693 * mark it as down. */
694 i2400m->updown = 0;
695 wmb(); /* see i2400m->updown's documentation */
696 mutex_unlock(&i2400m->init_mutex);
697 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
698 return result;
699}
700EXPORT_SYMBOL_GPL(i2400m_post_reset);
701
702
703/*
623 * The device has rebooted; fix up the device and the driver 704 * The device has rebooted; fix up the device and the driver
624 * 705 *
625 * Tear down the driver communication with the device, reload the 706 * Tear down the driver communication with the device, reload the
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 1724955e0fe9..8fc8a0ca5126 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -817,6 +817,8 @@ void i2400m_put(struct i2400m *i2400m)
817} 817}
818 818
819extern int i2400m_dev_reset_handle(struct i2400m *, const char *); 819extern int i2400m_dev_reset_handle(struct i2400m *, const char *);
820extern int i2400m_pre_reset(struct i2400m *);
821extern int i2400m_post_reset(struct i2400m *);
820 822
821/* 823/*
822 * _setup()/_release() are called by the probe/disconnect functions of 824 * _setup()/_release() are called by the probe/disconnect functions of
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 77567970fe9a..8b246cc498b1 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -637,6 +637,37 @@ int i2400mu_reset_resume(struct usb_interface *iface)
637} 637}
638 638
639 639
640/*
641 * Another driver or user space is triggering a reset on the device
642 * which contains the interface passed as an argument. Cease IO and
643 * save any device state you need to restore.
644 *
645 * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
646 * you are in atomic context.
647 */
648static
649int i2400mu_pre_reset(struct usb_interface *iface)
650{
651 struct i2400mu *i2400mu = usb_get_intfdata(iface);
652 return i2400m_pre_reset(&i2400mu->i2400m);
653}
654
655
656/*
657 * The reset has completed. Restore any saved device state and begin
658 * using the device again.
659 *
660 * If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
661 * you are in atomic context.
662 */
663static
664int i2400mu_post_reset(struct usb_interface *iface)
665{
666 struct i2400mu *i2400mu = usb_get_intfdata(iface);
667 return i2400m_post_reset(&i2400mu->i2400m);
668}
669
670
640static 671static
641struct usb_device_id i2400mu_id_table[] = { 672struct usb_device_id i2400mu_id_table[] = {
642 { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) }, 673 { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
@@ -660,6 +691,8 @@ struct usb_driver i2400mu_driver = {
660 .reset_resume = i2400mu_reset_resume, 691 .reset_resume = i2400mu_reset_resume,
661 .probe = i2400mu_probe, 692 .probe = i2400mu_probe,
662 .disconnect = i2400mu_disconnect, 693 .disconnect = i2400mu_disconnect,
694 .pre_reset = i2400mu_pre_reset,
695 .post_reset = i2400mu_post_reset,
663 .id_table = i2400mu_id_table, 696 .id_table = i2400mu_id_table,
664 .supports_autosuspend = 1, 697 .supports_autosuspend = 1,
665}; 698};