1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Linux WiMAX 4 * Implement and export a method for resetting a WiMAX device 5 * 6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> 7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 8 * 9 * This implements a simple synchronous call to reset a WiMAX device. 10 * 11 * Resets aim at being warm, keeping the device handles active; 12 * however, when that fails, it falls back to a cold reset (that will 13 * disconnect and reconnect the device). 14 */ 15 16#include <net/wimax.h> 17#include <net/genetlink.h> 18#include <linux/wimax.h> 19#include <linux/security.h> 20#include <linux/export.h> 21#include "wimax-internal.h" 22 23#define D_SUBMODULE op_reset 24#include "debug-levels.h" 25 26 27/** 28 * wimax_reset - Reset a WiMAX device 29 * 30 * @wimax_dev: WiMAX device descriptor 31 * 32 * Returns: 33 * 34 * %0 if ok and a warm reset was done (the device still exists in 35 * the system). 36 * 37 * -%ENODEV if a cold/bus reset had to be done (device has 38 * disconnected and reconnected, so current handle is not valid 39 * any more). 40 * 41 * -%EINVAL if the device is not even registered. 42 * 43 * Any other negative error code shall be considered as 44 * non-recoverable. 45 * 46 * Description: 47 * 48 * Called when wanting to reset the device for any reason. Device is 49 * taken back to power on status. 50 * 51 * This call blocks; on successful return, the device has completed the 52 * reset process and is ready to operate. 53 */ 54int wimax_reset(struct wimax_dev *wimax_dev) 55{ 56 int result = -EINVAL; 57 struct device *dev = wimax_dev_to_dev(wimax_dev); 58 enum wimax_st state; 59 60 might_sleep(); 61 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); 62 mutex_lock(&wimax_dev->mutex); 63 dev_hold(wimax_dev->net_dev); 64 state = wimax_dev->state; 65 mutex_unlock(&wimax_dev->mutex); 66 67 if (state >= WIMAX_ST_DOWN) { 68 mutex_lock(&wimax_dev->mutex_reset); 69 result = wimax_dev->op_reset(wimax_dev); 70 mutex_unlock(&wimax_dev->mutex_reset); 71 } 72 dev_put(wimax_dev->net_dev); 73 74 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); 75 return result; 76} 77EXPORT_SYMBOL(wimax_reset); 78 79 80/* 81 * Exporting to user space over generic netlink 82 * 83 * Parse the reset command from user space, return error code. 84 * 85 * No attributes. 86 */ 87int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info) 88{ 89 int result, ifindex; 90 struct wimax_dev *wimax_dev; 91 92 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); 93 result = -ENODEV; 94 if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) { 95 pr_err("WIMAX_GNL_OP_RFKILL: can't find IFIDX attribute\n"); 96 goto error_no_wimax_dev; 97 } 98 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]); 99 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); 100 if (wimax_dev == NULL) 101 goto error_no_wimax_dev; 102 /* Execute the operation and send the result back to user space */ 103 result = wimax_reset(wimax_dev); 104 dev_put(wimax_dev->net_dev); 105error_no_wimax_dev: 106 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); 107 return result; 108} 109