usnic_vnic.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
  3. *
  4. * This software is available to you under a choice of one of two
  5. * licenses. You may choose to be licensed under the terms of the GNU
  6. * General Public License (GPL) Version 2, available from the file
  7. * COPYING in the main directory of this source tree, or the
  8. * BSD license below:
  9. *
  10. * Redistribution and use in source and binary forms, with or
  11. * without modification, are permitted provided that the following
  12. * conditions are met:
  13. *
  14. * - Redistributions of source code must retain the above
  15. * copyright notice, this list of conditions and the following
  16. * disclaimer.
  17. *
  18. * - Redistributions in binary form must reproduce the above
  19. * copyright notice, this list of conditions and the following
  20. * disclaimer in the documentation and/or other materials
  21. * provided with the distribution.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30. * SOFTWARE.
  31. *
  32. */
  33. #include <linux/errno.h>
  34. #include <linux/pci.h>
  35. #include "usnic_ib.h"
  36. #include "vnic_resource.h"
  37. #include "usnic_log.h"
  38. #include "usnic_vnic.h"
  39. struct usnic_vnic {
  40. struct vnic_dev *vdev;
  41. struct vnic_dev_bar bar[PCI_NUM_RESOURCES];
  42. struct usnic_vnic_res_chunk chunks[USNIC_VNIC_RES_TYPE_MAX];
  43. spinlock_t res_lock;
  44. };
  45. static enum vnic_res_type _to_vnic_res_type(enum usnic_vnic_res_type res_type)
  46. {
  47. #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
  48. vnic_res_type,
  49. #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
  50. vnic_res_type,
  51. static enum vnic_res_type usnic_vnic_type_2_vnic_type[] = {
  52. USNIC_VNIC_RES_TYPES};
  53. #undef DEFINE_USNIC_VNIC_RES
  54. #undef DEFINE_USNIC_VNIC_RES_AT
  55. if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
  56. return RES_TYPE_MAX;
  57. return usnic_vnic_type_2_vnic_type[res_type];
  58. }
  59. const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type)
  60. {
  61. #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
  62. desc,
  63. #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
  64. desc,
  65. static const char * const usnic_vnic_res_type_desc[] = {
  66. USNIC_VNIC_RES_TYPES};
  67. #undef DEFINE_USNIC_VNIC_RES
  68. #undef DEFINE_USNIC_VNIC_RES_AT
  69. if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
  70. return "unknown";
  71. return usnic_vnic_res_type_desc[res_type];
  72. }
  73. const char *usnic_vnic_pci_name(struct usnic_vnic *vnic)
  74. {
  75. return pci_name(usnic_vnic_get_pdev(vnic));
  76. }
  77. int usnic_vnic_dump(struct usnic_vnic *vnic, char *buf,
  78. int buf_sz,
  79. void *hdr_obj,
  80. int (*printtitle)(void *, char*, int),
  81. int (*printcols)(char *, int),
  82. int (*printrow)(void *, char *, int))
  83. {
  84. struct usnic_vnic_res_chunk *chunk;
  85. struct usnic_vnic_res *res;
  86. struct vnic_dev_bar *bar0;
  87. int i, j, offset;
  88. offset = 0;
  89. bar0 = usnic_vnic_get_bar(vnic, 0);
  90. offset += scnprintf(buf + offset, buf_sz - offset,
  91. "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
  92. usnic_vnic_get_index(vnic),
  93. &bar0->bus_addr,
  94. bar0->vaddr, bar0->len);
  95. if (printtitle)
  96. offset += printtitle(hdr_obj, buf + offset, buf_sz - offset);
  97. offset += scnprintf(buf + offset, buf_sz - offset, "\n");
  98. offset += scnprintf(buf + offset, buf_sz - offset,
  99. "|RES\t|CTRL_PIN\t\t|IN_USE\t");
  100. if (printcols)
  101. offset += printcols(buf + offset, buf_sz - offset);
  102. offset += scnprintf(buf + offset, buf_sz - offset, "\n");
  103. spin_lock(&vnic->res_lock);
  104. for (i = 0; i < ARRAY_SIZE(vnic->chunks); i++) {
  105. chunk = &vnic->chunks[i];
  106. for (j = 0; j < chunk->cnt; j++) {
  107. res = chunk->res[j];
  108. offset += scnprintf(buf + offset, buf_sz - offset,
  109. "|%s[%u]\t|0x%p\t|%u\t",
  110. usnic_vnic_res_type_to_str(res->type),
  111. res->vnic_idx, res->ctrl, !!res->owner);
  112. if (printrow) {
  113. offset += printrow(res->owner, buf + offset,
  114. buf_sz - offset);
  115. }
  116. offset += scnprintf(buf + offset, buf_sz - offset,
  117. "\n");
  118. }
  119. }
  120. spin_unlock(&vnic->res_lock);
  121. return offset;
  122. }
  123. void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec *spec,
  124. enum usnic_vnic_res_type trgt_type,
  125. u16 cnt)
  126. {
  127. int i;
  128. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  129. if (spec->resources[i].type == trgt_type) {
  130. spec->resources[i].cnt = cnt;
  131. return;
  132. }
  133. }
  134. WARN_ON(1);
  135. }
  136. int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec *min_spec,
  137. struct usnic_vnic_res_spec *res_spec)
  138. {
  139. int found, i, j;
  140. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  141. found = 0;
  142. for (j = 0; j < USNIC_VNIC_RES_TYPE_MAX; j++) {
  143. if (res_spec->resources[i].type !=
  144. min_spec->resources[i].type)
  145. continue;
  146. found = 1;
  147. if (min_spec->resources[i].cnt >
  148. res_spec->resources[i].cnt)
  149. return -EINVAL;
  150. break;
  151. }
  152. if (!found)
  153. return -EINVAL;
  154. }
  155. return 0;
  156. }
  157. int usnic_vnic_spec_dump(char *buf, int buf_sz,
  158. struct usnic_vnic_res_spec *res_spec)
  159. {
  160. enum usnic_vnic_res_type res_type;
  161. int res_cnt;
  162. int i;
  163. int offset = 0;
  164. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  165. res_type = res_spec->resources[i].type;
  166. res_cnt = res_spec->resources[i].cnt;
  167. offset += scnprintf(buf + offset, buf_sz - offset,
  168. "Res: %s Cnt: %d ",
  169. usnic_vnic_res_type_to_str(res_type),
  170. res_cnt);
  171. }
  172. return offset;
  173. }
  174. int usnic_vnic_check_room(struct usnic_vnic *vnic,
  175. struct usnic_vnic_res_spec *res_spec)
  176. {
  177. int i;
  178. enum usnic_vnic_res_type res_type;
  179. int res_cnt;
  180. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  181. res_type = res_spec->resources[i].type;
  182. res_cnt = res_spec->resources[i].cnt;
  183. if (res_type == USNIC_VNIC_RES_TYPE_EOL)
  184. break;
  185. if (res_cnt > usnic_vnic_res_free_cnt(vnic, res_type))
  186. return -EBUSY;
  187. }
  188. return 0;
  189. }
  190. int usnic_vnic_res_cnt(struct usnic_vnic *vnic,
  191. enum usnic_vnic_res_type type)
  192. {
  193. return vnic->chunks[type].cnt;
  194. }
  195. int usnic_vnic_res_free_cnt(struct usnic_vnic *vnic,
  196. enum usnic_vnic_res_type type)
  197. {
  198. return vnic->chunks[type].free_cnt;
  199. }
  200. struct usnic_vnic_res_chunk *
  201. usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type,
  202. int cnt, void *owner)
  203. {
  204. struct usnic_vnic_res_chunk *src, *ret;
  205. struct usnic_vnic_res *res;
  206. int i;
  207. if (usnic_vnic_res_free_cnt(vnic, type) < cnt || cnt < 0 || !owner)
  208. return ERR_PTR(-EINVAL);
  209. ret = kzalloc(sizeof(*ret), GFP_ATOMIC);
  210. if (!ret)
  211. return ERR_PTR(-ENOMEM);
  212. if (cnt > 0) {
  213. ret->res = kcalloc(cnt, sizeof(*(ret->res)), GFP_ATOMIC);
  214. if (!ret->res) {
  215. kfree(ret);
  216. return ERR_PTR(-ENOMEM);
  217. }
  218. spin_lock(&vnic->res_lock);
  219. src = &vnic->chunks[type];
  220. for (i = 0; i < src->cnt && ret->cnt < cnt; i++) {
  221. res = src->res[i];
  222. if (!res->owner) {
  223. src->free_cnt--;
  224. res->owner = owner;
  225. ret->res[ret->cnt++] = res;
  226. }
  227. }
  228. spin_unlock(&vnic->res_lock);
  229. }
  230. ret->type = type;
  231. ret->vnic = vnic;
  232. WARN_ON(ret->cnt != cnt);
  233. return ret;
  234. }
  235. void usnic_vnic_put_resources(struct usnic_vnic_res_chunk *chunk)
  236. {
  237. struct usnic_vnic_res *res;
  238. int i;
  239. struct usnic_vnic *vnic = chunk->vnic;
  240. if (chunk->cnt > 0) {
  241. spin_lock(&vnic->res_lock);
  242. while ((i = --chunk->cnt) >= 0) {
  243. res = chunk->res[i];
  244. chunk->res[i] = NULL;
  245. res->owner = NULL;
  246. vnic->chunks[res->type].free_cnt++;
  247. }
  248. spin_unlock(&vnic->res_lock);
  249. }
  250. kfree(chunk->res);
  251. kfree(chunk);
  252. }
  253. u16 usnic_vnic_get_index(struct usnic_vnic *vnic)
  254. {
  255. return usnic_vnic_get_pdev(vnic)->devfn - 1;
  256. }
  257. static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic,
  258. enum usnic_vnic_res_type type,
  259. struct usnic_vnic_res_chunk *chunk)
  260. {
  261. int cnt, err, i;
  262. struct usnic_vnic_res *res;
  263. cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type));
  264. if (cnt < 1) {
  265. usnic_err("Wrong res count with cnt %d\n", cnt);
  266. return -EINVAL;
  267. }
  268. chunk->cnt = chunk->free_cnt = cnt;
  269. chunk->res = kcalloc(cnt, sizeof(*(chunk->res)), GFP_KERNEL);
  270. if (!chunk->res)
  271. return -ENOMEM;
  272. for (i = 0; i < cnt; i++) {
  273. res = kzalloc(sizeof(*res), GFP_KERNEL);
  274. if (!res) {
  275. err = -ENOMEM;
  276. goto fail;
  277. }
  278. res->type = type;
  279. res->vnic_idx = i;
  280. res->vnic = vnic;
  281. res->ctrl = vnic_dev_get_res(vnic->vdev,
  282. _to_vnic_res_type(type), i);
  283. chunk->res[i] = res;
  284. }
  285. chunk->vnic = vnic;
  286. return 0;
  287. fail:
  288. for (i--; i >= 0; i--)
  289. kfree(chunk->res[i]);
  290. kfree(chunk->res);
  291. return err;
  292. }
  293. static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk *chunk)
  294. {
  295. int i;
  296. for (i = 0; i < chunk->cnt; i++)
  297. kfree(chunk->res[i]);
  298. kfree(chunk->res);
  299. }
  300. static int usnic_vnic_discover_resources(struct pci_dev *pdev,
  301. struct usnic_vnic *vnic)
  302. {
  303. enum usnic_vnic_res_type res_type;
  304. int i;
  305. int err = 0;
  306. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  307. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  308. continue;
  309. vnic->bar[i].len = pci_resource_len(pdev, i);
  310. vnic->bar[i].vaddr = pci_iomap(pdev, i, vnic->bar[i].len);
  311. if (!vnic->bar[i].vaddr) {
  312. usnic_err("Cannot memory-map BAR %d, aborting\n",
  313. i);
  314. err = -ENODEV;
  315. goto out_clean_bar;
  316. }
  317. vnic->bar[i].bus_addr = pci_resource_start(pdev, i);
  318. }
  319. vnic->vdev = vnic_dev_register(NULL, pdev, pdev, vnic->bar,
  320. ARRAY_SIZE(vnic->bar));
  321. if (!vnic->vdev) {
  322. usnic_err("Failed to register device %s\n",
  323. pci_name(pdev));
  324. err = -EINVAL;
  325. goto out_clean_bar;
  326. }
  327. for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
  328. res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) {
  329. err = usnic_vnic_alloc_res_chunk(vnic, res_type,
  330. &vnic->chunks[res_type]);
  331. if (err)
  332. goto out_clean_chunks;
  333. }
  334. return 0;
  335. out_clean_chunks:
  336. for (res_type--; res_type > USNIC_VNIC_RES_TYPE_EOL; res_type--)
  337. usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
  338. vnic_dev_unregister(vnic->vdev);
  339. out_clean_bar:
  340. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  341. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  342. continue;
  343. if (!vnic->bar[i].vaddr)
  344. break;
  345. iounmap(vnic->bar[i].vaddr);
  346. }
  347. return err;
  348. }
  349. struct pci_dev *usnic_vnic_get_pdev(struct usnic_vnic *vnic)
  350. {
  351. return vnic_dev_get_pdev(vnic->vdev);
  352. }
  353. struct vnic_dev_bar *usnic_vnic_get_bar(struct usnic_vnic *vnic,
  354. int bar_num)
  355. {
  356. return (bar_num < ARRAY_SIZE(vnic->bar)) ? &vnic->bar[bar_num] : NULL;
  357. }
  358. static void usnic_vnic_release_resources(struct usnic_vnic *vnic)
  359. {
  360. int i;
  361. struct pci_dev *pdev;
  362. enum usnic_vnic_res_type res_type;
  363. pdev = usnic_vnic_get_pdev(vnic);
  364. for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
  365. res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++)
  366. usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
  367. vnic_dev_unregister(vnic->vdev);
  368. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  369. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  370. continue;
  371. iounmap(vnic->bar[i].vaddr);
  372. }
  373. }
  374. struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev)
  375. {
  376. struct usnic_vnic *vnic;
  377. int err = 0;
  378. if (!pci_is_enabled(pdev)) {
  379. usnic_err("PCI dev %s is disabled\n", pci_name(pdev));
  380. return ERR_PTR(-EINVAL);
  381. }
  382. vnic = kzalloc(sizeof(*vnic), GFP_KERNEL);
  383. if (!vnic)
  384. return ERR_PTR(-ENOMEM);
  385. spin_lock_init(&vnic->res_lock);
  386. err = usnic_vnic_discover_resources(pdev, vnic);
  387. if (err) {
  388. usnic_err("Failed to discover %s resources with err %d\n",
  389. pci_name(pdev), err);
  390. goto out_free_vnic;
  391. }
  392. usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic));
  393. return vnic;
  394. out_free_vnic:
  395. kfree(vnic);
  396. return ERR_PTR(err);
  397. }
  398. void usnic_vnic_free(struct usnic_vnic *vnic)
  399. {
  400. usnic_vnic_release_resources(vnic);
  401. kfree(vnic);
  402. }