usnic_ib_sysfs.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
  3. *
  4. * This program is free software; you may redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; version 2 of the License.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  9. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  10. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  11. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  12. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  13. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  15. * SOFTWARE.
  16. *
  17. */
  18. #include <linux/module.h>
  19. #include <linux/init.h>
  20. #include <linux/errno.h>
  21. #include <rdma/ib_user_verbs.h>
  22. #include <rdma/ib_addr.h>
  23. #include "usnic_common_util.h"
  24. #include "usnic_ib.h"
  25. #include "usnic_ib_qp_grp.h"
  26. #include "usnic_vnic.h"
  27. #include "usnic_ib_verbs.h"
  28. #include "usnic_log.h"
  29. static ssize_t usnic_ib_show_fw_ver(struct device *device,
  30. struct device_attribute *attr,
  31. char *buf)
  32. {
  33. struct usnic_ib_dev *us_ibdev =
  34. container_of(device, struct usnic_ib_dev, ib_dev.dev);
  35. struct ethtool_drvinfo info;
  36. mutex_lock(&us_ibdev->usdev_lock);
  37. us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
  38. mutex_unlock(&us_ibdev->usdev_lock);
  39. return scnprintf(buf, PAGE_SIZE, "%s\n", info.fw_version);
  40. }
  41. static ssize_t usnic_ib_show_board(struct device *device,
  42. struct device_attribute *attr,
  43. char *buf)
  44. {
  45. struct usnic_ib_dev *us_ibdev =
  46. container_of(device, struct usnic_ib_dev, ib_dev.dev);
  47. unsigned short subsystem_device_id;
  48. mutex_lock(&us_ibdev->usdev_lock);
  49. subsystem_device_id = us_ibdev->pdev->subsystem_device;
  50. mutex_unlock(&us_ibdev->usdev_lock);
  51. return scnprintf(buf, PAGE_SIZE, "%hu\n", subsystem_device_id);
  52. }
  53. /*
  54. * Report the configuration for this PF
  55. */
  56. static ssize_t
  57. usnic_ib_show_config(struct device *device, struct device_attribute *attr,
  58. char *buf)
  59. {
  60. struct usnic_ib_dev *us_ibdev;
  61. char *ptr;
  62. unsigned left;
  63. unsigned n;
  64. enum usnic_vnic_res_type res_type;
  65. us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev);
  66. /* Buffer space limit is 1 page */
  67. ptr = buf;
  68. left = PAGE_SIZE;
  69. mutex_lock(&us_ibdev->usdev_lock);
  70. if (atomic_read(&us_ibdev->vf_cnt.refcount) > 0) {
  71. char *busname;
  72. /*
  73. * bus name seems to come with annoying prefix.
  74. * Remove it if it is predictable
  75. */
  76. busname = us_ibdev->pdev->bus->name;
  77. if (strncmp(busname, "PCI Bus ", 8) == 0)
  78. busname += 8;
  79. n = scnprintf(ptr, left,
  80. "%s: %s:%d.%d, %s, %pM, %u VFs\n Per VF:",
  81. us_ibdev->ib_dev.name,
  82. busname,
  83. PCI_SLOT(us_ibdev->pdev->devfn),
  84. PCI_FUNC(us_ibdev->pdev->devfn),
  85. netdev_name(us_ibdev->netdev),
  86. us_ibdev->ufdev->mac,
  87. atomic_read(&us_ibdev->vf_cnt.refcount));
  88. UPDATE_PTR_LEFT(n, ptr, left);
  89. for (res_type = USNIC_VNIC_RES_TYPE_EOL;
  90. res_type < USNIC_VNIC_RES_TYPE_MAX;
  91. res_type++) {
  92. if (us_ibdev->vf_res_cnt[res_type] == 0)
  93. continue;
  94. n = scnprintf(ptr, left, " %d %s%s",
  95. us_ibdev->vf_res_cnt[res_type],
  96. usnic_vnic_res_type_to_str(res_type),
  97. (res_type < (USNIC_VNIC_RES_TYPE_MAX - 1)) ?
  98. "," : "");
  99. UPDATE_PTR_LEFT(n, ptr, left);
  100. }
  101. n = scnprintf(ptr, left, "\n");
  102. UPDATE_PTR_LEFT(n, ptr, left);
  103. } else {
  104. n = scnprintf(ptr, left, "%s: no VFs\n",
  105. us_ibdev->ib_dev.name);
  106. UPDATE_PTR_LEFT(n, ptr, left);
  107. }
  108. mutex_unlock(&us_ibdev->usdev_lock);
  109. return ptr - buf;
  110. }
  111. static ssize_t
  112. usnic_ib_show_iface(struct device *device, struct device_attribute *attr,
  113. char *buf)
  114. {
  115. struct usnic_ib_dev *us_ibdev;
  116. us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev);
  117. return scnprintf(buf, PAGE_SIZE, "%s\n",
  118. netdev_name(us_ibdev->netdev));
  119. }
  120. static ssize_t
  121. usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr,
  122. char *buf)
  123. {
  124. struct usnic_ib_dev *us_ibdev;
  125. us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev);
  126. return scnprintf(buf, PAGE_SIZE, "%u\n",
  127. atomic_read(&us_ibdev->vf_cnt.refcount));
  128. }
  129. static ssize_t
  130. usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr,
  131. char *buf)
  132. {
  133. struct usnic_ib_dev *us_ibdev;
  134. int qp_per_vf;
  135. us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev);
  136. qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ],
  137. us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]);
  138. return scnprintf(buf, PAGE_SIZE,
  139. "%d\n", qp_per_vf);
  140. }
  141. static ssize_t
  142. usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr,
  143. char *buf)
  144. {
  145. struct usnic_ib_dev *us_ibdev;
  146. us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev);
  147. return scnprintf(buf, PAGE_SIZE, "%d\n",
  148. us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]);
  149. }
  150. static DEVICE_ATTR(fw_ver, S_IRUGO, usnic_ib_show_fw_ver, NULL);
  151. static DEVICE_ATTR(board_id, S_IRUGO, usnic_ib_show_board, NULL);
  152. static DEVICE_ATTR(config, S_IRUGO, usnic_ib_show_config, NULL);
  153. static DEVICE_ATTR(iface, S_IRUGO, usnic_ib_show_iface, NULL);
  154. static DEVICE_ATTR(max_vf, S_IRUGO, usnic_ib_show_max_vf, NULL);
  155. static DEVICE_ATTR(qp_per_vf, S_IRUGO, usnic_ib_show_qp_per_vf, NULL);
  156. static DEVICE_ATTR(cq_per_vf, S_IRUGO, usnic_ib_show_cq_per_vf, NULL);
  157. static struct device_attribute *usnic_class_attributes[] = {
  158. &dev_attr_fw_ver,
  159. &dev_attr_board_id,
  160. &dev_attr_config,
  161. &dev_attr_iface,
  162. &dev_attr_max_vf,
  163. &dev_attr_qp_per_vf,
  164. &dev_attr_cq_per_vf,
  165. };
  166. struct qpn_attribute {
  167. struct attribute attr;
  168. ssize_t (*show)(struct usnic_ib_qp_grp *, char *buf);
  169. };
  170. /*
  171. * Definitions for supporting QPN entries in sysfs
  172. */
  173. static ssize_t
  174. usnic_ib_qpn_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
  175. {
  176. struct usnic_ib_qp_grp *qp_grp;
  177. struct qpn_attribute *qpn_attr;
  178. qp_grp = container_of(kobj, struct usnic_ib_qp_grp, kobj);
  179. qpn_attr = container_of(attr, struct qpn_attribute, attr);
  180. return qpn_attr->show(qp_grp, buf);
  181. }
  182. static const struct sysfs_ops usnic_ib_qpn_sysfs_ops = {
  183. .show = usnic_ib_qpn_attr_show
  184. };
  185. #define QPN_ATTR_RO(NAME) \
  186. struct qpn_attribute qpn_attr_##NAME = __ATTR_RO(NAME)
  187. static ssize_t context_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
  188. {
  189. return scnprintf(buf, PAGE_SIZE, "0x%p\n", qp_grp->ctx);
  190. }
  191. static ssize_t summary_show(struct usnic_ib_qp_grp *qp_grp, char *buf)
  192. {
  193. int i, j, n;
  194. int left;
  195. char *ptr;
  196. struct usnic_vnic_res_chunk *res_chunk;
  197. struct usnic_vnic_res *vnic_res;
  198. left = PAGE_SIZE;
  199. ptr = buf;
  200. n = scnprintf(ptr, left,
  201. "QPN: %d State: (%s) PID: %u VF Idx: %hu ",
  202. qp_grp->ibqp.qp_num,
  203. usnic_ib_qp_grp_state_to_string(qp_grp->state),
  204. qp_grp->owner_pid,
  205. usnic_vnic_get_index(qp_grp->vf->vnic));
  206. UPDATE_PTR_LEFT(n, ptr, left);
  207. for (i = 0; qp_grp->res_chunk_list[i]; i++) {
  208. res_chunk = qp_grp->res_chunk_list[i];
  209. for (j = 0; j < res_chunk->cnt; j++) {
  210. vnic_res = res_chunk->res[j];
  211. n = scnprintf(ptr, left, "%s[%d] ",
  212. usnic_vnic_res_type_to_str(vnic_res->type),
  213. vnic_res->vnic_idx);
  214. UPDATE_PTR_LEFT(n, ptr, left);
  215. }
  216. }
  217. n = scnprintf(ptr, left, "\n");
  218. UPDATE_PTR_LEFT(n, ptr, left);
  219. return ptr - buf;
  220. }
  221. static QPN_ATTR_RO(context);
  222. static QPN_ATTR_RO(summary);
  223. static struct attribute *usnic_ib_qpn_default_attrs[] = {
  224. &qpn_attr_context.attr,
  225. &qpn_attr_summary.attr,
  226. NULL
  227. };
  228. static struct kobj_type usnic_ib_qpn_type = {
  229. .sysfs_ops = &usnic_ib_qpn_sysfs_ops,
  230. .default_attrs = usnic_ib_qpn_default_attrs
  231. };
  232. int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev)
  233. {
  234. int i;
  235. int err;
  236. for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) {
  237. err = device_create_file(&us_ibdev->ib_dev.dev,
  238. usnic_class_attributes[i]);
  239. if (err) {
  240. usnic_err("Failed to create device file %d for %s eith err %d",
  241. i, us_ibdev->ib_dev.name, err);
  242. return -EINVAL;
  243. }
  244. }
  245. /* create kernel object for looking at individual QPs */
  246. kobject_get(&us_ibdev->ib_dev.dev.kobj);
  247. us_ibdev->qpn_kobj = kobject_create_and_add("qpn",
  248. &us_ibdev->ib_dev.dev.kobj);
  249. if (us_ibdev->qpn_kobj == NULL) {
  250. kobject_put(&us_ibdev->ib_dev.dev.kobj);
  251. return -ENOMEM;
  252. }
  253. return 0;
  254. }
  255. void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev)
  256. {
  257. int i;
  258. for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) {
  259. device_remove_file(&us_ibdev->ib_dev.dev,
  260. usnic_class_attributes[i]);
  261. }
  262. kobject_put(us_ibdev->qpn_kobj);
  263. }
  264. void usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp)
  265. {
  266. struct usnic_ib_dev *us_ibdev;
  267. int err;
  268. us_ibdev = qp_grp->vf->pf;
  269. err = kobject_init_and_add(&qp_grp->kobj, &usnic_ib_qpn_type,
  270. kobject_get(us_ibdev->qpn_kobj),
  271. "%d", qp_grp->grp_id);
  272. if (err) {
  273. kobject_put(us_ibdev->qpn_kobj);
  274. return;
  275. }
  276. }
  277. void usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp)
  278. {
  279. struct usnic_ib_dev *us_ibdev;
  280. us_ibdev = qp_grp->vf->pf;
  281. kobject_put(&qp_grp->kobj);
  282. kobject_put(us_ibdev->qpn_kobj);
  283. }