}
}
+/**
+ * Set the start of a PCI BAR
+ *
+ * @v pci PCI device
+ * @v reg PCI register number
+ * @v start BAR start address
+ */
+void pci_bar_set ( struct pci_device *pci, unsigned int reg,
+ unsigned long start ) {
+ unsigned int type;
+ uint32_t low;
+ uint32_t high;
+
+ /* Check for a 64-bit BAR */
+ pci_read_config_dword ( pci, reg, &low );
+ type = ( low & ( PCI_BASE_ADDRESS_SPACE_IO |
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK ) );
+
+ /* Write low 32 bits */
+ low = start;
+ pci_write_config_dword ( pci, reg, low );
+
+ /* Write high 32 bits, if applicable */
+ if ( type == PCI_BASE_ADDRESS_MEM_TYPE_64 ) {
+ if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
+ high = ( ( ( uint64_t ) start ) >> 32 );
+ } else {
+ high = 0;
+ }
+ pci_write_config_dword ( pci, reg + 4, high );
+ }
+}
+
+/**
+ * Get the size of a PCI BAR
+ *
+ * @v pci PCI device
+ * @v reg PCI register number
+ * @ret size BAR size
+ *
+ * Most drivers should not need to call this function. It is not
+ * necessary to map the whole PCI BAR, only the portion that will be
+ * used for register access. Since register offsets are almost always
+ * fixed by hardware design, the length of the mapped portion will
+ * almost always be a compile-time constant.
+ */
+unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
+ unsigned long start;
+ unsigned long size;
+ uint16_t cmd;
+
+ /* Save the original command register and disable decoding */
+ pci_read_config_word ( pci, PCI_COMMAND, &cmd );
+ pci_write_config_word ( pci, PCI_COMMAND,
+ ( cmd & ~( PCI_COMMAND_MEM |
+ PCI_COMMAND_IO ) ) );
+
+ /* Save the original start address */
+ start = pci_bar_start ( pci, reg );
+
+ /* Set all possible bits */
+ pci_bar_set ( pci, reg, -1UL );
+
+ /* Determine size by finding lowest set bit */
+ size = pci_bar_start ( pci, reg );
+ size &= ( -size );
+
+ /* Restore the original start address */
+ pci_bar_set ( pci, reg, start );
+
+ /* Restore the original command register */
+ pci_write_config_word ( pci, PCI_COMMAND, cmd );
+
+ return size;
+}
+
/**
* Read membase and ioaddr for a PCI device
*
return pci_find_capability_common ( pci, new_pos, cap );
}
-/**
- * Find the size of a PCI BAR
- *
- * @v pci PCI device
- * @v reg PCI register number
- * @ret size BAR size
- *
- * It should not be necessary for any Etherboot code to call this
- * function.
- */
-unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
- uint16_t cmd;
- uint32_t start, size;
-
- /* Save the original command register */
- pci_read_config_word ( pci, PCI_COMMAND, &cmd );
- /* Save the original bar */
- pci_read_config_dword ( pci, reg, &start );
- /* Compute which bits can be set */
- pci_write_config_dword ( pci, reg, ~0 );
- pci_read_config_dword ( pci, reg, &size );
- /* Restore the original size */
- pci_write_config_dword ( pci, reg, start );
- /* Find the significant bits */
- /* Restore the original command register. This reenables decoding. */
- pci_write_config_word ( pci, PCI_COMMAND, cmd );
- if ( start & PCI_BASE_ADDRESS_SPACE_IO ) {
- size &= ~PCI_BASE_ADDRESS_IO_MASK;
- } else {
- size &= ~PCI_BASE_ADDRESS_MEM_MASK;
- }
- /* Find the lowest bit set */
- size = size & ~( size - 1 );
- return size;
-}
-
/**
* Perform PCI Express function-level reset (FLR)
*
extern void adjust_pci_device ( struct pci_device *pci );
extern unsigned long pci_bar_start ( struct pci_device *pci,
unsigned int reg );
+extern void pci_bar_set ( struct pci_device *pci, unsigned int reg,
+ unsigned long start );
+extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
extern int pci_read_config ( struct pci_device *pci );
extern int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn );
extern int pci_find_driver ( struct pci_device *pci );
extern int pci_find_capability ( struct pci_device *pci, int capability );
extern int pci_find_next_capability ( struct pci_device *pci,
int pos, int capability );
-extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg );
extern void pci_reset ( struct pci_device *pci, unsigned int exp );
/**