2005-04-17 02:20:36 +04:00
/*
* drivers / pci / setup - bus . c
*
* Extruded from code written by
* Dave Rusling ( david . rusling @ reo . mts . dec . com )
* David Mosberger ( davidm @ cs . arizona . edu )
* David Miller ( davem @ redhat . com )
*
* Support routines for initializing a PCI subsystem .
*/
/*
* Nov 2000 , Ivan Kokshaysky < ink @ jurassic . park . msu . ru >
* PCI - PCI bridges cleanup , sorted resource allocation .
* Feb 2002 , Ivan Kokshaysky < ink @ jurassic . park . msu . ru >
* Converted to allocation in 3 passes , which gives
* tighter packing . Prefetchable range support .
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/errno.h>
# include <linux/ioport.h>
# include <linux/cache.h>
# include <linux/slab.h>
2009-08-29 00:00:06 +04:00
# include "pci.h"
2005-04-17 02:20:36 +04:00
2010-01-22 12:02:21 +03:00
struct resource_list_x {
struct resource_list_x * next ;
struct resource * res ;
struct pci_dev * dev ;
resource_size_t start ;
resource_size_t end ;
2011-02-15 04:43:20 +03:00
resource_size_t add_size ;
2011-07-26 00:08:39 +04:00
resource_size_t min_align ;
2010-01-22 12:02:21 +03:00
unsigned long flags ;
} ;
2011-02-15 04:43:18 +03:00
# define free_list(type, head) do { \
struct type * list , * tmp ; \
for ( list = ( head ) - > next ; list ; ) { \
tmp = list ; \
list = list - > next ; \
kfree ( tmp ) ; \
} \
( head ) - > next = NULL ; \
} while ( 0 )
2011-07-07 22:19:10 +04:00
int pci_realloc_enable = 0 ;
# define pci_realloc_enabled() pci_realloc_enable
void pci_realloc ( void )
{
pci_realloc_enable = 1 ;
}
2011-02-15 04:43:20 +03:00
/**
* add_to_list ( ) - add a new resource tracker to the list
* @ head : Head of the list
* @ dev : device corresponding to which the resource
* belongs
* @ res : The resource to be tracked
* @ add_size : additional size to be optionally added
* to the resource
*/
2012-01-21 14:08:18 +04:00
static int add_to_list ( struct resource_list_x * head ,
2011-02-15 04:43:20 +03:00
struct pci_dev * dev , struct resource * res ,
2011-07-26 00:08:39 +04:00
resource_size_t add_size , resource_size_t min_align )
2010-01-22 12:02:21 +03:00
{
struct resource_list_x * list = head ;
struct resource_list_x * ln = list - > next ;
struct resource_list_x * tmp ;
tmp = kmalloc ( sizeof ( * tmp ) , GFP_KERNEL ) ;
if ( ! tmp ) {
2011-02-15 04:43:20 +03:00
pr_warning ( " add_to_list: kmalloc() failed! \n " ) ;
2012-01-21 14:08:18 +04:00
return - ENOMEM ;
2010-01-22 12:02:21 +03:00
}
tmp - > next = ln ;
tmp - > res = res ;
tmp - > dev = dev ;
tmp - > start = res - > start ;
tmp - > end = res - > end ;
tmp - > flags = res - > flags ;
2011-02-15 04:43:20 +03:00
tmp - > add_size = add_size ;
2011-07-26 00:08:39 +04:00
tmp - > min_align = min_align ;
2010-01-22 12:02:21 +03:00
list - > next = tmp ;
2012-01-21 14:08:18 +04:00
return 0 ;
2010-01-22 12:02:21 +03:00
}
2011-02-15 04:43:20 +03:00
static void add_to_failed_list ( struct resource_list_x * head ,
struct pci_dev * dev , struct resource * res )
{
2011-07-26 00:08:39 +04:00
add_to_list ( head , dev , res ,
0 /* dont care */ ,
0 /* dont care */ ) ;
2011-02-15 04:43:20 +03:00
}
2012-01-21 14:08:20 +04:00
static void remove_from_list ( struct resource_list_x * realloc_head ,
struct resource * res )
{
struct resource_list_x * prev , * tmp , * list ;
prev = realloc_head ;
for ( list = realloc_head - > next ; list ; ) {
if ( list - > res ! = res ) {
prev = list ;
list = list - > next ;
continue ;
}
tmp = list ;
prev - > next = list = list - > next ;
kfree ( tmp ) ;
}
}
2012-01-21 14:08:19 +04:00
static resource_size_t get_res_add_size ( struct resource_list_x * realloc_head ,
struct resource * res )
{
struct resource_list_x * list ;
/* check if it is in realloc_head list */
for ( list = realloc_head - > next ; list & & list - > res ! = res ;
list = list - > next )
;
2012-01-21 14:08:20 +04:00
if ( list ) {
dev_printk ( KERN_DEBUG , & list - > dev - > dev ,
" %pR get_res_add_size add_size %llx \n " ,
list - > res , ( unsigned long long ) list - > add_size ) ;
2012-01-21 14:08:19 +04:00
return list - > add_size ;
2012-01-21 14:08:20 +04:00
}
2012-01-21 14:08:19 +04:00
return 0 ;
}
2012-01-21 14:08:25 +04:00
/* Sort resources by alignment */
static void pdev_sort_resources ( struct pci_dev * dev , struct resource_list * head )
{
int i ;
for ( i = 0 ; i < PCI_NUM_RESOURCES ; i + + ) {
struct resource * r ;
struct resource_list * list , * tmp ;
resource_size_t r_align ;
r = & dev - > resource [ i ] ;
if ( r - > flags & IORESOURCE_PCI_FIXED )
continue ;
if ( ! ( r - > flags ) | | r - > parent )
continue ;
r_align = pci_resource_alignment ( dev , r ) ;
if ( ! r_align ) {
dev_warn ( & dev - > dev , " BAR %d: %pR has bogus alignment \n " ,
i , r ) ;
continue ;
}
for ( list = head ; ; list = list - > next ) {
resource_size_t align = 0 ;
struct resource_list * ln = list - > next ;
if ( ln )
align = pci_resource_alignment ( ln - > dev , ln - > res ) ;
if ( r_align > align ) {
tmp = kmalloc ( sizeof ( * tmp ) , GFP_KERNEL ) ;
if ( ! tmp )
panic ( " pdev_sort_resources(): "
" kmalloc() failed! \n " ) ;
tmp - > next = ln ;
tmp - > res = r ;
tmp - > dev = dev ;
list - > next = tmp ;
break ;
}
}
}
}
2010-01-22 12:02:25 +03:00
static void __dev_sort_resources ( struct pci_dev * dev ,
struct resource_list * head )
2005-04-17 02:20:36 +04:00
{
2010-01-22 12:02:25 +03:00
u16 class = dev - > class > > 8 ;
2005-04-17 02:20:36 +04:00
2010-01-22 12:02:25 +03:00
/* Don't touch classless devices or host bridges or ioapics. */
if ( class = = PCI_CLASS_NOT_DEFINED | | class = = PCI_CLASS_BRIDGE_HOST )
return ;
2005-04-17 02:20:36 +04:00
2010-01-22 12:02:25 +03:00
/* Don't touch ioapic devices already enabled by firmware */
if ( class = = PCI_CLASS_SYSTEM_PIC ) {
u16 command ;
pci_read_config_word ( dev , PCI_COMMAND , & command ) ;
if ( command & ( PCI_COMMAND_IO | PCI_COMMAND_MEMORY ) )
return ;
}
2005-04-17 02:20:36 +04:00
2010-01-22 12:02:25 +03:00
pdev_sort_resources ( dev , head ) ;
}
2006-09-12 21:21:44 +04:00
2011-02-15 04:43:19 +03:00
static inline void reset_resource ( struct resource * res )
{
res - > start = 0 ;
res - > end = 0 ;
res - > flags = 0 ;
}
2011-02-15 04:43:20 +03:00
/**
2011-07-26 00:08:42 +04:00
* reassign_resources_sorted ( ) - satisfy any additional resource requests
2011-02-15 04:43:20 +03:00
*
2011-07-26 00:08:42 +04:00
* @ realloc_head : head of the list tracking requests requiring additional
2011-02-15 04:43:20 +03:00
* resources
* @ head : head of the list tracking requests with allocated
* resources
*
2011-07-26 00:08:42 +04:00
* Walk through each element of the realloc_head and try to procure
2011-02-15 04:43:20 +03:00
* additional resources for the element , provided the element
* is in the head list .
*/
2011-07-26 00:08:42 +04:00
static void reassign_resources_sorted ( struct resource_list_x * realloc_head ,
2011-02-15 04:43:20 +03:00
struct resource_list * head )
2010-01-22 12:02:25 +03:00
{
struct resource * res ;
2011-02-15 04:43:20 +03:00
struct resource_list_x * list , * tmp , * prev ;
struct resource_list * hlist ;
resource_size_t add_size ;
2010-01-22 12:02:25 +03:00
int idx ;
2005-04-17 02:20:36 +04:00
2011-07-26 00:08:42 +04:00
prev = realloc_head ;
for ( list = realloc_head - > next ; list ; ) {
2005-04-17 02:20:36 +04:00
res = list - > res ;
2011-02-15 04:43:20 +03:00
/* skip resource that has been reset */
if ( ! res - > flags )
goto out ;
/* skip this resource if not found in head list */
for ( hlist = head - > next ; hlist & & hlist - > res ! = res ;
hlist = hlist - > next ) ;
if ( ! hlist ) { /* just skip */
prev = list ;
list = list - > next ;
continue ;
}
2005-04-17 02:20:36 +04:00
idx = res - & list - > dev - > resource [ 0 ] ;
2011-02-15 04:43:20 +03:00
add_size = list - > add_size ;
2011-07-26 00:08:39 +04:00
if ( ! resource_size ( res ) ) {
2011-07-26 00:08:41 +04:00
res - > start = list - > start ;
2011-07-26 00:08:39 +04:00
res - > end = res - > start + add_size - 1 ;
if ( pci_assign_resource ( list - > dev , idx ) )
2011-02-15 04:43:20 +03:00
reset_resource ( res ) ;
2011-07-26 00:08:39 +04:00
} else {
resource_size_t align = list - > min_align ;
res - > flags | = list - > flags & ( IORESOURCE_STARTALIGN | IORESOURCE_SIZEALIGN ) ;
if ( pci_reassign_resource ( list - > dev , idx , add_size , align ) )
dev_printk ( KERN_DEBUG , & list - > dev - > dev , " failed to add optional resources res=%pR \n " ,
res ) ;
2011-02-15 04:43:20 +03:00
}
out :
tmp = list ;
prev - > next = list = list - > next ;
kfree ( tmp ) ;
}
}
/**
* assign_requested_resources_sorted ( ) - satisfy resource requests
*
* @ head : head of the list tracking requests for resources
* @ failed_list : head of the list tracking requests that could
* not be allocated
*
* Satisfy resource requests of each element in the list . Add
* requests that could not satisfied to the failed_list .
*/
static void assign_requested_resources_sorted ( struct resource_list * head ,
struct resource_list_x * fail_head )
{
struct resource * res ;
struct resource_list * list ;
int idx ;
2010-03-01 02:49:39 +03:00
2011-02-15 04:43:20 +03:00
for ( list = head - > next ; list ; list = list - > next ) {
res = list - > res ;
idx = res - & list - > dev - > resource [ 0 ] ;
if ( resource_size ( res ) & & pci_assign_resource ( list - > dev , idx ) ) {
2010-03-01 02:49:39 +03:00
if ( fail_head & & ! pci_is_root_bus ( list - > dev - > bus ) ) {
/*
* if the failed res is for ROM BAR , and it will
* be enabled later , don ' t add it to the list
*/
if ( ! ( ( idx = = PCI_ROM_RESOURCE ) & &
( ! ( res - > flags & IORESOURCE_ROM_ENABLE ) ) ) )
add_to_failed_list ( fail_head , list - > dev , res ) ;
}
2011-02-15 04:43:19 +03:00
reset_resource ( res ) ;
2005-04-28 11:25:50 +04:00
}
2005-04-17 02:20:36 +04:00
}
}
2011-02-15 04:43:20 +03:00
static void __assign_resources_sorted ( struct resource_list * head ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head ,
2011-02-15 04:43:20 +03:00
struct resource_list_x * fail_head )
{
2012-01-21 14:08:20 +04:00
/*
* Should not assign requested resources at first .
* they could be adjacent , so later reassign can not reallocate
* them one by one in parent resource window .
* Try to assign requested + add_size at begining
* if could do that , could get out early .
* if could not do that , we still try to assign requested at first ,
* then try to reassign add_size for some resources .
*/
struct resource_list_x save_head , local_fail_head , * list ;
struct resource_list * l ;
/* Check if optional add_size is there */
if ( ! realloc_head | | ! realloc_head - > next )
goto requested_and_reassign ;
/* Save original start, end, flags etc at first */
save_head . next = NULL ;
for ( l = head - > next ; l ; l = l - > next )
if ( add_to_list ( & save_head , l - > dev , l - > res , 0 , 0 ) ) {
free_list ( resource_list_x , & save_head ) ;
goto requested_and_reassign ;
}
/* Update res in head list with add_size in realloc_head list */
for ( l = head - > next ; l ; l = l - > next )
l - > res - > end + = get_res_add_size ( realloc_head , l - > res ) ;
/* Try updated head list with add_size added */
local_fail_head . next = NULL ;
assign_requested_resources_sorted ( head , & local_fail_head ) ;
/* all assigned with add_size ? */
if ( ! local_fail_head . next ) {
/* Remove head list from realloc_head list */
for ( l = head - > next ; l ; l = l - > next )
remove_from_list ( realloc_head , l - > res ) ;
free_list ( resource_list_x , & save_head ) ;
free_list ( resource_list , head ) ;
return ;
}
free_list ( resource_list_x , & local_fail_head ) ;
/* Release assigned resource */
for ( l = head - > next ; l ; l = l - > next )
if ( l - > res - > parent )
release_resource ( l - > res ) ;
/* Restore start/end/flags from saved list */
for ( list = save_head . next ; list ; list = list - > next ) {
struct resource * res = list - > res ;
res - > start = list - > start ;
res - > end = list - > end ;
res - > flags = list - > flags ;
}
free_list ( resource_list_x , & save_head ) ;
requested_and_reassign :
2011-02-15 04:43:20 +03:00
/* Satisfy the must-have resource requests */
assign_requested_resources_sorted ( head , fail_head ) ;
2011-07-26 00:08:41 +04:00
/* Try to satisfy any additional optional resource
2011-02-15 04:43:20 +03:00
requests */
2011-07-26 00:08:42 +04:00
if ( realloc_head )
reassign_resources_sorted ( realloc_head , head ) ;
2011-02-15 04:43:20 +03:00
free_list ( resource_list , head ) ;
}
2010-01-22 12:02:25 +03:00
static void pdev_assign_resources_sorted ( struct pci_dev * dev ,
2012-01-21 14:08:21 +04:00
struct resource_list_x * add_head ,
2010-01-22 12:02:25 +03:00
struct resource_list_x * fail_head )
{
struct resource_list head ;
head . next = NULL ;
__dev_sort_resources ( dev , & head ) ;
2012-01-21 14:08:21 +04:00
__assign_resources_sorted ( & head , add_head , fail_head ) ;
2010-01-22 12:02:25 +03:00
}
static void pbus_assign_resources_sorted ( const struct pci_bus * bus ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head ,
2010-01-22 12:02:25 +03:00
struct resource_list_x * fail_head )
{
struct pci_dev * dev ;
struct resource_list head ;
head . next = NULL ;
list_for_each_entry ( dev , & bus - > devices , bus_list )
__dev_sort_resources ( dev , & head ) ;
2011-07-26 00:08:42 +04:00
__assign_resources_sorted ( & head , realloc_head , fail_head ) ;
2010-01-22 12:02:25 +03:00
}
2005-09-10 00:03:23 +04:00
void pci_setup_cardbus ( struct pci_bus * bus )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * bridge = bus - > self ;
2009-10-27 22:26:47 +03:00
struct resource * res ;
2005-04-17 02:20:36 +04:00
struct pci_bus_region region ;
2009-11-04 20:32:57 +03:00
dev_info ( & bridge - > dev , " CardBus bridge to [bus %02x-%02x] \n " ,
bus - > secondary , bus - > subordinate ) ;
2005-04-17 02:20:36 +04:00
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 0 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_IO ) {
2005-04-17 02:20:36 +04:00
/*
* The IO resource is allocated a range twice as large as it
* would normally need . This allows us to set both IO regs .
*/
2009-10-27 22:26:47 +03:00
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( bridge , PCI_CB_IO_BASE_0 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_LIMIT_0 ,
region . end ) ;
}
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 1 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_IO ) {
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( bridge , PCI_CB_IO_BASE_1 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_LIMIT_1 ,
region . end ) ;
}
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 2 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_MEM ) {
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( bridge , PCI_CB_MEMORY_BASE_0 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_MEMORY_LIMIT_0 ,
region . end ) ;
}
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 3 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_MEM ) {
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( bridge , PCI_CB_MEMORY_BASE_1 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_MEMORY_LIMIT_1 ,
region . end ) ;
}
}
2005-09-10 00:03:23 +04:00
EXPORT_SYMBOL ( pci_setup_cardbus ) ;
2005-04-17 02:20:36 +04:00
/* Initialize bridges with base/limit values we have collected.
PCI - to - PCI Bridge Architecture Specification rev . 1.1 ( 1998 )
requires that if there is no I / O ports or memory behind the
bridge , corresponding range must be turned off by writing base
value greater than limit to the bridge ' s base / limit registers .
Note : care must be taken when updating I / O base / limit registers
of bridges which support 32 - bit I / O . This update requires two
config space writes , so it ' s quite possible that an I / O window of
the bridge will have some undesirable address ( e . g . 0 ) after the
first write . Ditto 64 - bit prefetchable MMIO . */
2009-12-23 02:02:21 +03:00
static void pci_setup_bridge_io ( struct pci_bus * bus )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * bridge = bus - > self ;
2009-10-27 22:26:47 +03:00
struct resource * res ;
2005-04-17 02:20:36 +04:00
struct pci_bus_region region ;
2009-12-23 02:02:21 +03:00
u32 l , io_upper16 ;
2005-04-17 02:20:36 +04:00
/* Set up the top and bottom of the PCI I/O segment for this bus. */
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 0 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_IO ) {
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( bridge , PCI_IO_BASE , & l ) ;
l & = 0xffff0000 ;
l | = ( region . start > > 8 ) & 0x00f0 ;
l | = region . end & 0xf000 ;
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = ( region . end & 0xffff0000 ) | ( region . start > > 16 ) ;
2009-10-27 22:26:47 +03:00
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2009-12-23 02:02:21 +03:00
} else {
2005-04-17 02:20:36 +04:00
/* Clear upper 16 bits of I/O base/limit. */
io_upper16 = 0 ;
l = 0x00f0 ;
}
/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
pci_write_config_dword ( bridge , PCI_IO_BASE_UPPER16 , 0x0000ffff ) ;
/* Update lower 16 bits of I/O base/limit. */
pci_write_config_dword ( bridge , PCI_IO_BASE , l ) ;
/* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword ( bridge , PCI_IO_BASE_UPPER16 , io_upper16 ) ;
2009-12-23 02:02:21 +03:00
}
static void pci_setup_bridge_mmio ( struct pci_bus * bus )
{
struct pci_dev * bridge = bus - > self ;
struct resource * res ;
struct pci_bus_region region ;
u32 l ;
2005-04-17 02:20:36 +04:00
2009-12-23 02:02:21 +03:00
/* Set up the top and bottom of the PCI Memory segment for this bus. */
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 1 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_MEM ) {
2005-04-17 02:20:36 +04:00
l = ( region . start > > 16 ) & 0xfff0 ;
l | = region . end & 0xfff00000 ;
2009-10-27 22:26:47 +03:00
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2009-12-23 02:02:21 +03:00
} else {
2005-04-17 02:20:36 +04:00
l = 0x0000fff0 ;
}
pci_write_config_dword ( bridge , PCI_MEMORY_BASE , l ) ;
2009-12-23 02:02:21 +03:00
}
static void pci_setup_bridge_mmio_pref ( struct pci_bus * bus )
{
struct pci_dev * bridge = bus - > self ;
struct resource * res ;
struct pci_bus_region region ;
u32 l , bu , lu ;
2005-04-17 02:20:36 +04:00
/* Clear out the upper 32 bits of PREF limit.
If PCI_PREF_BASE_UPPER32 was non - zero , this temporarily
disables PREF range , which is ok . */
pci_write_config_dword ( bridge , PCI_PREF_LIMIT_UPPER32 , 0 ) ;
/* Set up PREF base/limit. */
2007-12-10 09:32:15 +03:00
bu = lu = 0 ;
2009-10-27 22:26:47 +03:00
res = bus - > resource [ 2 ] ;
pcibios_resource_to_bus ( bridge , & region , res ) ;
if ( res - > flags & IORESOURCE_PREFETCH ) {
2005-04-17 02:20:36 +04:00
l = ( region . start > > 16 ) & 0xfff0 ;
l | = region . end & 0xfff00000 ;
2009-10-27 22:26:47 +03:00
if ( res - > flags & IORESOURCE_MEM_64 ) {
2009-04-24 07:48:32 +04:00
bu = upper_32_bits ( region . start ) ;
lu = upper_32_bits ( region . end ) ;
}
2009-10-27 22:26:47 +03:00
dev_info ( & bridge - > dev , " bridge window %pR \n " , res ) ;
2009-12-23 02:02:21 +03:00
} else {
2005-04-17 02:20:36 +04:00
l = 0x0000fff0 ;
}
pci_write_config_dword ( bridge , PCI_PREF_MEMORY_BASE , l ) ;
2009-12-01 00:51:44 +03:00
/* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword ( bridge , PCI_PREF_BASE_UPPER32 , bu ) ;
pci_write_config_dword ( bridge , PCI_PREF_LIMIT_UPPER32 , lu ) ;
2009-12-23 02:02:21 +03:00
}
static void __pci_setup_bridge ( struct pci_bus * bus , unsigned long type )
{
struct pci_dev * bridge = bus - > self ;
dev_info ( & bridge - > dev , " PCI bridge to [bus %02x-%02x] \n " ,
bus - > secondary , bus - > subordinate ) ;
if ( type & IORESOURCE_IO )
pci_setup_bridge_io ( bus ) ;
if ( type & IORESOURCE_MEM )
pci_setup_bridge_mmio ( bus ) ;
if ( type & IORESOURCE_PREFETCH )
pci_setup_bridge_mmio_pref ( bus ) ;
2005-04-17 02:20:36 +04:00
pci_write_config_word ( bridge , PCI_BRIDGE_CONTROL , bus - > bridge_ctl ) ;
}
2011-09-11 21:08:38 +04:00
void pci_setup_bridge ( struct pci_bus * bus )
2009-12-23 02:02:21 +03:00
{
unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
__pci_setup_bridge ( bus , type ) ;
}
2005-04-17 02:20:36 +04:00
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges . If not , the respective
base / limit registers must be read - only and read as 0. */
2007-03-27 09:53:30 +04:00
static void pci_bridge_check_ranges ( struct pci_bus * bus )
2005-04-17 02:20:36 +04:00
{
u16 io ;
u32 pmem ;
struct pci_dev * bridge = bus - > self ;
struct resource * b_res ;
b_res = & bridge - > resource [ PCI_BRIDGE_RESOURCES ] ;
b_res [ 1 ] . flags | = IORESOURCE_MEM ;
pci_read_config_word ( bridge , PCI_IO_BASE , & io ) ;
if ( ! io ) {
pci_write_config_word ( bridge , PCI_IO_BASE , 0xf0f0 ) ;
pci_read_config_word ( bridge , PCI_IO_BASE , & io ) ;
pci_write_config_word ( bridge , PCI_IO_BASE , 0x0 ) ;
}
if ( io )
b_res [ 0 ] . flags | = IORESOURCE_IO ;
/* DECchip 21050 pass 2 errata: the bridge may miss an address
disconnect boundary by one PCI data phase .
Workaround : do not use prefetching on this device . */
if ( bridge - > vendor = = PCI_VENDOR_ID_DEC & & bridge - > device = = 0x0001 )
return ;
pci_read_config_dword ( bridge , PCI_PREF_MEMORY_BASE , & pmem ) ;
if ( ! pmem ) {
pci_write_config_dword ( bridge , PCI_PREF_MEMORY_BASE ,
0xfff0fff0 ) ;
pci_read_config_dword ( bridge , PCI_PREF_MEMORY_BASE , & pmem ) ;
pci_write_config_dword ( bridge , PCI_PREF_MEMORY_BASE , 0x0 ) ;
}
2009-04-24 07:48:32 +04:00
if ( pmem ) {
2005-04-17 02:20:36 +04:00
b_res [ 2 ] . flags | = IORESOURCE_MEM | IORESOURCE_PREFETCH ;
2010-01-22 12:02:28 +03:00
if ( ( pmem & PCI_PREF_RANGE_TYPE_MASK ) = =
PCI_PREF_RANGE_TYPE_64 ) {
2009-04-24 07:48:32 +04:00
b_res [ 2 ] . flags | = IORESOURCE_MEM_64 ;
2010-01-22 12:02:28 +03:00
b_res [ 2 ] . flags | = PCI_PREF_RANGE_TYPE_64 ;
}
2009-04-24 07:48:32 +04:00
}
/* double check if bridge does support 64 bit pref */
if ( b_res [ 2 ] . flags & IORESOURCE_MEM_64 ) {
u32 mem_base_hi , tmp ;
pci_read_config_dword ( bridge , PCI_PREF_BASE_UPPER32 ,
& mem_base_hi ) ;
pci_write_config_dword ( bridge , PCI_PREF_BASE_UPPER32 ,
0xffffffff ) ;
pci_read_config_dword ( bridge , PCI_PREF_BASE_UPPER32 , & tmp ) ;
if ( ! tmp )
b_res [ 2 ] . flags & = ~ IORESOURCE_MEM_64 ;
pci_write_config_dword ( bridge , PCI_PREF_BASE_UPPER32 ,
mem_base_hi ) ;
}
2005-04-17 02:20:36 +04:00
}
/* Helper function for sizing routines: find first available
bus resource of a given type . Note : we intentionally skip
the bus resources which have already been assigned ( that is ,
have non - NULL parent resource ) . */
2007-03-27 09:53:30 +04:00
static struct resource * find_free_bus_resource ( struct pci_bus * bus , unsigned long type )
2005-04-17 02:20:36 +04:00
{
int i ;
struct resource * r ;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
2010-02-23 20:24:31 +03:00
pci_bus_for_each_resource ( bus , r , i ) {
2005-06-15 18:59:27 +04:00
if ( r = = & ioport_resource | | r = = & iomem_resource )
continue ;
2009-10-27 19:39:18 +03:00
if ( r & & ( r - > flags & type_mask ) = = type & & ! r - > parent )
return r ;
2005-04-17 02:20:36 +04:00
}
return NULL ;
}
2011-02-15 04:43:17 +03:00
static resource_size_t calculate_iosize ( resource_size_t size ,
resource_size_t min_size ,
resource_size_t size1 ,
resource_size_t old_size ,
resource_size_t align )
{
if ( size < min_size )
size = min_size ;
if ( old_size = = 1 )
old_size = 0 ;
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus . */
# if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = ( size & 0xff ) + ( ( size & ~ 0xffUL ) < < 2 ) ;
# endif
size = ALIGN ( size + size1 , align ) ;
if ( size < old_size )
size = old_size ;
return size ;
}
static resource_size_t calculate_memsize ( resource_size_t size ,
resource_size_t min_size ,
resource_size_t size1 ,
resource_size_t old_size ,
resource_size_t align )
{
if ( size < min_size )
size = min_size ;
if ( old_size = = 1 )
old_size = 0 ;
if ( size < old_size )
size = old_size ;
size = ALIGN ( size + size1 , align ) ;
return size ;
}
2011-02-15 04:43:20 +03:00
/**
* pbus_size_io ( ) - size the io window of a given bus
*
* @ bus : the bus
* @ min_size : the minimum io window that must to be allocated
* @ add_size : additional optional io window
2011-07-26 00:08:42 +04:00
* @ realloc_head : track the additional io window on this list
2011-02-15 04:43:20 +03:00
*
* Sizing the IO windows of the PCI - PCI bridge is trivial ,
* since these windows have 4 K granularity and the IO ranges
* of non - bridge PCI devices are limited to 256 bytes .
* We must be careful with the ISA aliasing though .
*/
static void pbus_size_io ( struct pci_bus * bus , resource_size_t min_size ,
2011-07-26 00:08:42 +04:00
resource_size_t add_size , struct resource_list_x * realloc_head )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
struct resource * b_res = find_free_bus_resource ( bus , IORESOURCE_IO ) ;
2011-02-15 04:43:20 +03:00
unsigned long size = 0 , size0 = 0 , size1 = 0 ;
2011-07-26 00:08:38 +04:00
resource_size_t children_add_size = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! b_res )
return ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
int i ;
for ( i = 0 ; i < PCI_NUM_RESOURCES ; i + + ) {
struct resource * r = & dev - > resource [ i ] ;
unsigned long r_size ;
if ( r - > parent | | ! ( r - > flags & IORESOURCE_IO ) )
continue ;
2008-10-13 15:24:28 +04:00
r_size = resource_size ( r ) ;
2005-04-17 02:20:36 +04:00
if ( r_size < 0x400 )
/* Might be re-aligned for ISA */
size + = r_size ;
else
size1 + = r_size ;
2011-07-26 00:08:38 +04:00
2011-07-26 00:08:42 +04:00
if ( realloc_head )
children_add_size + = get_res_add_size ( realloc_head , r ) ;
2005-04-17 02:20:36 +04:00
}
}
2011-02-15 04:43:20 +03:00
size0 = calculate_iosize ( size , min_size , size1 ,
resource_size ( b_res ) , 4096 ) ;
2011-07-26 00:08:38 +04:00
if ( children_add_size > add_size )
add_size = children_add_size ;
2011-07-26 00:08:42 +04:00
size1 = ( ! realloc_head | | ( realloc_head & & ! add_size ) ) ? size0 :
2012-01-21 14:08:17 +04:00
calculate_iosize ( size , min_size , add_size + size1 ,
2011-02-15 04:43:17 +03:00
resource_size ( b_res ) , 4096 ) ;
2011-02-15 04:43:20 +03:00
if ( ! size0 & & ! size1 ) {
2009-11-04 20:32:57 +03:00
if ( b_res - > start | | b_res - > end )
dev_info ( & bus - > self - > dev , " disabling bridge window "
" %pR to [bus %02x-%02x] (unused) \n " , b_res ,
bus - > secondary , bus - > subordinate ) ;
2005-04-17 02:20:36 +04:00
b_res - > flags = 0 ;
return ;
}
/* Alignment of the IO window is always 4K */
b_res - > start = 4096 ;
2011-02-15 04:43:20 +03:00
b_res - > end = b_res - > start + size0 - 1 ;
PCI: clean up resource alignment management
Done per Linus' request and suggestions. Linus has explained that
better than I'll be able to explain:
On Thu, Mar 27, 2008 at 10:12:10AM -0700, Linus Torvalds wrote:
> Actually, before we go any further, there might be a less intrusive
> alternative: add just a couple of flags to the resource flags field (we
> still have something like 8 unused bits on 32-bit), and use those to
> implement a generic "resource_alignment()" routine.
>
> Two flags would do it:
>
> - IORESOURCE_SIZEALIGN: size indicates alignment (regular PCI device
> resources)
>
> - IORESOURCE_STARTALIGN: start field is alignment (PCI bus resources
> during probing)
>
> and then the case of both flags zero (or both bits set) would actually be
> "invalid", and we would also clear the IORESOURCE_STARTALIGN flag when we
> actually allocate the resource (so that we don't use the "start" field as
> alignment incorrectly when it no longer indicates alignment).
>
> That wouldn't be totally generic, but it would have the nice property of
> automatically at least add sanity checking for that whole "res->start has
> the odd meaning of 'alignment' during probing" and remove the need for a
> new field, and it would allow us to have a generic "resource_alignment()"
> routine that just gets a resource pointer.
Besides, I removed IORESOURCE_BUS_HAS_VGA flag which was unused for ages.
Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Gary Hade <garyhade@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2008-03-30 19:50:14 +04:00
b_res - > flags | = IORESOURCE_STARTALIGN ;
2011-07-26 00:08:42 +04:00
if ( size1 > size0 & & realloc_head )
add_to_list ( realloc_head , bus - > self , b_res , size1 - size0 , 4096 ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-15 04:43:20 +03:00
/**
* pbus_size_mem ( ) - size the memory window of a given bus
*
* @ bus : the bus
* @ min_size : the minimum memory window that must to be allocated
* @ add_size : additional optional memory window
2011-07-26 00:08:42 +04:00
* @ realloc_head : track the additional memory window on this list
2011-02-15 04:43:20 +03:00
*
* Calculate the size of the bus and minimal alignment which
* guarantees that all child resources fit in this size .
*/
2009-09-10 01:09:24 +04:00
static int pbus_size_mem ( struct pci_bus * bus , unsigned long mask ,
2011-02-15 04:43:20 +03:00
unsigned long type , resource_size_t min_size ,
resource_size_t add_size ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
2011-02-15 04:43:20 +03:00
resource_size_t min_align , align , size , size0 , size1 ;
2007-12-10 09:32:15 +03:00
resource_size_t aligns [ 12 ] ; /* Alignments from 1Mb to 2Gb */
2005-04-17 02:20:36 +04:00
int order , max_order ;
struct resource * b_res = find_free_bus_resource ( bus , type ) ;
2009-04-24 07:48:32 +04:00
unsigned int mem64_mask = 0 ;
2011-07-26 00:08:38 +04:00
resource_size_t children_add_size = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! b_res )
return 0 ;
memset ( aligns , 0 , sizeof ( aligns ) ) ;
max_order = 0 ;
size = 0 ;
2009-04-24 07:48:32 +04:00
mem64_mask = b_res - > flags & IORESOURCE_MEM_64 ;
b_res - > flags & = ~ IORESOURCE_MEM_64 ;
2005-04-17 02:20:36 +04:00
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
int i ;
2009-04-24 07:48:32 +04:00
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < PCI_NUM_RESOURCES ; i + + ) {
struct resource * r = & dev - > resource [ i ] ;
2007-12-10 09:32:15 +03:00
resource_size_t r_size ;
2005-04-17 02:20:36 +04:00
if ( r - > parent | | ( r - > flags & mask ) ! = type )
continue ;
2008-10-13 15:24:28 +04:00
r_size = resource_size ( r ) ;
2011-07-26 00:08:40 +04:00
# ifdef CONFIG_PCI_IOV
/* put SRIOV requested res to the optional list */
2011-07-26 00:08:42 +04:00
if ( realloc_head & & i > = PCI_IOV_RESOURCES & &
2011-07-26 00:08:40 +04:00
i < = PCI_IOV_RESOURCE_END ) {
r - > end = r - > start - 1 ;
2011-07-26 00:08:42 +04:00
add_to_list ( realloc_head , dev , r , r_size , 0 /* dont' care */ ) ;
2011-07-26 00:08:40 +04:00
children_add_size + = r_size ;
continue ;
}
# endif
2005-04-17 02:20:36 +04:00
/* For bridges size != alignment */
2009-08-29 00:00:06 +04:00
align = pci_resource_alignment ( dev , r ) ;
2005-04-17 02:20:36 +04:00
order = __ffs ( align ) - 20 ;
if ( order > 11 ) {
2009-11-04 20:32:57 +03:00
dev_warn ( & dev - > dev , " disabling BAR %d: %pR "
" (bad alignment %#llx) \n " , i , r ,
( unsigned long long ) align ) ;
2005-04-17 02:20:36 +04:00
r - > flags = 0 ;
continue ;
}
size + = r_size ;
if ( order < 0 )
order = 0 ;
/* Exclude ranges with size > align from
calculation of the alignment . */
if ( r_size = = align )
aligns [ order ] + = align ;
if ( order > max_order )
max_order = order ;
2009-04-24 07:48:32 +04:00
mem64_mask & = r - > flags & IORESOURCE_MEM_64 ;
2011-07-26 00:08:38 +04:00
2011-07-26 00:08:42 +04:00
if ( realloc_head )
children_add_size + = get_res_add_size ( realloc_head , r ) ;
2005-04-17 02:20:36 +04:00
}
}
align = 0 ;
min_align = 0 ;
for ( order = 0 ; order < = max_order ; order + + ) {
2008-09-11 12:31:50 +04:00
resource_size_t align1 = 1 ;
align1 < < = ( order + 20 ) ;
2005-04-17 02:20:36 +04:00
if ( ! align )
min_align = align1 ;
2007-07-09 22:55:51 +04:00
else if ( ALIGN ( align + min_align , min_align ) < align1 )
2005-04-17 02:20:36 +04:00
min_align = align1 > > 1 ;
align + = aligns [ order ] ;
}
2011-04-11 21:53:11 +04:00
size0 = calculate_memsize ( size , min_size , 0 , resource_size ( b_res ) , min_align ) ;
2011-07-26 00:08:38 +04:00
if ( children_add_size > add_size )
add_size = children_add_size ;
2011-07-26 00:08:42 +04:00
size1 = ( ! realloc_head | | ( realloc_head & & ! add_size ) ) ? size0 :
2012-01-21 14:08:17 +04:00
calculate_memsize ( size , min_size , add_size ,
2011-04-11 21:53:11 +04:00
resource_size ( b_res ) , min_align ) ;
2011-02-15 04:43:20 +03:00
if ( ! size0 & & ! size1 ) {
2009-11-04 20:32:57 +03:00
if ( b_res - > start | | b_res - > end )
dev_info ( & bus - > self - > dev , " disabling bridge window "
" %pR to [bus %02x-%02x] (unused) \n " , b_res ,
bus - > secondary , bus - > subordinate ) ;
2005-04-17 02:20:36 +04:00
b_res - > flags = 0 ;
return 1 ;
}
b_res - > start = min_align ;
2011-02-15 04:43:20 +03:00
b_res - > end = size0 + min_align - 1 ;
b_res - > flags | = IORESOURCE_STARTALIGN | mem64_mask ;
2011-07-26 00:08:42 +04:00
if ( size1 > size0 & & realloc_head )
add_to_list ( realloc_head , bus - > self , b_res , size1 - size0 , min_align ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2011-07-26 00:08:41 +04:00
unsigned long pci_cardbus_resource_alignment ( struct resource * res )
{
if ( res - > flags & IORESOURCE_IO )
return pci_cardbus_io_size ;
if ( res - > flags & IORESOURCE_MEM )
return pci_cardbus_mem_size ;
return 0 ;
}
static void pci_bus_size_cardbus ( struct pci_bus * bus ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * bridge = bus - > self ;
struct resource * b_res = & bridge - > resource [ PCI_BRIDGE_RESOURCES ] ;
u16 ctrl ;
/*
* Reserve some resources for CardBus . We reserve
* a fixed amount of bus space for CardBus bridges .
*/
2008-04-23 05:16:30 +04:00
b_res [ 0 ] . start = 0 ;
b_res [ 0 ] . flags | = IORESOURCE_IO | IORESOURCE_SIZEALIGN ;
2011-07-26 00:08:42 +04:00
if ( realloc_head )
add_to_list ( realloc_head , bridge , b_res , pci_cardbus_io_size , 0 /* dont care */ ) ;
2005-04-17 02:20:36 +04:00
2008-04-23 05:16:30 +04:00
b_res [ 1 ] . start = 0 ;
b_res [ 1 ] . flags | = IORESOURCE_IO | IORESOURCE_SIZEALIGN ;
2011-07-26 00:08:42 +04:00
if ( realloc_head )
add_to_list ( realloc_head , bridge , b_res + 1 , pci_cardbus_io_size , 0 /* dont care */ ) ;
2005-04-17 02:20:36 +04:00
/*
* Check whether prefetchable memory is supported
* by this bridge .
*/
pci_read_config_word ( bridge , PCI_CB_BRIDGE_CONTROL , & ctrl ) ;
if ( ! ( ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 ) ) {
ctrl | = PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 ;
pci_write_config_word ( bridge , PCI_CB_BRIDGE_CONTROL , ctrl ) ;
pci_read_config_word ( bridge , PCI_CB_BRIDGE_CONTROL , & ctrl ) ;
}
/*
* If we have prefetchable memory support , allocate
* two regions . Otherwise , allocate one region of
* twice the size .
*/
if ( ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 ) {
2008-04-23 05:16:30 +04:00
b_res [ 2 ] . start = 0 ;
b_res [ 2 ] . flags | = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN ;
2011-07-26 00:08:42 +04:00
if ( realloc_head )
add_to_list ( realloc_head , bridge , b_res + 2 , pci_cardbus_mem_size , 0 /* dont care */ ) ;
2005-04-17 02:20:36 +04:00
2008-04-23 05:16:30 +04:00
b_res [ 3 ] . start = 0 ;
b_res [ 3 ] . flags | = IORESOURCE_MEM | IORESOURCE_SIZEALIGN ;
2011-07-26 00:08:42 +04:00
if ( realloc_head )
add_to_list ( realloc_head , bridge , b_res + 3 , pci_cardbus_mem_size , 0 /* dont care */ ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-04-23 05:16:30 +04:00
b_res [ 3 ] . start = 0 ;
b_res [ 3 ] . flags | = IORESOURCE_MEM | IORESOURCE_SIZEALIGN ;
2011-07-26 00:08:42 +04:00
if ( realloc_head )
add_to_list ( realloc_head , bridge , b_res + 3 , pci_cardbus_mem_size * 2 , 0 /* dont care */ ) ;
2005-04-17 02:20:36 +04:00
}
2011-07-26 00:08:41 +04:00
/* set the size of the resource to zero, so that the resource does not
* get assigned during required - resource allocation cycle but gets assigned
* during the optional - resource allocation cycle .
*/
b_res [ 0 ] . start = b_res [ 1 ] . start = b_res [ 2 ] . start = b_res [ 3 ] . start = 1 ;
b_res [ 0 ] . end = b_res [ 1 ] . end = b_res [ 2 ] . end = b_res [ 3 ] . end = 0 ;
2005-04-17 02:20:36 +04:00
}
2011-02-15 04:43:20 +03:00
void __ref __pci_bus_size_bridges ( struct pci_bus * bus ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
unsigned long mask , prefmask ;
2011-02-15 04:43:20 +03:00
resource_size_t additional_mem_size = 0 , additional_io_size = 0 ;
2005-04-17 02:20:36 +04:00
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
struct pci_bus * b = dev - > subordinate ;
if ( ! b )
continue ;
switch ( dev - > class > > 8 ) {
case PCI_CLASS_BRIDGE_CARDBUS :
2011-07-26 00:08:42 +04:00
pci_bus_size_cardbus ( b , realloc_head ) ;
2005-04-17 02:20:36 +04:00
break ;
case PCI_CLASS_BRIDGE_PCI :
default :
2011-07-26 00:08:42 +04:00
__pci_bus_size_bridges ( b , realloc_head ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
/* The root bus? */
if ( ! bus - > self )
return ;
switch ( bus - > self - > class > > 8 ) {
case PCI_CLASS_BRIDGE_CARDBUS :
/* don't size cardbuses yet. */
break ;
case PCI_CLASS_BRIDGE_PCI :
pci_bridge_check_ranges ( bus ) ;
2009-09-10 01:09:24 +04:00
if ( bus - > self - > is_hotplug_bridge ) {
2011-02-15 04:43:20 +03:00
additional_io_size = pci_hotplug_io_size ;
additional_mem_size = pci_hotplug_mem_size ;
2009-09-10 01:09:24 +04:00
}
2011-02-15 04:43:20 +03:00
/*
* Follow thru
*/
2005-04-17 02:20:36 +04:00
default :
2012-01-21 14:08:24 +04:00
pbus_size_io ( bus , realloc_head ? 0 : additional_io_size ,
additional_io_size , realloc_head ) ;
2005-04-17 02:20:36 +04:00
/* If the bridge supports prefetchable range, size it
separately . If it doesn ' t , or its prefetchable window
has already been allocated by arch code , try
non - prefetchable range for both types of PCI memory
resources . */
mask = IORESOURCE_MEM ;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH ;
2012-01-21 14:08:24 +04:00
if ( pbus_size_mem ( bus , prefmask , prefmask ,
realloc_head ? 0 : additional_mem_size ,
additional_mem_size , realloc_head ) )
2005-04-17 02:20:36 +04:00
mask = prefmask ; /* Success, size non-prefetch only. */
2009-09-10 01:09:24 +04:00
else
2011-02-15 04:43:20 +03:00
additional_mem_size + = additional_mem_size ;
2012-01-21 14:08:24 +04:00
pbus_size_mem ( bus , mask , IORESOURCE_MEM ,
realloc_head ? 0 : additional_mem_size ,
additional_mem_size , realloc_head ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2011-02-15 04:43:20 +03:00
void __ref pci_bus_size_bridges ( struct pci_bus * bus )
{
__pci_bus_size_bridges ( bus , NULL ) ;
}
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( pci_bus_size_bridges ) ;
2010-01-22 12:02:21 +03:00
static void __ref __pci_bus_assign_resources ( const struct pci_bus * bus ,
2011-07-26 00:08:42 +04:00
struct resource_list_x * realloc_head ,
2010-01-22 12:02:21 +03:00
struct resource_list_x * fail_head )
2005-04-17 02:20:36 +04:00
{
struct pci_bus * b ;
struct pci_dev * dev ;
2011-07-26 00:08:42 +04:00
pbus_assign_resources_sorted ( bus , realloc_head , fail_head ) ;
2005-04-17 02:20:36 +04:00
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
b = dev - > subordinate ;
if ( ! b )
continue ;
2011-07-26 00:08:42 +04:00
__pci_bus_assign_resources ( b , realloc_head , fail_head ) ;
2005-04-17 02:20:36 +04:00
switch ( dev - > class > > 8 ) {
case PCI_CLASS_BRIDGE_PCI :
2010-01-22 12:02:25 +03:00
if ( ! pci_is_enabled ( dev ) )
pci_setup_bridge ( b ) ;
2005-04-17 02:20:36 +04:00
break ;
case PCI_CLASS_BRIDGE_CARDBUS :
pci_setup_cardbus ( b ) ;
break ;
default :
2008-06-13 20:52:11 +04:00
dev_info ( & dev - > dev , " not setting up bridge for bus "
" %04x:%02x \n " , pci_domain_nr ( b ) , b - > number ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
}
2010-01-22 12:02:21 +03:00
void __ref pci_bus_assign_resources ( const struct pci_bus * bus )
{
2011-02-15 04:43:20 +03:00
__pci_bus_assign_resources ( bus , NULL , NULL ) ;
2010-01-22 12:02:21 +03:00
}
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( pci_bus_assign_resources ) ;
2010-01-22 12:02:25 +03:00
static void __ref __pci_bridge_assign_resources ( const struct pci_dev * bridge ,
2012-01-21 14:08:21 +04:00
struct resource_list_x * add_head ,
2010-01-22 12:02:25 +03:00
struct resource_list_x * fail_head )
{
struct pci_bus * b ;
2012-01-21 14:08:21 +04:00
pdev_assign_resources_sorted ( ( struct pci_dev * ) bridge ,
add_head , fail_head ) ;
2010-01-22 12:02:25 +03:00
b = bridge - > subordinate ;
if ( ! b )
return ;
2012-01-21 14:08:21 +04:00
__pci_bus_assign_resources ( b , add_head , fail_head ) ;
2010-01-22 12:02:25 +03:00
switch ( bridge - > class > > 8 ) {
case PCI_CLASS_BRIDGE_PCI :
pci_setup_bridge ( b ) ;
break ;
case PCI_CLASS_BRIDGE_CARDBUS :
pci_setup_cardbus ( b ) ;
break ;
default :
dev_info ( & bridge - > dev , " not setting up bridge for bus "
" %04x:%02x \n " , pci_domain_nr ( b ) , b - > number ) ;
break ;
}
}
2010-01-22 12:02:20 +03:00
static void pci_bridge_release_resources ( struct pci_bus * bus ,
unsigned long type )
{
int idx ;
bool changed = false ;
struct pci_dev * dev ;
struct resource * r ;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
dev = bus - > self ;
for ( idx = PCI_BRIDGE_RESOURCES ; idx < = PCI_BRIDGE_RESOURCE_END ;
idx + + ) {
r = & dev - > resource [ idx ] ;
if ( ( r - > flags & type_mask ) ! = type )
continue ;
if ( ! r - > parent )
continue ;
/*
* if there are children under that , we should release them
* all
*/
release_child_resources ( r ) ;
if ( ! release_resource ( r ) ) {
dev_printk ( KERN_DEBUG , & dev - > dev ,
" resource %d %pR released \n " , idx , r ) ;
/* keep the old size */
r - > end = resource_size ( r ) - 1 ;
r - > start = 0 ;
r - > flags = 0 ;
changed = true ;
}
}
if ( changed ) {
/* avoiding touch the one without PREF */
if ( type & IORESOURCE_PREFETCH )
type = IORESOURCE_PREFETCH ;
__pci_setup_bridge ( bus , type ) ;
}
}
enum release_type {
leaf_only ,
whole_subtree ,
} ;
/*
* try to release pci bridge resources that is from leaf bridge ,
* so we can allocate big new one later
*/
static void __ref pci_bus_release_bridge_resources ( struct pci_bus * bus ,
unsigned long type ,
enum release_type rel_type )
{
struct pci_dev * dev ;
bool is_leaf_bridge = true ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
struct pci_bus * b = dev - > subordinate ;
if ( ! b )
continue ;
is_leaf_bridge = false ;
if ( ( dev - > class > > 8 ) ! = PCI_CLASS_BRIDGE_PCI )
continue ;
if ( rel_type = = whole_subtree )
pci_bus_release_bridge_resources ( b , type ,
whole_subtree ) ;
}
if ( pci_is_root_bus ( bus ) )
return ;
if ( ( bus - > self - > class > > 8 ) ! = PCI_CLASS_BRIDGE_PCI )
return ;
if ( ( rel_type = = whole_subtree ) | | is_leaf_bridge )
pci_bridge_release_resources ( bus , type ) ;
}
2008-06-23 22:33:06 +04:00
static void pci_bus_dump_res ( struct pci_bus * bus )
{
2010-02-23 20:24:31 +03:00
struct resource * res ;
int i ;
2009-12-23 02:02:24 +03:00
2010-02-23 20:24:31 +03:00
pci_bus_for_each_resource ( bus , res , i ) {
2009-12-23 02:02:24 +03:00
if ( ! res | | ! res - > end | | ! res - > flags )
2008-06-23 22:33:06 +04:00
continue ;
2009-10-27 22:26:47 +03:00
dev_printk ( KERN_DEBUG , & bus - > dev , " resource %d %pR \n " , i , res ) ;
2008-06-23 22:33:06 +04:00
}
}
static void pci_bus_dump_resources ( struct pci_bus * bus )
{
struct pci_bus * b ;
struct pci_dev * dev ;
pci_bus_dump_res ( bus ) ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
b = dev - > subordinate ;
if ( ! b )
continue ;
pci_bus_dump_resources ( b ) ;
}
}
2011-05-13 04:11:37 +04:00
static int __init pci_bus_get_depth ( struct pci_bus * bus )
{
int depth = 0 ;
struct pci_dev * dev ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
int ret ;
struct pci_bus * b = dev - > subordinate ;
if ( ! b )
continue ;
ret = pci_bus_get_depth ( b ) ;
if ( ret + 1 > depth )
depth = ret + 1 ;
}
return depth ;
}
static int __init pci_get_max_depth ( void )
{
int depth = 0 ;
struct pci_bus * bus ;
list_for_each_entry ( bus , & pci_root_buses , node ) {
int ret ;
ret = pci_bus_get_depth ( bus ) ;
if ( ret > depth )
depth = ret ;
}
return depth ;
}
2011-07-07 22:19:10 +04:00
2011-05-13 04:11:37 +04:00
/*
* first try will not touch pci bridge res
* second and later try will clear small leaf bridge res
* will stop till to the max deepth if can not find good one
*/
2005-04-17 02:20:36 +04:00
void __init
pci_assign_unassigned_resources ( void )
{
struct pci_bus * bus ;
2011-07-26 00:08:42 +04:00
struct resource_list_x realloc_list ; /* list of resources that
2011-02-15 04:43:20 +03:00
want additional resources */
2012-01-21 14:08:24 +04:00
struct resource_list_x * add_list = NULL ;
2011-05-13 04:11:37 +04:00
int tried_times = 0 ;
enum release_type rel_type = leaf_only ;
struct resource_list_x head , * list ;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
unsigned long failed_type ;
2012-01-21 14:08:24 +04:00
int pci_try_num = 1 ;
2011-05-13 04:11:37 +04:00
head . next = NULL ;
2011-07-26 00:08:42 +04:00
realloc_list . next = NULL ;
2011-05-13 04:11:37 +04:00
2012-01-21 14:08:24 +04:00
/* don't realloc if asked to do so */
if ( pci_realloc_enabled ( ) ) {
int max_depth = pci_get_max_depth ( ) ;
pci_try_num = max_depth + 1 ;
printk ( KERN_DEBUG " PCI: max bus depth: %d pci_try_num: %d \n " ,
max_depth , pci_try_num ) ;
}
2011-05-13 04:11:37 +04:00
again :
2012-01-21 14:08:24 +04:00
/*
* last try will use add_list , otherwise will try good to have as
* must have , so can realloc parent bridge resource
*/
if ( tried_times + 1 = = pci_try_num )
add_list = & realloc_list ;
2005-04-17 02:20:36 +04:00
/* Depth first, calculate sizes and alignments of all
subordinate buses . */
2011-05-13 04:11:37 +04:00
list_for_each_entry ( bus , & pci_root_buses , node )
2012-01-21 14:08:24 +04:00
__pci_bus_size_bridges ( bus , add_list ) ;
2011-02-15 04:43:20 +03:00
2005-04-17 02:20:36 +04:00
/* Depth last, allocate resources and update the hardware. */
2011-05-13 04:11:37 +04:00
list_for_each_entry ( bus , & pci_root_buses , node )
2012-01-21 14:08:24 +04:00
__pci_bus_assign_resources ( bus , add_list , & head ) ;
if ( add_list )
BUG_ON ( add_list - > next ) ;
2011-05-13 04:11:37 +04:00
tried_times + + ;
/* any device complain? */
if ( ! head . next )
goto enable_and_dump ;
2011-07-07 22:19:10 +04:00
2011-05-13 04:11:37 +04:00
failed_type = 0 ;
for ( list = head . next ; list ; ) {
failed_type | = list - > flags ;
list = list - > next ;
}
/*
* io port are tight , don ' t try extra
* or if reach the limit , don ' t want to try more
*/
failed_type & = type_mask ;
if ( ( failed_type = = IORESOURCE_IO ) | | ( tried_times > = pci_try_num ) ) {
free_list ( resource_list_x , & head ) ;
goto enable_and_dump ;
}
printk ( KERN_DEBUG " PCI: No. %d try to assign unassigned res \n " ,
tried_times + 1 ) ;
/* third times and later will not check if it is leaf */
if ( ( tried_times + 1 ) > 2 )
rel_type = whole_subtree ;
/*
* Try to release leaf bridge ' s resources that doesn ' t fit resource of
* child device under that bridge
*/
for ( list = head . next ; list ; ) {
bus = list - > dev - > bus ;
pci_bus_release_bridge_resources ( bus , list - > flags & type_mask ,
rel_type ) ;
list = list - > next ;
}
/* restore size and flags */
for ( list = head . next ; list ; ) {
struct resource * res = list - > res ;
res - > start = list - > start ;
res - > end = list - > end ;
res - > flags = list - > flags ;
if ( list - > dev - > subordinate )
res - > flags = 0 ;
list = list - > next ;
}
free_list ( resource_list_x , & head ) ;
goto again ;
enable_and_dump :
/* Depth last, update the hardware. */
list_for_each_entry ( bus , & pci_root_buses , node )
pci_enable_bridges ( bus ) ;
2008-06-23 22:33:06 +04:00
/* dump the resource on buses */
2011-05-13 04:11:37 +04:00
list_for_each_entry ( bus , & pci_root_buses , node )
2008-06-23 22:33:06 +04:00
pci_bus_dump_resources ( bus ) ;
2005-04-17 02:20:36 +04:00
}
2010-01-22 12:02:25 +03:00
void pci_assign_unassigned_bridge_resources ( struct pci_dev * bridge )
{
struct pci_bus * parent = bridge - > subordinate ;
2012-01-21 14:08:21 +04:00
struct resource_list_x add_list ; /* list of resources that
want additional resources */
2010-01-22 12:02:27 +03:00
int tried_times = 0 ;
struct resource_list_x head , * list ;
2010-01-22 12:02:25 +03:00
int retval ;
2010-01-22 12:02:27 +03:00
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
head . next = NULL ;
2012-01-21 14:08:21 +04:00
add_list . next = NULL ;
2010-01-22 12:02:25 +03:00
2010-01-22 12:02:27 +03:00
again :
2012-01-21 14:08:21 +04:00
__pci_bus_size_bridges ( parent , & add_list ) ;
__pci_bridge_assign_resources ( bridge , & add_list , & head ) ;
BUG_ON ( add_list . next ) ;
2010-01-22 12:02:27 +03:00
tried_times + + ;
if ( ! head . next )
2010-05-22 01:35:06 +04:00
goto enable_all ;
2010-01-22 12:02:27 +03:00
if ( tried_times > = 2 ) {
/* still fail, don't need to try more */
2011-02-15 04:43:18 +03:00
free_list ( resource_list_x , & head ) ;
2010-05-22 01:35:06 +04:00
goto enable_all ;
2010-01-22 12:02:27 +03:00
}
printk ( KERN_DEBUG " PCI: No. %d try to assign unassigned res \n " ,
tried_times + 1 ) ;
/*
* Try to release leaf bridge ' s resources that doesn ' t fit resource of
* child device under that bridge
*/
for ( list = head . next ; list ; ) {
struct pci_bus * bus = list - > dev - > bus ;
unsigned long flags = list - > flags ;
pci_bus_release_bridge_resources ( bus , flags & type_mask ,
whole_subtree ) ;
list = list - > next ;
}
/* restore size and flags */
for ( list = head . next ; list ; ) {
struct resource * res = list - > res ;
res - > start = list - > start ;
res - > end = list - > end ;
res - > flags = list - > flags ;
if ( list - > dev - > subordinate )
res - > flags = 0 ;
list = list - > next ;
}
2011-02-15 04:43:18 +03:00
free_list ( resource_list_x , & head ) ;
2010-01-22 12:02:27 +03:00
goto again ;
2010-05-22 01:35:06 +04:00
enable_all :
retval = pci_reenable_device ( bridge ) ;
pci_set_master ( bridge ) ;
pci_enable_bridges ( parent ) ;
2010-01-22 12:02:25 +03:00
}
EXPORT_SYMBOL_GPL ( pci_assign_unassigned_bridge_resources ) ;
2012-01-21 14:08:23 +04:00
# ifdef CONFIG_HOTPLUG
/**
* pci_rescan_bus - scan a PCI bus for devices .
* @ bus : PCI bus to scan
*
* Scan a PCI bus and child buses for new devices , adds them ,
* and enables them .
*
* Returns the max number of subordinate bus discovered .
*/
unsigned int __ref pci_rescan_bus ( struct pci_bus * bus )
{
unsigned int max ;
struct pci_dev * dev ;
struct resource_list_x add_list ; /* list of resources that
want additional resources */
max = pci_scan_child_bus ( bus ) ;
add_list . next = NULL ;
down_read ( & pci_bus_sem ) ;
list_for_each_entry ( dev , & bus - > devices , bus_list )
if ( dev - > hdr_type = = PCI_HEADER_TYPE_BRIDGE | |
dev - > hdr_type = = PCI_HEADER_TYPE_CARDBUS )
if ( dev - > subordinate )
__pci_bus_size_bridges ( dev - > subordinate ,
& add_list ) ;
up_read ( & pci_bus_sem ) ;
__pci_bus_assign_resources ( bus , & add_list , NULL ) ;
BUG_ON ( add_list . next ) ;
pci_enable_bridges ( bus ) ;
pci_bus_add_devices ( bus ) ;
return max ;
}
EXPORT_SYMBOL_GPL ( pci_rescan_bus ) ;
# endif