op-reset.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. #include <net/wimax.h>
  31. #include <net/genetlink.h>
  32. #include <linux/wimax.h>
  33. #include <linux/security.h>
  34. #include "wimax-internal.h"
  35. #define D_SUBMODULE op_reset
  36. #include "debug-levels.h"
  37. /**
  38. * wimax_reset - Reset a WiMAX device
  39. *
  40. * @wimax_dev: WiMAX device descriptor
  41. *
  42. * Returns:
  43. *
  44. * %0 if ok and a warm reset was done (the device still exists in
  45. * the system).
  46. *
  47. * -%ENODEV if a cold/bus reset had to be done (device has
  48. * disconnected and reconnected, so current handle is not valid
  49. * any more).
  50. *
  51. * -%EINVAL if the device is not even registered.
  52. *
  53. * Any other negative error code shall be considered as
  54. * non-recoverable.
  55. *
  56. * Description:
  57. *
  58. * Called when wanting to reset the device for any reason. Device is
  59. * taken back to power on status.
  60. *
  61. * This call blocks; on successful return, the device has completed the
  62. * reset process and is ready to operate.
  63. */
  64. int wimax_reset(struct wimax_dev *wimax_dev)
  65. {
  66. int result = -EINVAL;
  67. struct device *dev = wimax_dev_to_dev(wimax_dev);
  68. enum wimax_st state;
  69. might_sleep();
  70. d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
  71. mutex_lock(&wimax_dev->mutex);
  72. dev_hold(wimax_dev->net_dev);
  73. state = wimax_dev->state;
  74. mutex_unlock(&wimax_dev->mutex);
  75. if (state >= WIMAX_ST_DOWN) {
  76. mutex_lock(&wimax_dev->mutex_reset);
  77. result = wimax_dev->op_reset(wimax_dev);
  78. mutex_unlock(&wimax_dev->mutex_reset);
  79. }
  80. dev_put(wimax_dev->net_dev);
  81. d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
  82. return result;
  83. }
  84. EXPORT_SYMBOL(wimax_reset);
  85. static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = {
  86. [WIMAX_GNL_RESET_IFIDX] = {
  87. .type = NLA_U32,
  88. },
  89. };
  90. /*
  91. * Exporting to user space over generic netlink
  92. *
  93. * Parse the reset command from user space, return error code.
  94. *
  95. * No attributes.
  96. */
  97. static
  98. int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
  99. {
  100. int result, ifindex;
  101. struct wimax_dev *wimax_dev;
  102. d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
  103. result = -ENODEV;
  104. if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) {
  105. printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
  106. "attribute\n");
  107. goto error_no_wimax_dev;
  108. }
  109. ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]);
  110. wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
  111. if (wimax_dev == NULL)
  112. goto error_no_wimax_dev;
  113. /* Execute the operation and send the result back to user space */
  114. result = wimax_reset(wimax_dev);
  115. dev_put(wimax_dev->net_dev);
  116. error_no_wimax_dev:
  117. d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
  118. return result;
  119. }
  120. struct genl_ops wimax_gnl_reset = {
  121. .cmd = WIMAX_GNL_OP_RESET,
  122. .flags = GENL_ADMIN_PERM,
  123. .policy = wimax_gnl_reset_policy,
  124. .doit = wimax_gnl_doit_reset,
  125. .dumpit = NULL,
  126. };