usnic_vnic.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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/errno.h>
  19. #include <linux/module.h>
  20. #include <linux/pci.h>
  21. #include "usnic_ib.h"
  22. #include "vnic_resource.h"
  23. #include "usnic_log.h"
  24. #include "usnic_vnic.h"
  25. struct usnic_vnic {
  26. struct vnic_dev *vdev;
  27. struct vnic_dev_bar bar[PCI_NUM_RESOURCES];
  28. struct usnic_vnic_res_chunk chunks[USNIC_VNIC_RES_TYPE_MAX];
  29. spinlock_t res_lock;
  30. };
  31. static enum vnic_res_type _to_vnic_res_type(enum usnic_vnic_res_type res_type)
  32. {
  33. #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
  34. vnic_res_type,
  35. #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
  36. vnic_res_type,
  37. static enum vnic_res_type usnic_vnic_type_2_vnic_type[] = {
  38. USNIC_VNIC_RES_TYPES};
  39. #undef DEFINE_USNIC_VNIC_RES
  40. #undef DEFINE_USNIC_VNIC_RES_AT
  41. if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
  42. return RES_TYPE_MAX;
  43. return usnic_vnic_type_2_vnic_type[res_type];
  44. }
  45. const char *usnic_vnic_res_type_to_str(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. desc,
  49. #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
  50. desc,
  51. static const char * const usnic_vnic_res_type_desc[] = {
  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 "unknown";
  57. return usnic_vnic_res_type_desc[res_type];
  58. }
  59. const char *usnic_vnic_pci_name(struct usnic_vnic *vnic)
  60. {
  61. return pci_name(usnic_vnic_get_pdev(vnic));
  62. }
  63. int usnic_vnic_dump(struct usnic_vnic *vnic, char *buf,
  64. int buf_sz,
  65. void *hdr_obj,
  66. int (*printtitle)(void *, char*, int),
  67. int (*printcols)(char *, int),
  68. int (*printrow)(void *, char *, int))
  69. {
  70. struct usnic_vnic_res_chunk *chunk;
  71. struct usnic_vnic_res *res;
  72. struct vnic_dev_bar *bar0;
  73. int i, j, offset;
  74. offset = 0;
  75. bar0 = usnic_vnic_get_bar(vnic, 0);
  76. offset += scnprintf(buf + offset, buf_sz - offset,
  77. "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
  78. usnic_vnic_get_index(vnic),
  79. &bar0->bus_addr,
  80. bar0->vaddr, bar0->len);
  81. if (printtitle)
  82. offset += printtitle(hdr_obj, buf + offset, buf_sz - offset);
  83. offset += scnprintf(buf + offset, buf_sz - offset, "\n");
  84. offset += scnprintf(buf + offset, buf_sz - offset,
  85. "|RES\t|CTRL_PIN\t\t|IN_USE\t");
  86. if (printcols)
  87. offset += printcols(buf + offset, buf_sz - offset);
  88. offset += scnprintf(buf + offset, buf_sz - offset, "\n");
  89. spin_lock(&vnic->res_lock);
  90. for (i = 0; i < ARRAY_SIZE(vnic->chunks); i++) {
  91. chunk = &vnic->chunks[i];
  92. for (j = 0; j < chunk->cnt; j++) {
  93. res = chunk->res[j];
  94. offset += scnprintf(buf + offset, buf_sz - offset,
  95. "|%s[%u]\t|0x%p\t|%u\t",
  96. usnic_vnic_res_type_to_str(res->type),
  97. res->vnic_idx, res->ctrl, !!res->owner);
  98. if (printrow) {
  99. offset += printrow(res->owner, buf + offset,
  100. buf_sz - offset);
  101. }
  102. offset += scnprintf(buf + offset, buf_sz - offset,
  103. "\n");
  104. }
  105. }
  106. spin_unlock(&vnic->res_lock);
  107. return offset;
  108. }
  109. void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec *spec,
  110. enum usnic_vnic_res_type trgt_type,
  111. u16 cnt)
  112. {
  113. int i;
  114. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  115. if (spec->resources[i].type == trgt_type) {
  116. spec->resources[i].cnt = cnt;
  117. return;
  118. }
  119. }
  120. WARN_ON(1);
  121. }
  122. int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec *min_spec,
  123. struct usnic_vnic_res_spec *res_spec)
  124. {
  125. int found, i, j;
  126. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  127. found = 0;
  128. for (j = 0; j < USNIC_VNIC_RES_TYPE_MAX; j++) {
  129. if (res_spec->resources[i].type !=
  130. min_spec->resources[i].type)
  131. continue;
  132. found = 1;
  133. if (min_spec->resources[i].cnt >
  134. res_spec->resources[i].cnt)
  135. return -EINVAL;
  136. break;
  137. }
  138. if (!found)
  139. return -EINVAL;
  140. }
  141. return 0;
  142. }
  143. int usnic_vnic_spec_dump(char *buf, int buf_sz,
  144. struct usnic_vnic_res_spec *res_spec)
  145. {
  146. enum usnic_vnic_res_type res_type;
  147. int res_cnt;
  148. int i;
  149. int offset = 0;
  150. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  151. res_type = res_spec->resources[i].type;
  152. res_cnt = res_spec->resources[i].cnt;
  153. offset += scnprintf(buf + offset, buf_sz - offset,
  154. "Res: %s Cnt: %d ",
  155. usnic_vnic_res_type_to_str(res_type),
  156. res_cnt);
  157. }
  158. return offset;
  159. }
  160. int usnic_vnic_check_room(struct usnic_vnic *vnic,
  161. struct usnic_vnic_res_spec *res_spec)
  162. {
  163. int i;
  164. enum usnic_vnic_res_type res_type;
  165. int res_cnt;
  166. for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
  167. res_type = res_spec->resources[i].type;
  168. res_cnt = res_spec->resources[i].cnt;
  169. if (res_type == USNIC_VNIC_RES_TYPE_EOL)
  170. break;
  171. if (res_cnt > usnic_vnic_res_free_cnt(vnic, res_type))
  172. return -EBUSY;
  173. }
  174. return 0;
  175. }
  176. int usnic_vnic_res_cnt(struct usnic_vnic *vnic,
  177. enum usnic_vnic_res_type type)
  178. {
  179. return vnic->chunks[type].cnt;
  180. }
  181. int usnic_vnic_res_free_cnt(struct usnic_vnic *vnic,
  182. enum usnic_vnic_res_type type)
  183. {
  184. return vnic->chunks[type].free_cnt;
  185. }
  186. struct usnic_vnic_res_chunk *
  187. usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type,
  188. int cnt, void *owner)
  189. {
  190. struct usnic_vnic_res_chunk *src, *ret;
  191. struct usnic_vnic_res *res;
  192. int i;
  193. if (usnic_vnic_res_free_cnt(vnic, type) < cnt || cnt < 1 || !owner)
  194. return ERR_PTR(-EINVAL);
  195. ret = kzalloc(sizeof(*ret), GFP_ATOMIC);
  196. if (!ret) {
  197. usnic_err("Failed to allocate chunk for %s - Out of memory\n",
  198. usnic_vnic_pci_name(vnic));
  199. return ERR_PTR(-ENOMEM);
  200. }
  201. ret->res = kzalloc(sizeof(*(ret->res))*cnt, GFP_ATOMIC);
  202. if (!ret->res) {
  203. usnic_err("Failed to allocate resources for %s. Out of memory\n",
  204. usnic_vnic_pci_name(vnic));
  205. kfree(ret);
  206. return ERR_PTR(-ENOMEM);
  207. }
  208. spin_lock(&vnic->res_lock);
  209. src = &vnic->chunks[type];
  210. for (i = 0; i < src->cnt && ret->cnt < cnt; i++) {
  211. res = src->res[i];
  212. if (!res->owner) {
  213. src->free_cnt--;
  214. res->owner = owner;
  215. ret->res[ret->cnt++] = res;
  216. }
  217. }
  218. spin_unlock(&vnic->res_lock);
  219. ret->type = type;
  220. ret->vnic = vnic;
  221. WARN_ON(ret->cnt != cnt);
  222. return ret;
  223. }
  224. void usnic_vnic_put_resources(struct usnic_vnic_res_chunk *chunk)
  225. {
  226. struct usnic_vnic_res *res;
  227. int i;
  228. struct usnic_vnic *vnic = chunk->vnic;
  229. spin_lock(&vnic->res_lock);
  230. while ((i = --chunk->cnt) >= 0) {
  231. res = chunk->res[i];
  232. chunk->res[i] = NULL;
  233. res->owner = NULL;
  234. vnic->chunks[res->type].free_cnt++;
  235. }
  236. spin_unlock(&vnic->res_lock);
  237. kfree(chunk->res);
  238. kfree(chunk);
  239. }
  240. u16 usnic_vnic_get_index(struct usnic_vnic *vnic)
  241. {
  242. return usnic_vnic_get_pdev(vnic)->devfn - 1;
  243. }
  244. static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic,
  245. enum usnic_vnic_res_type type,
  246. struct usnic_vnic_res_chunk *chunk)
  247. {
  248. int cnt, err, i;
  249. struct usnic_vnic_res *res;
  250. cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type));
  251. if (cnt < 1)
  252. return -EINVAL;
  253. chunk->cnt = chunk->free_cnt = cnt;
  254. chunk->res = kzalloc(sizeof(*(chunk->res))*cnt, GFP_KERNEL);
  255. if (!chunk->res)
  256. return -ENOMEM;
  257. for (i = 0; i < cnt; i++) {
  258. res = kzalloc(sizeof(*res), GFP_KERNEL);
  259. if (!res) {
  260. err = -ENOMEM;
  261. goto fail;
  262. }
  263. res->type = type;
  264. res->vnic_idx = i;
  265. res->vnic = vnic;
  266. res->ctrl = vnic_dev_get_res(vnic->vdev,
  267. _to_vnic_res_type(type), i);
  268. chunk->res[i] = res;
  269. }
  270. chunk->vnic = vnic;
  271. return 0;
  272. fail:
  273. for (i--; i >= 0; i--)
  274. kfree(chunk->res[i]);
  275. kfree(chunk->res);
  276. return err;
  277. }
  278. static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk *chunk)
  279. {
  280. int i;
  281. for (i = 0; i < chunk->cnt; i++)
  282. kfree(chunk->res[i]);
  283. kfree(chunk->res);
  284. }
  285. static int usnic_vnic_discover_resources(struct pci_dev *pdev,
  286. struct usnic_vnic *vnic)
  287. {
  288. enum usnic_vnic_res_type res_type;
  289. int i;
  290. int err = 0;
  291. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  292. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  293. continue;
  294. vnic->bar[i].len = pci_resource_len(pdev, i);
  295. vnic->bar[i].vaddr = pci_iomap(pdev, i, vnic->bar[i].len);
  296. if (!vnic->bar[i].vaddr) {
  297. usnic_err("Cannot memory-map BAR %d, aborting\n",
  298. i);
  299. err = -ENODEV;
  300. goto out_clean_bar;
  301. }
  302. vnic->bar[i].bus_addr = pci_resource_start(pdev, i);
  303. }
  304. vnic->vdev = vnic_dev_register(NULL, pdev, pdev, vnic->bar,
  305. ARRAY_SIZE(vnic->bar));
  306. if (!vnic->vdev) {
  307. usnic_err("Failed to register device %s\n",
  308. pci_name(pdev));
  309. err = -EINVAL;
  310. goto out_clean_bar;
  311. }
  312. for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
  313. res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) {
  314. err = usnic_vnic_alloc_res_chunk(vnic, res_type,
  315. &vnic->chunks[res_type]);
  316. if (err) {
  317. usnic_err("Failed to alloc res %s with err %d\n",
  318. usnic_vnic_res_type_to_str(res_type),
  319. err);
  320. goto out_clean_chunks;
  321. }
  322. }
  323. return 0;
  324. out_clean_chunks:
  325. for (res_type--; res_type > USNIC_VNIC_RES_TYPE_EOL; res_type--)
  326. usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
  327. vnic_dev_unregister(vnic->vdev);
  328. out_clean_bar:
  329. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  330. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  331. continue;
  332. if (!vnic->bar[i].vaddr)
  333. break;
  334. iounmap(vnic->bar[i].vaddr);
  335. }
  336. return err;
  337. }
  338. struct pci_dev *usnic_vnic_get_pdev(struct usnic_vnic *vnic)
  339. {
  340. return vnic_dev_get_pdev(vnic->vdev);
  341. }
  342. struct vnic_dev_bar *usnic_vnic_get_bar(struct usnic_vnic *vnic,
  343. int bar_num)
  344. {
  345. return (bar_num < ARRAY_SIZE(vnic->bar)) ? &vnic->bar[bar_num] : NULL;
  346. }
  347. static void usnic_vnic_release_resources(struct usnic_vnic *vnic)
  348. {
  349. int i;
  350. struct pci_dev *pdev;
  351. enum usnic_vnic_res_type res_type;
  352. pdev = usnic_vnic_get_pdev(vnic);
  353. for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
  354. res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++)
  355. usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
  356. vnic_dev_unregister(vnic->vdev);
  357. for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
  358. if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
  359. continue;
  360. iounmap(vnic->bar[i].vaddr);
  361. }
  362. }
  363. struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev)
  364. {
  365. struct usnic_vnic *vnic;
  366. int err = 0;
  367. if (!pci_is_enabled(pdev)) {
  368. usnic_err("PCI dev %s is disabled\n", pci_name(pdev));
  369. return ERR_PTR(-EINVAL);
  370. }
  371. vnic = kzalloc(sizeof(*vnic), GFP_KERNEL);
  372. if (!vnic) {
  373. usnic_err("Failed to alloc vnic for %s - out of memory\n",
  374. pci_name(pdev));
  375. return ERR_PTR(-ENOMEM);
  376. }
  377. spin_lock_init(&vnic->res_lock);
  378. err = usnic_vnic_discover_resources(pdev, vnic);
  379. if (err) {
  380. usnic_err("Failed to discover %s resources with err %d\n",
  381. pci_name(pdev), err);
  382. goto out_free_vnic;
  383. }
  384. usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic));
  385. return vnic;
  386. out_free_vnic:
  387. kfree(vnic);
  388. return ERR_PTR(err);
  389. }
  390. void usnic_vnic_free(struct usnic_vnic *vnic)
  391. {
  392. usnic_vnic_release_resources(vnic);
  393. kfree(vnic);
  394. }