18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux WiMAX 48c2ecf20Sopenharmony_ci * Implement and export a method for resetting a WiMAX device 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> 78c2ecf20Sopenharmony_ci * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This implements a simple synchronous call to reset a WiMAX device. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Resets aim at being warm, keeping the device handles active; 128c2ecf20Sopenharmony_ci * however, when that fails, it falls back to a cold reset (that will 138c2ecf20Sopenharmony_ci * disconnect and reconnect the device). 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <net/wimax.h> 178c2ecf20Sopenharmony_ci#include <net/genetlink.h> 188c2ecf20Sopenharmony_ci#include <linux/wimax.h> 198c2ecf20Sopenharmony_ci#include <linux/security.h> 208c2ecf20Sopenharmony_ci#include <linux/export.h> 218c2ecf20Sopenharmony_ci#include "wimax-internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define D_SUBMODULE op_reset 248c2ecf20Sopenharmony_ci#include "debug-levels.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/** 288c2ecf20Sopenharmony_ci * wimax_reset - Reset a WiMAX device 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * @wimax_dev: WiMAX device descriptor 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Returns: 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * %0 if ok and a warm reset was done (the device still exists in 358c2ecf20Sopenharmony_ci * the system). 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * -%ENODEV if a cold/bus reset had to be done (device has 388c2ecf20Sopenharmony_ci * disconnected and reconnected, so current handle is not valid 398c2ecf20Sopenharmony_ci * any more). 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * -%EINVAL if the device is not even registered. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * Any other negative error code shall be considered as 448c2ecf20Sopenharmony_ci * non-recoverable. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Description: 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Called when wanting to reset the device for any reason. Device is 498c2ecf20Sopenharmony_ci * taken back to power on status. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * This call blocks; on successful return, the device has completed the 528c2ecf20Sopenharmony_ci * reset process and is ready to operate. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ciint wimax_reset(struct wimax_dev *wimax_dev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int result = -EINVAL; 578c2ecf20Sopenharmony_ci struct device *dev = wimax_dev_to_dev(wimax_dev); 588c2ecf20Sopenharmony_ci enum wimax_st state; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci might_sleep(); 618c2ecf20Sopenharmony_ci d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); 628c2ecf20Sopenharmony_ci mutex_lock(&wimax_dev->mutex); 638c2ecf20Sopenharmony_ci dev_hold(wimax_dev->net_dev); 648c2ecf20Sopenharmony_ci state = wimax_dev->state; 658c2ecf20Sopenharmony_ci mutex_unlock(&wimax_dev->mutex); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (state >= WIMAX_ST_DOWN) { 688c2ecf20Sopenharmony_ci mutex_lock(&wimax_dev->mutex_reset); 698c2ecf20Sopenharmony_ci result = wimax_dev->op_reset(wimax_dev); 708c2ecf20Sopenharmony_ci mutex_unlock(&wimax_dev->mutex_reset); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci dev_put(wimax_dev->net_dev); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); 758c2ecf20Sopenharmony_ci return result; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(wimax_reset); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Exporting to user space over generic netlink 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * Parse the reset command from user space, return error code. 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * No attributes. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciint wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int result, ifindex; 908c2ecf20Sopenharmony_ci struct wimax_dev *wimax_dev; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); 938c2ecf20Sopenharmony_ci result = -ENODEV; 948c2ecf20Sopenharmony_ci if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) { 958c2ecf20Sopenharmony_ci pr_err("WIMAX_GNL_OP_RFKILL: can't find IFIDX attribute\n"); 968c2ecf20Sopenharmony_ci goto error_no_wimax_dev; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]); 998c2ecf20Sopenharmony_ci wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); 1008c2ecf20Sopenharmony_ci if (wimax_dev == NULL) 1018c2ecf20Sopenharmony_ci goto error_no_wimax_dev; 1028c2ecf20Sopenharmony_ci /* Execute the operation and send the result back to user space */ 1038c2ecf20Sopenharmony_ci result = wimax_reset(wimax_dev); 1048c2ecf20Sopenharmony_ci dev_put(wimax_dev->net_dev); 1058c2ecf20Sopenharmony_cierror_no_wimax_dev: 1068c2ecf20Sopenharmony_ci d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); 1078c2ecf20Sopenharmony_ci return result; 1088c2ecf20Sopenharmony_ci} 109