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.

pciea.c 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright (C) 2016 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 <stdint.h>
  25. #include <errno.h>
  26. #include <ipxe/pci.h>
  27. #include <ipxe/pciea.h>
  28. /** @file
  29. *
  30. * PCI Enhanced Allocation
  31. *
  32. */
  33. /**
  34. * Locate PCI Enhanced Allocation BAR equivalent entry
  35. *
  36. * @v pci PCI device
  37. * @v bei BAR equivalent indicator
  38. * @ret offset PCI Enhanced Allocation entry offset, or negative error
  39. */
  40. static int pciea_offset ( struct pci_device *pci, unsigned int bei ) {
  41. uint8_t entries;
  42. uint32_t desc;
  43. unsigned int i;
  44. int offset;
  45. /* Locate Enhanced Allocation capability */
  46. offset = pci_find_capability ( pci, PCI_CAP_ID_EA );
  47. if ( offset < 0 )
  48. return offset;
  49. /* Get number of entries */
  50. pci_read_config_byte ( pci, ( offset + PCIEA_ENTRIES ), &entries );
  51. entries &= PCIEA_ENTRIES_MASK;
  52. /* Locate first entry */
  53. offset += PCIEA_FIRST;
  54. /* Search for a matching entry */
  55. for ( i = 0 ; i < entries ; i++ ) {
  56. /* Read entry descriptor */
  57. pci_read_config_dword ( pci, offset, &desc );
  58. /* Check for a matching entry */
  59. if ( ( desc & PCIEA_DESC_ENABLED ) &&
  60. ( bei == PCIEA_DESC_BEI ( desc ) ) )
  61. return offset;
  62. /* Move to next entry */
  63. offset += ( ( PCIEA_DESC_SIZE ( desc ) + 1 ) << 2 );
  64. }
  65. return -ENOENT;
  66. }
  67. /**
  68. * Read PCI Enhanced Allocation BAR equivalent value
  69. *
  70. * @v pci PCI device
  71. * @v bei BAR equivalent indicator
  72. * @v low_offset Offset to low dword of value
  73. * @ret value BAR equivalent value
  74. */
  75. static unsigned long pciea_bar_value ( struct pci_device *pci, unsigned int bei,
  76. unsigned int low_offset ) {
  77. uint32_t low;
  78. uint32_t high;
  79. int offset;
  80. /* Locate Enhanced Allocation offset for this BEI */
  81. offset = pciea_offset ( pci, bei );
  82. if ( offset < 0 )
  83. return 0;
  84. /* Read BAR equivalent */
  85. offset += low_offset;
  86. pci_read_config_dword ( pci, offset, &low );
  87. if ( low & PCIEA_LOW_ATTR_64BIT ) {
  88. offset += PCIEA_LOW_HIGH;
  89. pci_read_config_dword ( pci, offset, &high );
  90. if ( high ) {
  91. if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
  92. return ( ( ( uint64_t ) high << 32 ) | low );
  93. } else {
  94. DBGC ( pci, PCI_FMT " unhandled 64-bit EA BAR "
  95. "%08x%08x\n",
  96. PCI_ARGS ( pci ), high, low );
  97. return 0;
  98. }
  99. }
  100. }
  101. return low;
  102. }
  103. /**
  104. * Find the start of a PCI Enhanced Allocation BAR equivalent
  105. *
  106. * @v pci PCI device
  107. * @v bei BAR equivalent indicator
  108. * @ret start BAR start address
  109. *
  110. * If the address exceeds the size of an unsigned long (i.e. if a
  111. * 64-bit BAR has a non-zero high dword on a 32-bit machine), the
  112. * return value will be zero.
  113. */
  114. unsigned long pciea_bar_start ( struct pci_device *pci, unsigned int bei ) {
  115. unsigned long base;
  116. base = pciea_bar_value ( pci, bei, PCIEA_LOW_BASE );
  117. return ( base & ~PCIEA_LOW_ATTR_MASK );
  118. }
  119. /**
  120. * Find the size of a PCI Enhanced Allocation BAR equivalent
  121. *
  122. * @v pci PCI device
  123. * @v bei BAR equivalent indicator
  124. * @ret size BAR size
  125. */
  126. unsigned long pciea_bar_size ( struct pci_device *pci, unsigned int bei ) {
  127. unsigned long limit;
  128. limit = pciea_bar_value ( pci, bei, PCIEA_LOW_LIMIT );
  129. return ( limit ? ( ( limit | PCIEA_LOW_ATTR_MASK ) + 1 ) : 0 );
  130. }