Lines Matching +full:mode +full:- +full:recovery
1 // SPDX-License-Identifier: GPL-2.0-only
6 * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
21 * i240m->bus_reset()
29 * i2400m->bus_setup()
37 * i2400m->bus_dev_start()
45 * i2400m->bus_dev_stop()
47 * i2400m->bus_release()
60 #include "debug-levels.h"
67 "String of space-separated NAME:VALUE pairs, where NAMEs "
75 "String of comma-separated 32-bit values; each is "
77 "signal; values are appended to a list--setting one value "
128 result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); in i2400m_op_msg_from_user()
151 * See the documentation for wimax_reset() and wimax_dev->op_reset for
156 * and return -ENODEV. On successful warm reset, we need to block
159 * The bus-driver implementation of reset takes care of falling back
174 mutex_lock(&i2400m->init_mutex); in i2400m_op_reset()
175 i2400m->reset_ctx = &ctx; in i2400m_op_reset()
176 mutex_unlock(&i2400m->init_mutex); in i2400m_op_reset()
182 result = -ETIMEDOUT; in i2400m_op_reset()
186 mutex_lock(&i2400m->init_mutex); in i2400m_op_reset()
187 i2400m->reset_ctx = NULL; in i2400m_op_reset()
188 mutex_unlock(&i2400m->init_mutex); in i2400m_op_reset()
196 * Check the MAC address we got from boot mode is ok
209 struct net_device *net_dev = i2400m->wimax_dev.net_dev; in i2400m_check_mac_addr()
220 ddi = (void *) skb->data; in i2400m_check_mac_addr()
221 BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address)); in i2400m_check_mac_addr()
223 ddi->mac_address); in i2400m_check_mac_addr()
224 if (!memcmp(net_dev->perm_addr, ddi->mac_address, in i2400m_check_mac_addr()
225 sizeof(ddi->mac_address))) in i2400m_check_mac_addr()
228 "to that of boot mode's\n"); in i2400m_check_mac_addr()
229 dev_warn(dev, "device reports %pM\n", ddi->mac_address); in i2400m_check_mac_addr()
230 dev_warn(dev, "boot mode reported %pM\n", net_dev->perm_addr); in i2400m_check_mac_addr()
231 if (is_zero_ether_addr(ddi->mac_address)) in i2400m_check_mac_addr()
236 net_dev->addr_len = ETH_ALEN; in i2400m_check_mac_addr()
237 memcpy(net_dev->perm_addr, ddi->mac_address, ETH_ALEN); in i2400m_check_mac_addr()
238 memcpy(net_dev->dev_addr, ddi->mac_address, ETH_ALEN); in i2400m_check_mac_addr()
250 * __i2400m_dev_start - Bring up driver communication with the device
253 * @flags: boot mode flags
265 * TX needs to be setup before the bus-specific code (otherwise on
266 * shutdown, the bus-tx code could try to access it).
272 struct wimax_dev *wimax_dev = &i2400m->wimax_dev; in __i2400m_dev_start()
273 struct net_device *net_dev = wimax_dev->net_dev; in __i2400m_dev_start()
275 int times = i2400m->bus_bm_retries; in __i2400m_dev_start()
290 i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); in __i2400m_dev_start()
291 if (i2400m->work_queue == NULL) { in __i2400m_dev_start()
292 result = -ENOMEM; in __i2400m_dev_start()
296 if (i2400m->bus_dev_start) { in __i2400m_dev_start()
297 result = i2400m->bus_dev_start(i2400m); in __i2400m_dev_start()
301 i2400m->ready = 1; in __i2400m_dev_start()
302 wmb(); /* see i2400m->ready's documentation */ in __i2400m_dev_start()
304 queue_work(i2400m->work_queue, &i2400m->rx_report_ws); in __i2400m_dev_start()
316 /* We don't want any additional unwanted error recovery triggered in __i2400m_dev_start()
318 * here, let's keep i2400m->error_recovery untouched and leave it to in __i2400m_dev_start()
321 atomic_dec(&i2400m->error_recovery); in __i2400m_dev_start()
323 * take error recovery if it's required. */ in __i2400m_dev_start()
334 i2400m->ready = 0; in __i2400m_dev_start()
335 wmb(); /* see i2400m->ready's documentation */ in __i2400m_dev_start()
336 flush_workqueue(i2400m->work_queue); in __i2400m_dev_start()
337 if (i2400m->bus_dev_stop) in __i2400m_dev_start()
338 i2400m->bus_dev_stop(i2400m); in __i2400m_dev_start()
340 destroy_workqueue(i2400m->work_queue); in __i2400m_dev_start()
347 if (result == -EL3RST && times-- > 0) { in __i2400m_dev_start()
361 mutex_lock(&i2400m->init_mutex); /* Well, start the device */ in i2400m_dev_start()
362 if (i2400m->updown == 0) { in i2400m_dev_start()
365 i2400m->updown = 1; in i2400m_dev_start()
366 i2400m->alive = 1; in i2400m_dev_start()
367 wmb();/* see i2400m->updown and i2400m->alive's doc */ in i2400m_dev_start()
370 mutex_unlock(&i2400m->init_mutex); in i2400m_dev_start()
376 * i2400m_dev_stop - Tear down driver communication with the device
389 struct wimax_dev *wimax_dev = &i2400m->wimax_dev; in __i2400m_dev_stop()
394 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); in __i2400m_dev_stop()
395 complete(&i2400m->msg_completion); in __i2400m_dev_stop()
402 i2400m->ready = 0; /* nobody can queue work anymore */ in __i2400m_dev_stop()
403 wmb(); /* see i2400m->ready's documentation */ in __i2400m_dev_stop()
404 flush_workqueue(i2400m->work_queue); in __i2400m_dev_stop()
406 if (i2400m->bus_dev_stop) in __i2400m_dev_stop()
407 i2400m->bus_dev_stop(i2400m); in __i2400m_dev_stop()
408 destroy_workqueue(i2400m->work_queue); in __i2400m_dev_stop()
417 * Watch out -- we only need to stop if there is a need for it. The
424 mutex_lock(&i2400m->init_mutex); in i2400m_dev_stop()
425 if (i2400m->updown) { in i2400m_dev_stop()
427 i2400m->updown = 0; in i2400m_dev_stop()
428 i2400m->alive = 0; in i2400m_dev_stop()
429 wmb(); /* see i2400m->updown and i2400m->alive's doc */ in i2400m_dev_stop()
431 mutex_unlock(&i2400m->init_mutex); in i2400m_dev_stop()
481 * pre-reset is called before a device is going on reset
491 d_printf(1, dev, "pre-reset shut down\n"); in i2400m_pre_reset()
493 mutex_lock(&i2400m->init_mutex); in i2400m_pre_reset()
494 if (i2400m->updown) { in i2400m_pre_reset()
495 netif_tx_disable(i2400m->wimax_dev.net_dev); in i2400m_pre_reset()
497 /* down't set updown to zero -- this way in i2400m_pre_reset()
500 mutex_unlock(&i2400m->init_mutex); in i2400m_pre_reset()
501 if (i2400m->bus_release) in i2400m_pre_reset()
502 i2400m->bus_release(i2400m); in i2400m_pre_reset()
515 * NOTE: this requires i2400m->init_mutex taken
523 d_printf(1, dev, "post-reset start\n"); in i2400m_post_reset()
524 if (i2400m->bus_setup) { in i2400m_post_reset()
525 result = i2400m->bus_setup(i2400m); in i2400m_post_reset()
527 dev_err(dev, "bus-specific setup failed: %d\n", in i2400m_post_reset()
532 mutex_lock(&i2400m->init_mutex); in i2400m_post_reset()
533 if (i2400m->updown) { in i2400m_post_reset()
539 mutex_unlock(&i2400m->init_mutex); in i2400m_post_reset()
544 if (i2400m->bus_release) in i2400m_post_reset()
545 i2400m->bus_release(i2400m); in i2400m_post_reset()
548 i2400m->updown = 0; in i2400m_post_reset()
549 wmb(); /* see i2400m->updown's documentation */ in i2400m_post_reset()
550 mutex_unlock(&i2400m->init_mutex); in i2400m_post_reset()
585 const char *reason = i2400m->reset_reason; in __i2400m_dev_reset_handle()
587 struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; in __i2400m_dev_reset_handle()
592 i2400m->boot_mode = 1; in __i2400m_dev_reset_handle()
596 if (mutex_trylock(&i2400m->init_mutex) == 0) { in __i2400m_dev_reset_handle()
601 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); in __i2400m_dev_reset_handle()
602 complete(&i2400m->msg_completion); in __i2400m_dev_reset_handle()
608 if (i2400m->updown) { in __i2400m_dev_reset_handle()
610 i2400m->updown = 0; in __i2400m_dev_reset_handle()
611 wmb(); /* see i2400m->updown's documentation */ in __i2400m_dev_reset_handle()
614 if (i2400m->alive) { in __i2400m_dev_reset_handle()
620 result = -EUCLEAN; in __i2400m_dev_reset_handle()
621 if (atomic_read(&i2400m->bus_reset_retries) in __i2400m_dev_reset_handle()
623 result = -ENODEV; in __i2400m_dev_reset_handle()
630 if (i2400m->reset_ctx) { in __i2400m_dev_reset_handle()
631 ctx->result = result; in __i2400m_dev_reset_handle()
632 complete(&ctx->completion); in __i2400m_dev_reset_handle()
634 mutex_unlock(&i2400m->init_mutex); in __i2400m_dev_reset_handle()
635 if (result == -EUCLEAN) { in __i2400m_dev_reset_handle()
637 * We come here because the reset during operational mode in __i2400m_dev_reset_handle()
644 i2400m->boot_mode = 0; in __i2400m_dev_reset_handle()
647 atomic_inc(&i2400m->bus_reset_retries); in __i2400m_dev_reset_handle()
651 result = -ENODEV; in __i2400m_dev_reset_handle()
654 if (i2400m->alive) { in __i2400m_dev_reset_handle()
657 i2400m->updown = 1; in __i2400m_dev_reset_handle()
659 atomic_set(&i2400m->bus_reset_retries, 0); in __i2400m_dev_reset_handle()
669 * i2400m_dev_reset_handle - Handle a device's reset in a thread context
678 * bus-specific functions ops as needed.
682 i2400m->reset_reason = reason; in i2400m_dev_reset_handle()
683 return schedule_work(&i2400m->reset_ws); in i2400m_dev_reset_handle()
689 * The actual work of error recovery.
691 * The current implementation of error recovery is to trigger a bus reset.
702 * Schedule a work struct for error recovery.
704 * The intention of error recovery is to bring back the device to some
705 * known state whenever TX sees -110 (-ETIMEOUT) on copying the data to
707 * error recovery implementation is to trigger a bus reset to the device
710 * The actual work of error recovery has to be in a thread context because
711 * it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be
712 * destroyed by the error recovery mechanism (currently a bus reset).
715 * the -ETIMEOUT error condition because the device is stuck already.
716 * Since bus reset is used as the error recovery mechanism and we don't
721 * Error recovery shall only be invoked again if previous one was completed.
722 * The flag error_recovery is set when error recovery mechanism is scheduled,
723 * and is checked when we need to schedule another error recovery. If it is
728 if (atomic_add_return(1, &i2400m->error_recovery) == 1) in i2400m_error_recovery()
729 schedule_work(&i2400m->recovery_ws); in i2400m_error_recovery()
731 atomic_dec(&i2400m->error_recovery); in i2400m_error_recovery()
736 * Alloc the command and ack buffers for boot mode
738 * Get the buffers needed to deal with boot mode messages.
743 i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL); in i2400m_bm_buf_alloc()
744 if (i2400m->bm_cmd_buf == NULL) in i2400m_bm_buf_alloc()
746 i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL); in i2400m_bm_buf_alloc()
747 if (i2400m->bm_ack_buf == NULL) in i2400m_bm_buf_alloc()
752 kfree(i2400m->bm_cmd_buf); in i2400m_bm_buf_alloc()
754 return -ENOMEM; in i2400m_bm_buf_alloc()
759 * Free boot mode command and ack buffers.
764 kfree(i2400m->bm_ack_buf); in i2400m_bm_buf_free()
765 kfree(i2400m->bm_cmd_buf); in i2400m_bm_buf_free()
770 * i2400m_init - Initialize a 'struct i2400m' from all zeroes
772 * This is a bus-generic API call.
776 wimax_dev_init(&i2400m->wimax_dev); in i2400m_init()
778 i2400m->boot_mode = 1; in i2400m_init()
779 i2400m->rx_reorder = 1; in i2400m_init()
780 init_waitqueue_head(&i2400m->state_wq); in i2400m_init()
782 spin_lock_init(&i2400m->tx_lock); in i2400m_init()
783 i2400m->tx_pl_min = UINT_MAX; in i2400m_init()
784 i2400m->tx_size_min = UINT_MAX; in i2400m_init()
786 spin_lock_init(&i2400m->rx_lock); in i2400m_init()
787 i2400m->rx_pl_min = UINT_MAX; in i2400m_init()
788 i2400m->rx_size_min = UINT_MAX; in i2400m_init()
789 INIT_LIST_HEAD(&i2400m->rx_reports); in i2400m_init()
790 INIT_WORK(&i2400m->rx_report_ws, i2400m_report_hook_work); in i2400m_init()
792 mutex_init(&i2400m->msg_mutex); in i2400m_init()
793 init_completion(&i2400m->msg_completion); in i2400m_init()
795 mutex_init(&i2400m->init_mutex); in i2400m_init()
798 INIT_WORK(&i2400m->reset_ws, __i2400m_dev_reset_handle); in i2400m_init()
799 INIT_WORK(&i2400m->recovery_ws, __i2400m_error_recovery); in i2400m_init()
801 atomic_set(&i2400m->bus_reset_retries, 0); in i2400m_init()
803 i2400m->alive = 0; in i2400m_init()
806 * are not yet ready to take any error recovery */ in i2400m_init()
807 atomic_set(&i2400m->error_recovery, 1); in i2400m_init()
814 struct net_device *net_dev = i2400m->wimax_dev.net_dev; in i2400m_reset()
821 if (net_dev->reg_state == NETREG_REGISTERED) { in i2400m_reset()
825 return i2400m->bus_reset(i2400m, rt); in i2400m_reset()
831 * i2400m_setup - bus-generic setup function for the i2400m device
833 * @i2400m: device descriptor (bus-specific parts have been initialized)
845 struct wimax_dev *wimax_dev = &i2400m->wimax_dev; in i2400m_setup()
846 struct net_device *net_dev = i2400m->wimax_dev.net_dev; in i2400m_setup()
850 snprintf(wimax_dev->name, sizeof(wimax_dev->name), in i2400m_setup()
851 "i2400m-%s:%s", dev->bus->name, dev_name(dev)); in i2400m_setup()
859 if (i2400m->bus_setup) { in i2400m_setup()
860 result = i2400m->bus_setup(i2400m); in i2400m_setup()
862 dev_err(dev, "bus-specific setup failed: %d\n", in i2400m_setup()
877 eth_random_addr(i2400m->src_mac_addr); in i2400m_setup()
879 i2400m->pm_notifier.notifier_call = i2400m_pm_notifier; in i2400m_setup()
880 register_pm_notifier(&i2400m->pm_notifier); in i2400m_setup()
890 i2400m->wimax_dev.op_msg_from_user = i2400m_op_msg_from_user; in i2400m_setup()
891 i2400m->wimax_dev.op_rfkill_sw_toggle = i2400m_op_rfkill_sw_toggle; in i2400m_setup()
892 i2400m->wimax_dev.op_reset = i2400m_op_reset; in i2400m_setup()
894 result = wimax_dev_add(&i2400m->wimax_dev, net_dev); in i2400m_setup()
899 result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group); in i2400m_setup()
915 sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, in i2400m_setup()
918 wimax_dev_rm(&i2400m->wimax_dev); in i2400m_setup()
922 unregister_pm_notifier(&i2400m->pm_notifier); in i2400m_setup()
925 if (i2400m->bus_release) in i2400m_setup()
926 i2400m->bus_release(i2400m); in i2400m_setup()
937 * i2400m_release - release the bus-generic driver resources
946 netif_stop_queue(i2400m->wimax_dev.net_dev); in i2400m_release()
950 cancel_work_sync(&i2400m->reset_ws); in i2400m_release()
951 cancel_work_sync(&i2400m->recovery_ws); in i2400m_release()
954 sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj, in i2400m_release()
956 wimax_dev_rm(&i2400m->wimax_dev); in i2400m_release()
957 unregister_netdev(i2400m->wimax_dev.net_dev); in i2400m_release()
958 unregister_pm_notifier(&i2400m->pm_notifier); in i2400m_release()
959 if (i2400m->bus_release) in i2400m_release()
960 i2400m->bus_release(i2400m); in i2400m_release()
1000 MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
1001 MODULE_DESCRIPTION("Intel 2400M WiMAX networking bus-generic driver");