You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

linux_pci.c 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdio.h>
  25. #include <errno.h>
  26. #include <byteswap.h>
  27. #include <linux_api.h>
  28. #include <ipxe/linux.h>
  29. #include <ipxe/pci.h>
  30. /** @file
  31. *
  32. * iPXE PCI API for Linux
  33. *
  34. */
  35. /**
  36. * Open PCI configuration space
  37. *
  38. * @v pci PCI device
  39. * @v flags Access mode flags
  40. * @v where Address within configuration space
  41. * @ret fd File handle, or negative error
  42. */
  43. static int linux_pci_open ( struct pci_device *pci, int flags,
  44. unsigned long where ) {
  45. char filename[ 22 /* "/proc/bus/pci/xx/xx.x" + NUL */ ];
  46. int fd;
  47. int rc;
  48. /* Construct filename */
  49. snprintf ( filename, sizeof ( filename ), "/proc/bus/pci/%02x/%02x.%x",
  50. PCI_BUS ( pci->busdevfn ), PCI_SLOT ( pci->busdevfn ),
  51. PCI_FUNC ( pci->busdevfn ) );
  52. /* Open file */
  53. fd = linux_open ( filename, flags );
  54. if ( fd < 0 ) {
  55. DBGC ( pci, "PCI could not open %s: %s\n", filename,
  56. linux_strerror ( linux_errno ) );
  57. rc = -ELINUX ( linux_errno );
  58. goto err_open;
  59. }
  60. /* Seek to location */
  61. if ( linux_lseek ( fd, where, SEEK_SET ) < 0 ) {
  62. DBGC ( pci, "PCI could not seek to %s offset %#02lx: %s\n",
  63. filename, where, linux_strerror ( linux_errno ) );
  64. rc = -ELINUX ( linux_errno );
  65. goto err_seek;
  66. }
  67. return fd;
  68. err_seek:
  69. linux_close ( fd );
  70. err_open:
  71. return rc;
  72. }
  73. /**
  74. * Read from PCI configuration space
  75. *
  76. * @v pci PCI device
  77. * @v where Address within configuration space
  78. * @v value Data buffer
  79. * @v len Length to read
  80. * @ret rc Return status code
  81. */
  82. int linux_pci_read ( struct pci_device *pci, unsigned long where,
  83. unsigned long *value, size_t len ) {
  84. uint32_t tmp = 0;
  85. int fd;
  86. int check_len;
  87. int rc;
  88. /* Return "missing device" in case of error */
  89. *value = -1UL;
  90. /* Open configuration space */
  91. fd = linux_pci_open ( pci, O_RDONLY, where );
  92. if ( fd < 0 ) {
  93. rc = fd;
  94. goto err_open;
  95. }
  96. /* Read value */
  97. check_len = linux_read ( fd, &tmp, len );
  98. if ( check_len < 0 ) {
  99. DBGC ( pci, "PCI could not read from " PCI_FMT " %#02lx+%#zx: "
  100. "%s\n", PCI_ARGS ( pci ), where, len,
  101. linux_strerror ( linux_errno ) );
  102. rc = -ELINUX ( linux_errno );
  103. goto err_read;
  104. }
  105. if ( ( size_t ) check_len != len ) {
  106. DBGC ( pci, "PCI read only %#x bytes from " PCI_FMT
  107. " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ),
  108. where, len );
  109. rc = -EIO;
  110. goto err_read;
  111. }
  112. /* Return value */
  113. *value = le32_to_cpu ( tmp );
  114. /* Success */
  115. rc = 0;
  116. err_read:
  117. linux_close ( fd );
  118. err_open:
  119. return rc;
  120. }
  121. /**
  122. * Write to PCI configuration space
  123. *
  124. * @v pci PCI device
  125. * @v where Address within configuration space
  126. * @v value Value to write
  127. * @v len Length of value
  128. * @ret rc Return status code
  129. */
  130. int linux_pci_write ( struct pci_device *pci, unsigned long where,
  131. unsigned long value, size_t len ) {
  132. uint32_t tmp;
  133. int fd;
  134. int check_len;
  135. int rc;
  136. /* Open configuration space */
  137. fd = linux_pci_open ( pci, O_WRONLY, where );
  138. if ( fd < 0 ) {
  139. rc = fd;
  140. goto err_open;
  141. }
  142. /* Prepare value for writing */
  143. tmp = cpu_to_le32 ( value );
  144. assert ( len <= sizeof ( tmp ) );
  145. /* Write value */
  146. check_len = linux_write ( fd, &tmp, len );
  147. if ( check_len < 0 ) {
  148. DBGC ( pci, "PCI could not write to " PCI_FMT " %#02lx+%#zx: "
  149. "%s\n", PCI_ARGS ( pci ), where, len,
  150. linux_strerror ( linux_errno ) );
  151. rc = -ELINUX ( linux_errno );
  152. goto err_write;
  153. }
  154. if ( ( size_t ) check_len != len ) {
  155. DBGC ( pci, "PCI wrote only %#x bytes to " PCI_FMT
  156. " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ),
  157. where, len );
  158. rc = -EIO;
  159. goto err_write;
  160. }
  161. /* Success */
  162. rc = 0;
  163. err_write:
  164. linux_close ( fd );
  165. err_open:
  166. return rc;
  167. }