@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
}
# endif /* CONFIG_PCI_QUIRKS */
static int __pci_assign_resource ( struct pci_bus * bus , struct pci_dev * dev ,
int resno )
int resno , resource_size_t size , resource_size_t align )
{
struct resource * res = dev - > resource + resno ;
resource_size_t size , min , alig n ;
resource_size_t min ;
int ret ;
size = resource_size ( res ) ;
min = ( res - > flags & IORESOURCE_IO ) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM ;
align = pci_resource_alignment ( dev , res ) ;
/* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource ( bus , res , size , align , min ,
@ -154,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
ret = pci_bus_alloc_resource ( bus , res , size , align , min , 0 ,
pcibios_align_resource , dev ) ;
}
return ret ;
}
if ( ret < 0 & & dev - > fw_addr [ resno ] ) {
struct resource * root , * conflict ;
resource_size_t start , end ;
static int pci_revert_fw_address ( struct resource * res , struct pci_dev * dev ,
int resno , resource_size_t size )
{
struct resource * root , * conflict ;
resource_size_t start , end ;
int ret = 0 ;
/*
* If we failed to assign anything , let ' s try the address
* where firmware left it . That at least has a chance of
* working , which is better than just leaving it disabled .
*/
if ( res - > flags & IORESOURCE_IO )
root = & ioport_resource ;
else
root = & iomem_resource ;
start = res - > start ;
end = res - > end ;
res - > start = dev - > fw_addr [ resno ] ;
res - > end = res - > start + size - 1 ;
dev_info ( & dev - > dev , " BAR %d: trying firmware assignment %pR \n " ,
resno , res ) ;
conflict = request_resource_conflict ( root , res ) ;
if ( conflict ) {
dev_info ( & dev - > dev ,
" BAR %d: %pR conflicts with %s %pR \n " , resno ,
res , conflict - > name , conflict ) ;
res - > start = start ;
res - > end = end ;
ret = 1 ;
}
return ret ;
}
static int _pci_assign_resource ( struct pci_dev * dev , int resno , int size , resource_size_t min_align )
{
struct resource * res = dev - > resource + resno ;
struct pci_bus * bus ;
int ret ;
char * type ;
if ( res - > flags & IORESOURCE_IO )
root = & ioport_resource ;
bus = dev - > bus ;
while ( ( ret = __pci_assign_resource ( bus , dev , resno , size , min_align ) ) ) {
if ( ! bus - > parent | | ! bus - > self - > transparent )
break ;
bus = bus - > parent ;
}
if ( ret ) {
if ( res - > flags & IORESOURCE_MEM )
if ( res - > flags & IORESOURCE_PREFETCH )
type = " mem pref " ;
else
type = " mem " ;
else if ( res - > flags & IORESOURCE_IO )
type = " io " ;
else
root = & iomem_resource ;
start = res - > start ;
end = res - > end ;
res - > start = dev - > fw_addr [ resno ] ;
res - > end = res - > start + size - 1 ;
dev_info ( & dev - > dev , " BAR %d: trying firmware assignment %pR \n " ,
resno , res ) ;
conflict = request_resource_conflict ( root , res ) ;
if ( conflict ) {
dev_info ( & dev - > dev ,
" BAR %d: %pR conflicts with %s %pR \n " , resno ,
res , conflict - > name , conflict ) ;
res - > start = start ;
res - > end = end ;
} else
ret = 0 ;
type = " unknown " ;
dev_info ( & dev - > dev ,
" BAR %d: can't assign %s (size %#llx) \n " ,
resno , type , ( unsigned long long ) resource_size ( res ) ) ;
}
return ret ;
}
int pci_reassign_resource ( struct pci_dev * dev , int resno , resource_size_t addsize ,
resource_size_t min_align )
{
struct resource * res = dev - > resource + resno ;
resource_size_t new_size ;
int ret ;
if ( ! res - > parent ) {
dev_info ( & dev - > dev , " BAR %d: can't reassign an unassigned resouce %pR "
" \n " , resno , res ) ;
return - EINVAL ;
}
new_size = resource_size ( res ) + addsize + min_align ;
ret = _pci_assign_resource ( dev , resno , new_size , min_align ) ;
if ( ! ret ) {
res - > flags & = ~ IORESOURCE_STARTALIGN ;
dev_info ( & dev - > dev , " BAR %d: assigned %pR \n " , resno , res ) ;
if ( resno < PCI_BRIDGE_RESOURCES )
pci_update_resource ( dev , resno ) ;
}
return ret ;
}
int pci_assign_resource ( struct pci_dev * dev , int resno )
{
struct resource * res = dev - > resource + resno ;
resource_size_t align ;
resource_size_t align , size ;
struct pci_bus * bus ;
int ret ;
char * type ;
align = pci_resource_alignment ( dev , res ) ;
if ( ! align ) {
@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
bus = dev - > bus ;
while ( ( ret = __pci_assign_resource ( bus , dev , resno ) ) ) {
if ( bus - > parent & & bus - > self - > transparent )
bus = bus - > parent ;
else
bus = NULL ;
if ( bus )
continue ;
break ;
}
size = resource_size ( res ) ;
ret = _pci_assign_resource ( dev , resno , size , align ) ;
if ( ret ) {
if ( res - > flags & IORESOURCE_MEM )
if ( res - > flags & IORESOURCE_PREFETCH )
type = " mem pref " ;
else
type = " mem " ;
else if ( res - > flags & IORESOURCE_IO )
type = " io " ;
else
type = " unknown " ;
dev_info ( & dev - > dev ,
" BAR %d: can't assign %s (size %#llx) \n " ,
resno , type , ( unsigned long long ) resource_size ( res ) ) ;
}
/*
* If we failed to assign anything , let ' s try the address
* where firmware left it . That at least has a chance of
* working , which is better than just leaving it disabled .
*/
if ( ret < 0 & & dev - > fw_addr [ resno ] )
ret = pci_revert_fw_address ( res , dev , resno , size ) ;
if ( ! ret ) {
res - > flags & = ~ IORESOURCE_STARTALIGN ;
dev_info ( & dev - > dev , " BAR %d: assigned %pR \n " , resno , res ) ;
if ( resno < PCI_BRIDGE_RESOURCES )
pci_update_resource ( dev , resno ) ;
}
return ret ;
}
/* Sort resources by alignment */
void pdev_sort_resources ( struct pci_dev * dev , struct resource_list * head )
{