mirror of
https://github.com/ipxe/ipxe
synced 2025-12-07 09:50:26 +03:00
[pci] Handle sizing of 64-bit BARs
Provide pci_bar_set() to handle setting the base address for a potentially 64-bit BAR, and rewrite pci_bar_size() to correctly handle sizing of 64-bit BARs. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -104,6 +104,82 @@ unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
||||
@@ -79,42 +79,6 @@ int pci_find_next_capability ( struct pci_device *pci, int pos, int cap ) {
|
||||
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)
|
||||
*
|
||||
|
||||
@@ -314,6 +314,9 @@ struct pci_driver {
|
||||
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 );
|
||||
@@ -322,7 +325,6 @@ extern void pci_remove ( 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 );
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user