sysfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * WUSB Wire Adapter: WLP interface
  3. * Sysfs interfaces
  4. *
  5. * Copyright (C) 2005-2006 Intel Corporation
  6. * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License version
  10. * 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20. * 02110-1301, USA.
  21. *
  22. *
  23. * FIXME: docs
  24. */
  25. #include <linux/netdevice.h>
  26. #include <linux/etherdevice.h>
  27. #include <linux/uwb/debug.h>
  28. #include <linux/device.h>
  29. #include "i1480u-wlp.h"
  30. /**
  31. *
  32. * @dev: Class device from the net_device; assumed refcnted.
  33. *
  34. * Yes, I don't lock--we assume it is refcounted and I am getting a
  35. * single byte value that is kind of atomic to read.
  36. */
  37. ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf)
  38. {
  39. return sprintf(buf, "%u\n",
  40. wlp_tx_hdr_phy_rate(&options->def_tx_hdr));
  41. }
  42. EXPORT_SYMBOL_GPL(uwb_phy_rate_show);
  43. ssize_t uwb_phy_rate_store(struct wlp_options *options,
  44. const char *buf, size_t size)
  45. {
  46. ssize_t result;
  47. unsigned rate;
  48. result = sscanf(buf, "%u\n", &rate);
  49. if (result != 1) {
  50. result = -EINVAL;
  51. goto out;
  52. }
  53. result = -EINVAL;
  54. if (rate >= UWB_PHY_RATE_INVALID)
  55. goto out;
  56. wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate);
  57. result = 0;
  58. out:
  59. return result < 0 ? result : size;
  60. }
  61. EXPORT_SYMBOL_GPL(uwb_phy_rate_store);
  62. ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf)
  63. {
  64. return sprintf(buf, "%u\n",
  65. wlp_tx_hdr_rts_cts(&options->def_tx_hdr));
  66. }
  67. EXPORT_SYMBOL_GPL(uwb_rts_cts_show);
  68. ssize_t uwb_rts_cts_store(struct wlp_options *options,
  69. const char *buf, size_t size)
  70. {
  71. ssize_t result;
  72. unsigned value;
  73. result = sscanf(buf, "%u\n", &value);
  74. if (result != 1) {
  75. result = -EINVAL;
  76. goto out;
  77. }
  78. result = -EINVAL;
  79. wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value);
  80. result = 0;
  81. out:
  82. return result < 0 ? result : size;
  83. }
  84. EXPORT_SYMBOL_GPL(uwb_rts_cts_store);
  85. ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf)
  86. {
  87. return sprintf(buf, "%u\n",
  88. wlp_tx_hdr_ack_policy(&options->def_tx_hdr));
  89. }
  90. EXPORT_SYMBOL_GPL(uwb_ack_policy_show);
  91. ssize_t uwb_ack_policy_store(struct wlp_options *options,
  92. const char *buf, size_t size)
  93. {
  94. ssize_t result;
  95. unsigned value;
  96. result = sscanf(buf, "%u\n", &value);
  97. if (result != 1 || value > UWB_ACK_B_REQ) {
  98. result = -EINVAL;
  99. goto out;
  100. }
  101. wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value);
  102. result = 0;
  103. out:
  104. return result < 0 ? result : size;
  105. }
  106. EXPORT_SYMBOL_GPL(uwb_ack_policy_store);
  107. /**
  108. * Show the PCA base priority.
  109. *
  110. * We can access without locking, as the value is (for now) orthogonal
  111. * to other values.
  112. */
  113. ssize_t uwb_pca_base_priority_show(const struct wlp_options *options,
  114. char *buf)
  115. {
  116. return sprintf(buf, "%u\n",
  117. options->pca_base_priority);
  118. }
  119. EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show);
  120. /**
  121. * Set the PCA base priority.
  122. *
  123. * We can access without locking, as the value is (for now) orthogonal
  124. * to other values.
  125. */
  126. ssize_t uwb_pca_base_priority_store(struct wlp_options *options,
  127. const char *buf, size_t size)
  128. {
  129. ssize_t result = -EINVAL;
  130. u8 pca_base_priority;
  131. result = sscanf(buf, "%hhu\n", &pca_base_priority);
  132. if (result != 1) {
  133. result = -EINVAL;
  134. goto out;
  135. }
  136. result = -EINVAL;
  137. if (pca_base_priority >= 8)
  138. goto out;
  139. options->pca_base_priority = pca_base_priority;
  140. /* Update TX header if we are currently using PCA. */
  141. if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0)
  142. wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority);
  143. result = 0;
  144. out:
  145. return result < 0 ? result : size;
  146. }
  147. EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store);
  148. /**
  149. * Show current inflight values
  150. *
  151. * Will print the current MAX and THRESHOLD values for the basic flow
  152. * control. In addition it will report how many times the TX queue needed
  153. * to be restarted since the last time this query was made.
  154. */
  155. static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight,
  156. char *buf)
  157. {
  158. ssize_t result;
  159. unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ;
  160. unsigned long restart_count = atomic_read(&inflight->restart_count);
  161. result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n"
  162. "#read: threshold max inflight_count restarts "
  163. "seconds restarts/sec\n"
  164. "#write: threshold max\n",
  165. inflight->threshold, inflight->max,
  166. atomic_read(&inflight->count),
  167. restart_count, sec_elapsed,
  168. sec_elapsed == 0 ? 0 : restart_count/sec_elapsed);
  169. inflight->restart_ts = jiffies;
  170. atomic_set(&inflight->restart_count, 0);
  171. return result;
  172. }
  173. static
  174. ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight,
  175. const char *buf, size_t size)
  176. {
  177. unsigned long in_threshold, in_max;
  178. ssize_t result;
  179. result = sscanf(buf, "%lu %lu", &in_threshold, &in_max);
  180. if (result != 2)
  181. return -EINVAL;
  182. if (in_max <= in_threshold)
  183. return -EINVAL;
  184. inflight->max = in_max;
  185. inflight->threshold = in_threshold;
  186. return size;
  187. }
  188. /*
  189. * Glue (or function adaptors) for accesing info on sysfs
  190. *
  191. * [we need this indirection because the PCI driver does almost the
  192. * same]
  193. *
  194. * Linux 2.6.21 changed how 'struct netdevice' does attributes (from
  195. * having a 'struct class_dev' to having a 'struct device'). That is
  196. * quite of a pain.
  197. *
  198. * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE()
  199. * create adaptors for extracting the 'struct i1480u' from a 'struct
  200. * dev' and calling a function for doing a sysfs operation (as we have
  201. * them factorized already). i1480u_ATTR creates the attribute file
  202. * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a
  203. * class_device_attr_NAME or device_attr_NAME (for group registration).
  204. */
  205. #include <linux/version.h>
  206. #define i1480u_SHOW(name, fn, param) \
  207. static ssize_t i1480u_show_##name(struct device *dev, \
  208. struct device_attribute *attr,\
  209. char *buf) \
  210. { \
  211. struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
  212. return fn(&i1480u->param, buf); \
  213. }
  214. #define i1480u_STORE(name, fn, param) \
  215. static ssize_t i1480u_store_##name(struct device *dev, \
  216. struct device_attribute *attr,\
  217. const char *buf, size_t size)\
  218. { \
  219. struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \
  220. return fn(&i1480u->param, buf, size); \
  221. }
  222. #define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \
  223. i1480u_show_##name,\
  224. i1480u_store_##name)
  225. #define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \
  226. S_IRUGO, \
  227. i1480u_show_##name, NULL)
  228. #define i1480u_ATTR_NAME(a) (dev_attr_##a)
  229. /*
  230. * Sysfs adaptors
  231. */
  232. i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options);
  233. i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options);
  234. i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR);
  235. i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options);
  236. i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options);
  237. i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR);
  238. i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options);
  239. i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options);
  240. i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR);
  241. i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options);
  242. i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options);
  243. i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR);
  244. i1480u_SHOW(wlp_eda, wlp_eda_show, wlp);
  245. i1480u_STORE(wlp_eda, wlp_eda_store, wlp);
  246. i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR);
  247. i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp);
  248. i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp);
  249. i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR);
  250. i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp);
  251. i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp);
  252. i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR);
  253. i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp);
  254. i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp);
  255. i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR);
  256. i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp);
  257. i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp);
  258. i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR);
  259. i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp);
  260. i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp);
  261. i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR);
  262. i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp);
  263. i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp);
  264. i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR);
  265. i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp);
  266. i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp);
  267. i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR);
  268. i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp);
  269. i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp);
  270. i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR);
  271. i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp);
  272. i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp);
  273. i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR);
  274. i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp);
  275. i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp);
  276. i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR);
  277. i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp);
  278. i1480u_ATTR_SHOW(wlp_neighborhood);
  279. i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss);
  280. i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss);
  281. i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR);
  282. /*
  283. * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over
  284. * the last 256 received WLP frames (ECMA-368 13.3).
  285. *
  286. * [the -7dB that have to be substracted from the LQI to make the LQE
  287. * are already taken into account].
  288. */
  289. i1480u_SHOW(wlp_lqe, stats_show, lqe_stats);
  290. i1480u_STORE(wlp_lqe, stats_store, lqe_stats);
  291. i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR);
  292. /*
  293. * Show the Receive Signal Strength Indicator averaged over all the
  294. * received WLP frames (ECMA-368 13.3). Still is not clear what
  295. * this value is, but is kind of a percentage of the signal strength
  296. * at the antenna.
  297. */
  298. i1480u_SHOW(wlp_rssi, stats_show, rssi_stats);
  299. i1480u_STORE(wlp_rssi, stats_store, rssi_stats);
  300. i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR);
  301. /**
  302. * We maintain a basic flow control counter. "count" how many TX URBs are
  303. * outstanding. Only allow "max"
  304. * TX URBs to be outstanding. If this value is reached the queue will be
  305. * stopped. The queue will be restarted when there are
  306. * "threshold" URBs outstanding.
  307. */
  308. i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight);
  309. i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight);
  310. i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR);
  311. static struct attribute *i1480u_attrs[] = {
  312. &i1480u_ATTR_NAME(uwb_phy_rate).attr,
  313. &i1480u_ATTR_NAME(uwb_rts_cts).attr,
  314. &i1480u_ATTR_NAME(uwb_ack_policy).attr,
  315. &i1480u_ATTR_NAME(uwb_pca_base_priority).attr,
  316. &i1480u_ATTR_NAME(wlp_lqe).attr,
  317. &i1480u_ATTR_NAME(wlp_rssi).attr,
  318. &i1480u_ATTR_NAME(wlp_eda).attr,
  319. &i1480u_ATTR_NAME(wlp_uuid).attr,
  320. &i1480u_ATTR_NAME(wlp_dev_name).attr,
  321. &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr,
  322. &i1480u_ATTR_NAME(wlp_dev_model_name).attr,
  323. &i1480u_ATTR_NAME(wlp_dev_model_nr).attr,
  324. &i1480u_ATTR_NAME(wlp_dev_serial).attr,
  325. &i1480u_ATTR_NAME(wlp_dev_prim_category).attr,
  326. &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr,
  327. &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr,
  328. &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr,
  329. &i1480u_ATTR_NAME(wlp_neighborhood).attr,
  330. &i1480u_ATTR_NAME(wss_activate).attr,
  331. &i1480u_ATTR_NAME(wlp_tx_inflight).attr,
  332. NULL,
  333. };
  334. static struct attribute_group i1480u_attr_group = {
  335. .name = NULL, /* we want them in the same directory */
  336. .attrs = i1480u_attrs,
  337. };
  338. int i1480u_sysfs_setup(struct i1480u *i1480u)
  339. {
  340. int result;
  341. struct device *dev = &i1480u->usb_iface->dev;
  342. result = sysfs_create_group(&i1480u->net_dev->dev.kobj,
  343. &i1480u_attr_group);
  344. if (result < 0)
  345. dev_err(dev, "cannot initialize sysfs attributes: %d\n",
  346. result);
  347. return result;
  348. }
  349. void i1480u_sysfs_release(struct i1480u *i1480u)
  350. {
  351. sysfs_remove_group(&i1480u->net_dev->dev.kobj,
  352. &i1480u_attr_group);
  353. }