op-reset.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 succesful 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
  86. struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = {
  87. [WIMAX_GNL_RESET_IFIDX] = {
  88. .type = NLA_U32,
  89. },
  90. };
  91. /*
  92. * Exporting to user space over generic netlink
  93. *
  94. * Parse the reset command from user space, return error code.
  95. *
  96. * No attributes.
  97. */
  98. static
  99. int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
  100. {
  101. int result, ifindex;
  102. struct wimax_dev *wimax_dev;
  103. struct device *dev;
  104. d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
  105. result = -ENODEV;
  106. if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) {
  107. printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
  108. "attribute\n");
  109. goto error_no_wimax_dev;
  110. }
  111. ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]);
  112. wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
  113. if (wimax_dev == NULL)
  114. goto error_no_wimax_dev;
  115. dev = wimax_dev_to_dev(wimax_dev);
  116. /* Execute the operation and send the result back to user space */
  117. result = wimax_reset(wimax_dev);
  118. dev_put(wimax_dev->net_dev);
  119. error_no_wimax_dev:
  120. d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
  121. return result;
  122. }
  123. struct genl_ops wimax_gnl_reset = {
  124. .cmd = WIMAX_GNL_OP_RESET,
  125. .flags = GENL_ADMIN_PERM,
  126. .policy = wimax_gnl_reset_policy,
  127. .doit = wimax_gnl_doit_reset,
  128. .dumpit = NULL,
  129. };