mirror of
https://github.com/ipxe/ipxe
synced 2026-02-03 22:49:29 +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
|
* 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 );
|
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)
|
* Perform PCI Express function-level reset (FLR)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -314,6 +314,9 @@ struct pci_driver {
|
|||||||
extern void adjust_pci_device ( struct pci_device *pci );
|
extern void adjust_pci_device ( struct pci_device *pci );
|
||||||
extern unsigned long pci_bar_start ( struct pci_device *pci,
|
extern unsigned long pci_bar_start ( struct pci_device *pci,
|
||||||
unsigned int reg );
|
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_read_config ( struct pci_device *pci );
|
||||||
extern int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn );
|
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_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_capability ( struct pci_device *pci, int capability );
|
||||||
extern int pci_find_next_capability ( struct pci_device *pci,
|
extern int pci_find_next_capability ( struct pci_device *pci,
|
||||||
int pos, int capability );
|
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 );
|
extern void pci_reset ( struct pci_device *pci, unsigned int exp );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user