iov.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * drivers/pci/iov.c
  3. *
  4. * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
  5. *
  6. * PCI Express I/O Virtualization (IOV) support.
  7. * Single Root IOV 1.0
  8. */
  9. #include <linux/pci.h>
  10. #include <linux/mutex.h>
  11. #include <linux/string.h>
  12. #include <linux/delay.h>
  13. #include "pci.h"
  14. static int sriov_init(struct pci_dev *dev, int pos)
  15. {
  16. int i;
  17. int rc;
  18. int nres;
  19. u32 pgsz;
  20. u16 ctrl, total, offset, stride;
  21. struct pci_sriov *iov;
  22. struct resource *res;
  23. struct pci_dev *pdev;
  24. if (dev->pcie_type != PCI_EXP_TYPE_RC_END &&
  25. dev->pcie_type != PCI_EXP_TYPE_ENDPOINT)
  26. return -ENODEV;
  27. pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
  28. if (ctrl & PCI_SRIOV_CTRL_VFE) {
  29. pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
  30. ssleep(1);
  31. }
  32. pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
  33. if (!total)
  34. return 0;
  35. ctrl = 0;
  36. list_for_each_entry(pdev, &dev->bus->devices, bus_list)
  37. if (pdev->is_physfn)
  38. goto found;
  39. pdev = NULL;
  40. if (pci_ari_enabled(dev->bus))
  41. ctrl |= PCI_SRIOV_CTRL_ARI;
  42. found:
  43. pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
  44. pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
  45. pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
  46. pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
  47. if (!offset || (total > 1 && !stride))
  48. return -EIO;
  49. pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
  50. i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
  51. pgsz &= ~((1 << i) - 1);
  52. if (!pgsz)
  53. return -EIO;
  54. pgsz &= ~(pgsz - 1);
  55. pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
  56. nres = 0;
  57. for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
  58. res = dev->resource + PCI_IOV_RESOURCES + i;
  59. i += __pci_read_base(dev, pci_bar_unknown, res,
  60. pos + PCI_SRIOV_BAR + i * 4);
  61. if (!res->flags)
  62. continue;
  63. if (resource_size(res) & (PAGE_SIZE - 1)) {
  64. rc = -EIO;
  65. goto failed;
  66. }
  67. res->end = res->start + resource_size(res) * total - 1;
  68. nres++;
  69. }
  70. iov = kzalloc(sizeof(*iov), GFP_KERNEL);
  71. if (!iov) {
  72. rc = -ENOMEM;
  73. goto failed;
  74. }
  75. iov->pos = pos;
  76. iov->nres = nres;
  77. iov->ctrl = ctrl;
  78. iov->total = total;
  79. iov->offset = offset;
  80. iov->stride = stride;
  81. iov->pgsz = pgsz;
  82. iov->self = dev;
  83. pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
  84. pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
  85. if (pdev)
  86. iov->dev = pci_dev_get(pdev);
  87. else {
  88. iov->dev = dev;
  89. mutex_init(&iov->lock);
  90. }
  91. dev->sriov = iov;
  92. dev->is_physfn = 1;
  93. return 0;
  94. failed:
  95. for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
  96. res = dev->resource + PCI_IOV_RESOURCES + i;
  97. res->flags = 0;
  98. }
  99. return rc;
  100. }
  101. static void sriov_release(struct pci_dev *dev)
  102. {
  103. if (dev == dev->sriov->dev)
  104. mutex_destroy(&dev->sriov->lock);
  105. else
  106. pci_dev_put(dev->sriov->dev);
  107. kfree(dev->sriov);
  108. dev->sriov = NULL;
  109. }
  110. /**
  111. * pci_iov_init - initialize the IOV capability
  112. * @dev: the PCI device
  113. *
  114. * Returns 0 on success, or negative on failure.
  115. */
  116. int pci_iov_init(struct pci_dev *dev)
  117. {
  118. int pos;
  119. if (!dev->is_pcie)
  120. return -ENODEV;
  121. pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
  122. if (pos)
  123. return sriov_init(dev, pos);
  124. return -ENODEV;
  125. }
  126. /**
  127. * pci_iov_release - release resources used by the IOV capability
  128. * @dev: the PCI device
  129. */
  130. void pci_iov_release(struct pci_dev *dev)
  131. {
  132. if (dev->is_physfn)
  133. sriov_release(dev);
  134. }
  135. /**
  136. * pci_iov_resource_bar - get position of the SR-IOV BAR
  137. * @dev: the PCI device
  138. * @resno: the resource number
  139. * @type: the BAR type to be filled in
  140. *
  141. * Returns position of the BAR encapsulated in the SR-IOV capability.
  142. */
  143. int pci_iov_resource_bar(struct pci_dev *dev, int resno,
  144. enum pci_bar_type *type)
  145. {
  146. if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
  147. return 0;
  148. BUG_ON(!dev->is_physfn);
  149. *type = pci_bar_unknown;
  150. return dev->sriov->pos + PCI_SRIOV_BAR +
  151. 4 * (resno - PCI_IOV_RESOURCES);
  152. }