pcie.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Karol Herbst <git@karolherbst.de>
  23. */
  24. #include "priv.h"
  25. static char *nvkm_pcie_speeds[] = {
  26. "2.5GT/s",
  27. "5.0GT/s",
  28. "8.0GT/s",
  29. };
  30. static enum nvkm_pcie_speed
  31. nvkm_pcie_speed(enum pci_bus_speed speed)
  32. {
  33. switch (speed) {
  34. case PCIE_SPEED_2_5GT:
  35. return NVKM_PCIE_SPEED_2_5;
  36. case PCIE_SPEED_5_0GT:
  37. return NVKM_PCIE_SPEED_5_0;
  38. case PCIE_SPEED_8_0GT:
  39. return NVKM_PCIE_SPEED_8_0;
  40. default:
  41. /* XXX 0x16 is 8_0, assume 0x17 will be 16_0 for now */
  42. if (speed == 0x17)
  43. return NVKM_PCIE_SPEED_8_0;
  44. return -1;
  45. }
  46. }
  47. static int
  48. nvkm_pcie_get_version(struct nvkm_pci *pci)
  49. {
  50. if (!pci->func->pcie.version)
  51. return -ENOSYS;
  52. return pci->func->pcie.version(pci);
  53. }
  54. static int
  55. nvkm_pcie_get_max_version(struct nvkm_pci *pci)
  56. {
  57. if (!pci->func->pcie.version_supported)
  58. return -ENOSYS;
  59. return pci->func->pcie.version_supported(pci);
  60. }
  61. static int
  62. nvkm_pcie_set_version(struct nvkm_pci *pci, int version)
  63. {
  64. if (!pci->func->pcie.set_version)
  65. return -ENOSYS;
  66. nvkm_trace(&pci->subdev, "set to version %i\n", version);
  67. pci->func->pcie.set_version(pci, version);
  68. return nvkm_pcie_get_version(pci);
  69. }
  70. int
  71. nvkm_pcie_oneinit(struct nvkm_pci *pci)
  72. {
  73. if (pci->func->pcie.max_speed)
  74. nvkm_debug(&pci->subdev, "pcie max speed: %s\n",
  75. nvkm_pcie_speeds[pci->func->pcie.max_speed(pci)]);
  76. return 0;
  77. }
  78. int
  79. nvkm_pcie_init(struct nvkm_pci *pci)
  80. {
  81. struct nvkm_subdev *subdev = &pci->subdev;
  82. int ret;
  83. /* raise pcie version first */
  84. ret = nvkm_pcie_get_version(pci);
  85. if (ret > 0) {
  86. int max_version = nvkm_pcie_get_max_version(pci);
  87. if (max_version > 0 && max_version > ret)
  88. ret = nvkm_pcie_set_version(pci, max_version);
  89. if (ret < max_version)
  90. nvkm_error(subdev, "couldn't raise version: %i\n", ret);
  91. }
  92. if (pci->func->pcie.init)
  93. pci->func->pcie.init(pci);
  94. if (pci->pcie.speed != -1)
  95. nvkm_pcie_set_link(pci, pci->pcie.speed, pci->pcie.width);
  96. return 0;
  97. }
  98. int
  99. nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
  100. {
  101. struct nvkm_subdev *subdev = &pci->subdev;
  102. enum nvkm_pcie_speed cur_speed, max_speed;
  103. struct pci_bus *pbus;
  104. int ret;
  105. if (!pci || !pci_is_pcie(pci->pdev))
  106. return 0;
  107. pbus = pci->pdev->bus;
  108. if (!pci->func->pcie.set_link)
  109. return -ENOSYS;
  110. nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
  111. if (pci->func->pcie.version(pci) < 2) {
  112. nvkm_error(subdev, "setting link failed due to low version\n");
  113. return -ENODEV;
  114. }
  115. cur_speed = pci->func->pcie.cur_speed(pci);
  116. max_speed = min(nvkm_pcie_speed(pbus->max_bus_speed),
  117. pci->func->pcie.max_speed(pci));
  118. nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
  119. if (speed > max_speed) {
  120. nvkm_debug(subdev, "%s not supported by bus or card, dropping"
  121. "requested speed to %s", nvkm_pcie_speeds[speed],
  122. nvkm_pcie_speeds[max_speed]);
  123. speed = max_speed;
  124. }
  125. pci->pcie.speed = speed;
  126. pci->pcie.width = width;
  127. if (speed == cur_speed) {
  128. nvkm_debug(subdev, "requested matches current speed\n");
  129. return speed;
  130. }
  131. nvkm_debug(subdev, "set link to %s x%i\n",
  132. nvkm_pcie_speeds[speed], width);
  133. ret = pci->func->pcie.set_link(pci, speed, width);
  134. if (ret < 0)
  135. nvkm_error(subdev, "setting link failed: %i\n", ret);
  136. return ret;
  137. }