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>
# define DEBUG_CONFIG 1
# if DEBUG_CONFIG
# define DBG(x...) printk(x)
# else
# define DBG(x...)
# endif
# define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
static void __devinit
pbus_assign_resources_sorted ( struct pci_bus * bus )
{
struct pci_dev * dev ;
struct resource * res ;
struct resource_list head , * list , * tmp ;
int idx ;
head . next = NULL ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
u16 class = dev - > class > > 8 ;
2006-10-04 13:15:34 +04:00
/* Don't touch classless devices or host bridges or ioapics. */
2005-04-17 02:20:36 +04:00
if ( class = = PCI_CLASS_NOT_DEFINED | |
2006-09-12 21:21:44 +04:00
class = = PCI_CLASS_BRIDGE_HOST )
2005-04-17 02:20:36 +04:00
continue ;
2006-10-04 13:15:34 +04:00
/* Don't touch ioapic devices already enabled by firmware */
2006-09-12 21:21:44 +04:00
if ( class = = PCI_CLASS_SYSTEM_PIC ) {
2006-10-04 13:15:34 +04:00
u16 command ;
pci_read_config_word ( dev , PCI_COMMAND , & command ) ;
if ( command & ( PCI_COMMAND_IO | PCI_COMMAND_MEMORY ) )
2006-09-12 21:21:44 +04:00
continue ;
}
2005-04-17 02:20:36 +04:00
pdev_sort_resources ( dev , & head ) ;
}
for ( list = head . next ; list ; ) {
res = list - > res ;
idx = res - & list - > dev - > resource [ 0 ] ;
2005-04-28 11:25:50 +04:00
if ( pci_assign_resource ( list - > dev , idx ) ) {
res - > start = 0 ;
2005-07-07 03:07:56 +04:00
res - > end = 0 ;
2005-04-28 11:25:50 +04:00
res - > flags = 0 ;
}
2005-04-17 02:20:36 +04:00
tmp = list ;
list = list - > next ;
kfree ( tmp ) ;
}
}
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 ;
struct pci_bus_region region ;
printk ( " PCI: Bus %d, cardbus bridge: %s \n " ,
bus - > number , pci_name ( bridge ) ) ;
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 0 ] ) ;
if ( bus - > resource [ 0 ] - > flags & IORESOURCE_IO ) {
/*
* The IO resource is allocated a range twice as large as it
* would normally need . This allows us to set both IO regs .
*/
printk ( " IO window: %08lx-%08lx \n " ,
region . start , region . end ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_BASE_0 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_LIMIT_0 ,
region . end ) ;
}
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 1 ] ) ;
if ( bus - > resource [ 1 ] - > flags & IORESOURCE_IO ) {
printk ( " IO window: %08lx-%08lx \n " ,
region . start , region . end ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_BASE_1 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_IO_LIMIT_1 ,
region . end ) ;
}
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 2 ] ) ;
if ( bus - > resource [ 2 ] - > flags & IORESOURCE_MEM ) {
printk ( " PREFETCH window: %08lx-%08lx \n " ,
region . start , region . end ) ;
pci_write_config_dword ( bridge , PCI_CB_MEMORY_BASE_0 ,
region . start ) ;
pci_write_config_dword ( bridge , PCI_CB_MEMORY_LIMIT_0 ,
region . end ) ;
}
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 3 ] ) ;
if ( bus - > resource [ 3 ] - > flags & IORESOURCE_MEM ) {
printk ( " MEM window: %08lx-%08lx \n " ,
region . start , region . end ) ;
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 . */
static void __devinit
pci_setup_bridge ( struct pci_bus * bus )
{
struct pci_dev * bridge = bus - > self ;
struct pci_bus_region region ;
u32 l , io_upper16 ;
DBG ( KERN_INFO " PCI: Bridge: %s \n " , pci_name ( bridge ) ) ;
/* Set up the top and bottom of the PCI I/O segment for this bus. */
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 0 ] ) ;
if ( bus - > resource [ 0 ] - > flags & IORESOURCE_IO ) {
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 ) ;
DBG ( KERN_INFO " IO window: %04lx-%04lx \n " ,
region . start , region . end ) ;
}
else {
/* Clear upper 16 bits of I/O base/limit. */
io_upper16 = 0 ;
l = 0x00f0 ;
DBG ( KERN_INFO " IO window: disabled. \n " ) ;
}
/* 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 ) ;
/* Set up the top and bottom of the PCI Memory segment
for this bus . */
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 1 ] ) ;
if ( bus - > resource [ 1 ] - > flags & IORESOURCE_MEM ) {
l = ( region . start > > 16 ) & 0xfff0 ;
l | = region . end & 0xfff00000 ;
DBG ( KERN_INFO " MEM window: %08lx-%08lx \n " ,
region . start , region . end ) ;
}
else {
l = 0x0000fff0 ;
DBG ( KERN_INFO " MEM window: disabled. \n " ) ;
}
pci_write_config_dword ( bridge , PCI_MEMORY_BASE , l ) ;
/* 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. */
pcibios_resource_to_bus ( bridge , & region , bus - > resource [ 2 ] ) ;
if ( bus - > resource [ 2 ] - > flags & IORESOURCE_PREFETCH ) {
l = ( region . start > > 16 ) & 0xfff0 ;
l | = region . end & 0xfff00000 ;
DBG ( KERN_INFO " PREFETCH window: %08lx-%08lx \n " ,
region . start , region . end ) ;
}
else {
l = 0x0000fff0 ;
DBG ( KERN_INFO " PREFETCH window: disabled. \n " ) ;
}
pci_write_config_dword ( bridge , PCI_PREF_MEMORY_BASE , l ) ;
/* Clear out the upper 32 bits of PREF base. */
pci_write_config_dword ( bridge , PCI_PREF_BASE_UPPER32 , 0 ) ;
pci_write_config_word ( bridge , PCI_BRIDGE_CONTROL , bus - > bridge_ctl ) ;
}
/* 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. */
static void __devinit
pci_bridge_check_ranges ( struct pci_bus * bus )
{
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 ) ;
}
if ( pmem )
b_res [ 2 ] . flags | = IORESOURCE_MEM | IORESOURCE_PREFETCH ;
}
/* 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 ) . */
static struct resource * __devinit
find_free_bus_resource ( struct pci_bus * bus , unsigned long type )
{
int i ;
struct resource * r ;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_PREFETCH ;
for ( i = 0 ; i < PCI_BUS_NUM_RESOURCES ; i + + ) {
r = bus - > resource [ i ] ;
2005-06-15 18:59:27 +04:00
if ( r = = & ioport_resource | | r = = & iomem_resource )
continue ;
2005-04-17 02:20:36 +04:00
if ( r & & ( r - > flags & type_mask ) = = type & & ! r - > parent )
return r ;
}
return NULL ;
}
/* 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 __devinit
pbus_size_io ( struct pci_bus * bus )
{
struct pci_dev * dev ;
struct resource * b_res = find_free_bus_resource ( bus , IORESOURCE_IO ) ;
unsigned long size = 0 , size1 = 0 ;
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 ;
r_size = r - > end - r - > start + 1 ;
if ( r_size < 0x400 )
/* Might be re-aligned for ISA */
size + = r_size ;
else
size1 + = r_size ;
}
}
/* 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 = ROUND_UP ( size + size1 , 4096 ) ;
if ( ! size ) {
b_res - > flags = 0 ;
return ;
}
/* Alignment of the IO window is always 4K */
b_res - > start = 4096 ;
b_res - > end = b_res - > start + size - 1 ;
}
/* Calculate the size of the bus and minimal alignment which
guarantees that all child resources fit in this size . */
static int __devinit
pbus_size_mem ( struct pci_bus * bus , unsigned long mask , unsigned long type )
{
struct pci_dev * dev ;
unsigned long min_align , align , size ;
unsigned long aligns [ 12 ] ; /* Alignments from 1Mb to 2Gb */
int order , max_order ;
struct resource * b_res = find_free_bus_resource ( bus , type ) ;
if ( ! b_res )
return 0 ;
memset ( aligns , 0 , sizeof ( aligns ) ) ;
max_order = 0 ;
size = 0 ;
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 & mask ) ! = type )
continue ;
r_size = r - > end - r - > start + 1 ;
/* For bridges size != alignment */
align = ( i < PCI_BRIDGE_RESOURCES ) ? r_size : r - > start ;
order = __ffs ( align ) - 20 ;
if ( order > 11 ) {
printk ( KERN_WARNING " PCI: region %s/%d "
2006-06-13 02:14:29 +04:00
" too large: %llx-%llx \n " ,
pci_name ( dev ) , i ,
( unsigned long long ) r - > start ,
( unsigned long long ) r - > end ) ;
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 ;
}
}
align = 0 ;
min_align = 0 ;
for ( order = 0 ; order < = max_order ; order + + ) {
unsigned long align1 = 1UL < < ( order + 20 ) ;
if ( ! align )
min_align = align1 ;
else if ( ROUND_UP ( align + min_align , min_align ) < align1 )
min_align = align1 > > 1 ;
align + = aligns [ order ] ;
}
size = ROUND_UP ( size , min_align ) ;
if ( ! size ) {
b_res - > flags = 0 ;
return 1 ;
}
b_res - > start = min_align ;
b_res - > end = size + min_align - 1 ;
return 1 ;
}
static void __devinit
pci_bus_size_cardbus ( struct pci_bus * bus )
{
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 .
*/
2007-02-06 03:36:06 +03:00
b_res [ 0 ] . start = pci_cardbus_io_size ;
b_res [ 0 ] . end = b_res [ 0 ] . start + pci_cardbus_io_size - 1 ;
2005-04-17 02:20:36 +04:00
b_res [ 0 ] . flags | = IORESOURCE_IO ;
2007-02-06 03:36:06 +03:00
b_res [ 1 ] . start = pci_cardbus_io_size ;
b_res [ 1 ] . end = b_res [ 1 ] . start + pci_cardbus_io_size - 1 ;
2005-04-17 02:20:36 +04:00
b_res [ 1 ] . flags | = IORESOURCE_IO ;
/*
* 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 ) {
2007-02-06 03:36:06 +03:00
b_res [ 2 ] . start = pci_cardbus_mem_size ;
b_res [ 2 ] . end = b_res [ 2 ] . start + pci_cardbus_mem_size - 1 ;
2005-04-17 02:20:36 +04:00
b_res [ 2 ] . flags | = IORESOURCE_MEM | IORESOURCE_PREFETCH ;
2007-02-06 03:36:06 +03:00
b_res [ 3 ] . start = pci_cardbus_mem_size ;
b_res [ 3 ] . end = b_res [ 3 ] . start + pci_cardbus_mem_size - 1 ;
2005-04-17 02:20:36 +04:00
b_res [ 3 ] . flags | = IORESOURCE_MEM ;
} else {
2007-02-06 03:36:06 +03:00
b_res [ 3 ] . start = pci_cardbus_mem_size * 2 ;
b_res [ 3 ] . end = b_res [ 3 ] . start + pci_cardbus_mem_size * 2 - 1 ;
2005-04-17 02:20:36 +04:00
b_res [ 3 ] . flags | = IORESOURCE_MEM ;
}
}
void __devinit
pci_bus_size_bridges ( struct pci_bus * bus )
{
struct pci_dev * dev ;
unsigned long mask , prefmask ;
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 :
pci_bus_size_cardbus ( b ) ;
break ;
case PCI_CLASS_BRIDGE_PCI :
default :
pci_bus_size_bridges ( b ) ;
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 ) ;
default :
pbus_size_io ( bus ) ;
/* 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 ;
if ( pbus_size_mem ( bus , prefmask , prefmask ) )
mask = prefmask ; /* Success, size non-prefetch only. */
pbus_size_mem ( bus , mask , IORESOURCE_MEM ) ;
break ;
}
}
EXPORT_SYMBOL ( pci_bus_size_bridges ) ;
void __devinit
pci_bus_assign_resources ( struct pci_bus * bus )
{
struct pci_bus * b ;
struct pci_dev * dev ;
pbus_assign_resources_sorted ( bus ) ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
b = dev - > subordinate ;
if ( ! b )
continue ;
pci_bus_assign_resources ( b ) ;
switch ( dev - > class > > 8 ) {
case PCI_CLASS_BRIDGE_PCI :
pci_setup_bridge ( b ) ;
break ;
case PCI_CLASS_BRIDGE_CARDBUS :
pci_setup_cardbus ( b ) ;
break ;
default :
printk ( KERN_INFO " PCI: not setting up bridge %s "
" for bus %d \n " , pci_name ( dev ) , b - > number ) ;
break ;
}
}
}
EXPORT_SYMBOL ( pci_bus_assign_resources ) ;
void __init
pci_assign_unassigned_resources ( void )
{
struct pci_bus * bus ;
/* Depth first, calculate sizes and alignments of all
subordinate buses . */
list_for_each_entry ( bus , & pci_root_buses , node ) {
pci_bus_size_bridges ( bus ) ;
}
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry ( bus , & pci_root_buses , node ) {
pci_bus_assign_resources ( bus ) ;
pci_enable_bridges ( bus ) ;
}
}