1/* 2 * Linux WiMAX 3 * Implement and export a method for resetting a WiMAX device 4 * 5 * 6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> 7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License version 11 * 2 as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 * 02110-1301, USA. 22 * 23 * 24 * This implements a simple synchronous call to reset a WiMAX device. 25 * 26 * Resets aim at being warm, keeping the device handles active; 27 * however, when that fails, it falls back to a cold reset (that will 28 * disconnect and reconnect the device). 29 */ 30 31#include <net/wimax.h> 32#include <net/genetlink.h> 33#include <linux/wimax.h> 34#include <linux/security.h> 35#include "wimax-internal.h" 36 37#define D_SUBMODULE op_reset 38#include "debug-levels.h" 39 40 41/** 42 * wimax_reset - Reset a WiMAX device 43 * 44 * @wimax_dev: WiMAX device descriptor 45 * 46 * Returns: 47 * 48 * %0 if ok and a warm reset was done (the device still exists in 49 * the system). 50 * 51 * -%ENODEV if a cold/bus reset had to be done (device has 52 * disconnected and reconnected, so current handle is not valid 53 * any more). 54 * 55 * -%EINVAL if the device is not even registered. 56 * 57 * Any other negative error code shall be considered as 58 * non-recoverable. 59 * 60 * Description: 61 * 62 * Called when wanting to reset the device for any reason. Device is 63 * taken back to power on status. 64 * 65 * This call blocks; on successful return, the device has completed the 66 * reset process and is ready to operate. 67 */ 68int wimax_reset(struct wimax_dev *wimax_dev) 69{ 70 int result = -EINVAL; 71 struct device *dev = wimax_dev_to_dev(wimax_dev); 72 enum wimax_st state; 73 74 might_sleep(); 75 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); 76 mutex_lock(&wimax_dev->mutex); 77 dev_hold(wimax_dev->net_dev); 78 state = wimax_dev->state; 79 mutex_unlock(&wimax_dev->mutex); 80 81 if (state >= WIMAX_ST_DOWN) { 82 mutex_lock(&wimax_dev->mutex_reset); 83 result = wimax_dev->op_reset(wimax_dev); 84 mutex_unlock(&wimax_dev->mutex_reset); 85 } 86 dev_put(wimax_dev->net_dev); 87 88 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); 89 return result; 90} 91EXPORT_SYMBOL(wimax_reset); 92 93 94static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = { 95 [WIMAX_GNL_RESET_IFIDX] = { 96 .type = NLA_U32, 97 }, 98}; 99 100 101/* 102 * Exporting to user space over generic netlink 103 * 104 * Parse the reset command from user space, return error code. 105 * 106 * No attributes. 107 */ 108static 109int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info) 110{ 111 int result, ifindex; 112 struct wimax_dev *wimax_dev; 113 114 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); 115 result = -ENODEV; 116 if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) { 117 printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX " 118 "attribute\n"); 119 goto error_no_wimax_dev; 120 } 121 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]); 122 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); 123 if (wimax_dev == NULL) 124 goto error_no_wimax_dev; 125 /* Execute the operation and send the result back to user space */ 126 result = wimax_reset(wimax_dev); 127 dev_put(wimax_dev->net_dev); 128error_no_wimax_dev: 129 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); 130 return result; 131} 132 133 134struct genl_ops wimax_gnl_reset = { 135 .cmd = WIMAX_GNL_OP_RESET, 136 .flags = GENL_ADMIN_PERM, 137 .policy = wimax_gnl_reset_policy, 138 .doit = wimax_gnl_doit_reset, 139 .dumpit = NULL, 140}; 141