2005-04-17 02:20:36 +04:00
# include <linux/pci.h>
# include <linux/acpi.h>
# include <linux/init.h>
2005-09-30 20:34:42 +04:00
# include <linux/irq.h>
2007-10-04 02:56:14 +04:00
# include <linux/dmi.h>
2005-09-12 20:49:24 +04:00
# include <asm/numa.h>
2008-12-27 16:02:28 +03:00
# include <asm/pci_x86.h>
2005-04-17 02:20:36 +04:00
2007-10-04 02:56:51 +04:00
struct pci_root_info {
2009-10-07 01:33:49 +04:00
struct acpi_device * bridge ;
2007-10-04 02:56:51 +04:00
char * name ;
unsigned int res_num ;
struct resource * res ;
struct pci_bus * bus ;
int busnum ;
} ;
static acpi_status
resource_to_addr ( struct acpi_resource * resource ,
struct acpi_resource_address64 * addr )
{
acpi_status status ;
status = acpi_resource_to_address64 ( resource , addr ) ;
if ( ACPI_SUCCESS ( status ) & &
( addr - > resource_type = = ACPI_MEMORY_RANGE | |
addr - > resource_type = = ACPI_IO_RANGE ) & &
addr - > address_length > 0 & &
addr - > producer_consumer = = ACPI_PRODUCER ) {
return AE_OK ;
}
return AE_ERROR ;
}
static acpi_status
count_resource ( struct acpi_resource * acpi_res , void * data )
{
struct pci_root_info * info = data ;
struct acpi_resource_address64 addr ;
acpi_status status ;
status = resource_to_addr ( acpi_res , & addr ) ;
if ( ACPI_SUCCESS ( status ) )
info - > res_num + + ;
return AE_OK ;
}
2009-05-27 23:41:44 +04:00
static int
bus_has_transparent_bridge ( struct pci_bus * bus )
{
struct pci_dev * dev ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
u16 class = dev - > class > > 8 ;
if ( class = = PCI_CLASS_BRIDGE_PCI & & dev - > transparent )
return true ;
}
return false ;
}
2009-11-04 20:39:18 +03:00
static void
align_resource ( struct acpi_device * bridge , struct resource * res )
{
int align = ( res - > flags & IORESOURCE_MEM ) ? 16 : 4 ;
/*
* Host bridge windows are not BARs , but the decoders on the PCI side
* that claim this address space have starting alignment and length
* constraints , so fix any obvious BIOS goofs .
*/
if ( res - > start & ( align - 1 ) ) {
dev_printk ( KERN_DEBUG , & bridge - > dev ,
" host bridge window %pR invalid; "
" aligning start to %d-byte boundary \n " , res , align ) ;
res - > start & = ~ ( align - 1 ) ;
}
if ( ( res - > end + 1 ) & ( align - 1 ) ) {
dev_printk ( KERN_DEBUG , & bridge - > dev ,
" host bridge window %pR invalid; "
" aligning end to %d-byte boundary \n " , res , align ) ;
res - > end = roundup ( res - > end , align ) - 1 ;
}
}
2007-10-04 02:56:51 +04:00
static acpi_status
setup_resource ( struct acpi_resource * acpi_res , void * data )
{
struct pci_root_info * info = data ;
struct resource * res ;
struct acpi_resource_address64 addr ;
acpi_status status ;
unsigned long flags ;
struct resource * root ;
2009-05-27 23:41:44 +04:00
int max_root_bus_resources = PCI_BUS_NUM_RESOURCES ;
2009-06-25 06:01:19 +04:00
u64 start , end ;
if ( bus_has_transparent_bridge ( info - > bus ) )
max_root_bus_resources - = 3 ;
2007-11-17 18:27:01 +03:00
2007-10-04 02:56:51 +04:00
status = resource_to_addr ( acpi_res , & addr ) ;
if ( ! ACPI_SUCCESS ( status ) )
return AE_OK ;
if ( addr . resource_type = = ACPI_MEMORY_RANGE ) {
root = & iomem_resource ;
flags = IORESOURCE_MEM ;
if ( addr . info . mem . caching = = ACPI_PREFETCHABLE_MEMORY )
flags | = IORESOURCE_PREFETCH ;
} else if ( addr . resource_type = = ACPI_IO_RANGE ) {
root = & ioport_resource ;
flags = IORESOURCE_IO ;
} else
return AE_OK ;
2009-06-25 06:01:19 +04:00
start = addr . minimum + addr . translation_offset ;
end = start + addr . address_length - 1 ;
2009-05-27 23:41:44 +04:00
if ( info - > res_num > = max_root_bus_resources ) {
2009-11-04 20:39:13 +03:00
if ( pci_probe & PCI_USE__CRS )
printk ( KERN_WARNING " PCI: Failed to allocate "
" 0x%lx-0x%lx from %s for %s due to _CRS "
" returning more than %d resource descriptors \n " ,
( unsigned long ) start , ( unsigned long ) end ,
root - > name , info - > name , max_root_bus_resources ) ;
2009-05-27 23:41:44 +04:00
return AE_OK ;
}
2009-06-25 06:01:19 +04:00
res = & info - > res [ info - > res_num ] ;
res - > name = info - > name ;
res - > flags = flags ;
res - > start = start ;
res - > end = end ;
res - > child = NULL ;
2009-11-04 20:39:18 +03:00
align_resource ( info - > bridge , res ) ;
2009-06-25 06:01:19 +04:00
2009-11-04 20:39:13 +03:00
if ( ! ( pci_probe & PCI_USE__CRS ) ) {
dev_printk ( KERN_DEBUG , & info - > bridge - > dev ,
" host bridge window %pR (ignored) \n " , res ) ;
return AE_OK ;
}
2007-10-04 02:56:51 +04:00
if ( insert_resource ( root , res ) ) {
2009-10-27 22:26:47 +03:00
dev_err ( & info - > bridge - > dev ,
" can't allocate host bridge window %pR \n " , res ) ;
2007-10-04 02:56:51 +04:00
} else {
info - > bus - > resource [ info - > res_num ] = res ;
info - > res_num + + ;
2009-10-07 01:33:49 +04:00
if ( addr . translation_offset )
2009-10-27 22:26:47 +03:00
dev_info ( & info - > bridge - > dev , " host bridge window %pR "
2009-10-07 01:33:49 +04:00
" (PCI address [%#llx-%#llx]) \n " ,
res , res - > start - addr . translation_offset ,
res - > end - addr . translation_offset ) ;
else
dev_info ( & info - > bridge - > dev ,
2009-10-27 22:26:47 +03:00
" host bridge window %pR \n " , res ) ;
2007-10-04 02:56:51 +04:00
}
return AE_OK ;
}
static void
get_current_resources ( struct acpi_device * device , int busnum ,
2008-02-09 01:00:52 +03:00
int domain , struct pci_bus * bus )
2007-10-04 02:56:51 +04:00
{
struct pci_root_info info ;
size_t size ;
2009-11-04 20:39:13 +03:00
if ( ! ( pci_probe & PCI_USE__CRS ) )
dev_info ( & device - > dev ,
" ignoring host bridge windows from ACPI; "
" boot with \" pci=use_crs \" to use them \n " ) ;
2009-10-07 01:33:49 +04:00
info . bridge = device ;
2007-10-04 02:56:51 +04:00
info . bus = bus ;
info . res_num = 0 ;
acpi_walk_resources ( device - > handle , METHOD_NAME__CRS , count_resource ,
& info ) ;
if ( ! info . res_num )
return ;
size = sizeof ( * info . res ) * info . res_num ;
info . res = kmalloc ( size , GFP_KERNEL ) ;
if ( ! info . res )
goto res_alloc_fail ;
2008-02-09 01:00:52 +03:00
info . name = kmalloc ( 16 , GFP_KERNEL ) ;
2007-10-04 02:56:51 +04:00
if ( ! info . name )
goto name_alloc_fail ;
2008-02-09 01:00:52 +03:00
sprintf ( info . name , " PCI Bus %04x:%02x " , domain , busnum ) ;
2007-10-04 02:56:51 +04:00
info . res_num = 0 ;
acpi_walk_resources ( device - > handle , METHOD_NAME__CRS , setup_resource ,
& info ) ;
return ;
name_alloc_fail :
kfree ( info . res ) ;
res_alloc_fail :
return ;
}
2005-04-17 02:20:36 +04:00
struct pci_bus * __devinit pci_acpi_scan_root ( struct acpi_device * device , int domain , int busnum )
{
2005-09-12 20:49:24 +04:00
struct pci_bus * bus ;
2007-07-22 01:23:39 +04:00
struct pci_sysdata * sd ;
x86: get mp_bus_to_node early
Currently, on an amd k8 system with multi ht chains, the numa_node of
pci devices under /sys/devices/pci0000:80/* is always 0, even if that
chain is on node 1 or 2 or 3.
Workaround: pcibus_to_node(bus) is used when we want to get the node that
pci_device is on.
In struct device, we already have numa_node member, and we could use
dev_to_node()/set_dev_node() to get and set numa_node in the device.
set_dev_node is called in pci_device_add() with pcibus_to_node(bus),
and pcibus_to_node uses bus->sysdata for nodeid.
The problem is when pci_add_device is called, bus->sysdata is not assigned
correct nodeid yet. The result is that numa_node will always be 0.
pcibios_scan_root and pci_scan_root could take sysdata. So we need to get
mp_bus_to_node mapping before these two are called, and thus
get_mp_bus_to_node could get correct node for sysdata in root bus.
In scanning of the root bus, all child busses will take parent bus sysdata.
So all pci_device->dev.numa_node will be assigned correctly and automatically.
Later we could use dev_to_node(&pci_dev->dev) to get numa_node, and we
could also could make other bus specific device get the correct numa_node
too.
This is an updated version of pci_sysdata and Jeff's pci_domain patch.
[ mingo@elte.hu: build fix ]
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2008-02-19 14:20:09 +03:00
int node ;
# ifdef CONFIG_ACPI_NUMA
2007-07-22 01:23:39 +04:00
int pxm ;
x86: get mp_bus_to_node early
Currently, on an amd k8 system with multi ht chains, the numa_node of
pci devices under /sys/devices/pci0000:80/* is always 0, even if that
chain is on node 1 or 2 or 3.
Workaround: pcibus_to_node(bus) is used when we want to get the node that
pci_device is on.
In struct device, we already have numa_node member, and we could use
dev_to_node()/set_dev_node() to get and set numa_node in the device.
set_dev_node is called in pci_device_add() with pcibus_to_node(bus),
and pcibus_to_node uses bus->sysdata for nodeid.
The problem is when pci_add_device is called, bus->sysdata is not assigned
correct nodeid yet. The result is that numa_node will always be 0.
pcibios_scan_root and pci_scan_root could take sysdata. So we need to get
mp_bus_to_node mapping before these two are called, and thus
get_mp_bus_to_node could get correct node for sysdata in root bus.
In scanning of the root bus, all child busses will take parent bus sysdata.
So all pci_device->dev.numa_node will be assigned correctly and automatically.
Later we could use dev_to_node(&pci_dev->dev) to get numa_node, and we
could also could make other bus specific device get the correct numa_node
too.
This is an updated version of pci_sysdata and Jeff's pci_domain patch.
[ mingo@elte.hu: build fix ]
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2008-02-19 14:20:09 +03:00
# endif
2007-07-22 01:23:39 +04:00
2007-10-12 00:58:30 +04:00
if ( domain & & ! pci_domains_supported ) {
2009-11-04 20:32:47 +03:00
printk ( KERN_WARNING " pci_bus %04x:%02x: "
" ignored (multiple domains not supported) \n " ,
domain , busnum ) ;
2007-10-12 00:58:30 +04:00
return NULL ;
}
x86: get mp_bus_to_node early
Currently, on an amd k8 system with multi ht chains, the numa_node of
pci devices under /sys/devices/pci0000:80/* is always 0, even if that
chain is on node 1 or 2 or 3.
Workaround: pcibus_to_node(bus) is used when we want to get the node that
pci_device is on.
In struct device, we already have numa_node member, and we could use
dev_to_node()/set_dev_node() to get and set numa_node in the device.
set_dev_node is called in pci_device_add() with pcibus_to_node(bus),
and pcibus_to_node uses bus->sysdata for nodeid.
The problem is when pci_add_device is called, bus->sysdata is not assigned
correct nodeid yet. The result is that numa_node will always be 0.
pcibios_scan_root and pci_scan_root could take sysdata. So we need to get
mp_bus_to_node mapping before these two are called, and thus
get_mp_bus_to_node could get correct node for sysdata in root bus.
In scanning of the root bus, all child busses will take parent bus sysdata.
So all pci_device->dev.numa_node will be assigned correctly and automatically.
Later we could use dev_to_node(&pci_dev->dev) to get numa_node, and we
could also could make other bus specific device get the correct numa_node
too.
This is an updated version of pci_sysdata and Jeff's pci_domain patch.
[ mingo@elte.hu: build fix ]
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2008-02-19 14:20:09 +03:00
node = - 1 ;
# ifdef CONFIG_ACPI_NUMA
pxm = acpi_get_pxm ( device - > handle ) ;
if ( pxm > = 0 )
node = pxm_to_node ( pxm ) ;
if ( node ! = - 1 )
set_mp_bus_to_node ( busnum , node ) ;
else
# endif
node = get_mp_bus_to_node ( busnum ) ;
2008-02-20 23:41:52 +03:00
if ( node ! = - 1 & & ! node_online ( node ) )
node = - 1 ;
x86: get mp_bus_to_node early
Currently, on an amd k8 system with multi ht chains, the numa_node of
pci devices under /sys/devices/pci0000:80/* is always 0, even if that
chain is on node 1 or 2 or 3.
Workaround: pcibus_to_node(bus) is used when we want to get the node that
pci_device is on.
In struct device, we already have numa_node member, and we could use
dev_to_node()/set_dev_node() to get and set numa_node in the device.
set_dev_node is called in pci_device_add() with pcibus_to_node(bus),
and pcibus_to_node uses bus->sysdata for nodeid.
The problem is when pci_add_device is called, bus->sysdata is not assigned
correct nodeid yet. The result is that numa_node will always be 0.
pcibios_scan_root and pci_scan_root could take sysdata. So we need to get
mp_bus_to_node mapping before these two are called, and thus
get_mp_bus_to_node could get correct node for sysdata in root bus.
In scanning of the root bus, all child busses will take parent bus sysdata.
So all pci_device->dev.numa_node will be assigned correctly and automatically.
Later we could use dev_to_node(&pci_dev->dev) to get numa_node, and we
could also could make other bus specific device get the correct numa_node
too.
This is an updated version of pci_sysdata and Jeff's pci_domain patch.
[ mingo@elte.hu: build fix ]
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2008-02-19 14:20:09 +03:00
2007-07-22 01:23:39 +04:00
/* Allocate per-root-bus (not per bus) arch-specific data.
* TODO : leak ; this memory is never freed .
* It ' s arguable whether it ' s worth the trouble to care .
*/
sd = kzalloc ( sizeof ( * sd ) , GFP_KERNEL ) ;
if ( ! sd ) {
2009-11-04 20:32:47 +03:00
printk ( KERN_WARNING " pci_bus %04x:%02x: "
" ignored (out of memory) \n " , domain , busnum ) ;
2007-07-22 01:23:39 +04:00
return NULL ;
}
2005-09-12 20:49:24 +04:00
2007-10-12 00:58:30 +04:00
sd - > domain = domain ;
x86: get mp_bus_to_node early
Currently, on an amd k8 system with multi ht chains, the numa_node of
pci devices under /sys/devices/pci0000:80/* is always 0, even if that
chain is on node 1 or 2 or 3.
Workaround: pcibus_to_node(bus) is used when we want to get the node that
pci_device is on.
In struct device, we already have numa_node member, and we could use
dev_to_node()/set_dev_node() to get and set numa_node in the device.
set_dev_node is called in pci_device_add() with pcibus_to_node(bus),
and pcibus_to_node uses bus->sysdata for nodeid.
The problem is when pci_add_device is called, bus->sysdata is not assigned
correct nodeid yet. The result is that numa_node will always be 0.
pcibios_scan_root and pci_scan_root could take sysdata. So we need to get
mp_bus_to_node mapping before these two are called, and thus
get_mp_bus_to_node could get correct node for sysdata in root bus.
In scanning of the root bus, all child busses will take parent bus sysdata.
So all pci_device->dev.numa_node will be assigned correctly and automatically.
Later we could use dev_to_node(&pci_dev->dev) to get numa_node, and we
could also could make other bus specific device get the correct numa_node
too.
This is an updated version of pci_sysdata and Jeff's pci_domain patch.
[ mingo@elte.hu: build fix ]
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2008-02-19 14:20:09 +03:00
sd - > node = node ;
2008-04-16 01:34:49 +04:00
/*
* Maybe the desired pci bus has been already scanned . In such case
* it is unnecessary to scan the pci bus with the given domain , busnum .
*/
bus = pci_find_bus ( domain , busnum ) ;
if ( bus ) {
/*
* If the desired bus exits , the content of bus - > sysdata will
* be replaced by sd .
*/
memcpy ( bus - > sysdata , sd , sizeof ( * sd ) ) ;
kfree ( sd ) ;
2009-06-25 07:00:12 +04:00
} else {
bus = pci_create_bus ( NULL , busnum , & pci_root_ops , sd ) ;
if ( bus ) {
2009-11-04 20:39:13 +03:00
get_current_resources ( device , busnum , domain , bus ) ;
2009-06-25 07:00:12 +04:00
bus - > subordinate = pci_scan_child_bus ( bus ) ;
}
}
2007-07-22 01:23:39 +04:00
if ( ! bus )
kfree ( sd ) ;
2008-04-19 12:30:16 +04:00
if ( bus & & node ! = - 1 ) {
2005-09-12 20:49:24 +04:00
# ifdef CONFIG_ACPI_NUMA
2008-04-19 12:30:16 +04:00
if ( pxm > = 0 )
2008-12-19 02:34:51 +03:00
dev_printk ( KERN_DEBUG , & bus - > dev ,
" on NUMA node %d (pxm %d) \n " , node , pxm ) ;
2008-04-19 12:30:16 +04:00
# else
2008-12-19 02:34:51 +03:00
dev_printk ( KERN_DEBUG , & bus - > dev , " on NUMA node %d \n " , node ) ;
2005-09-12 20:49:24 +04:00
# endif
2008-04-19 12:30:16 +04:00
}
2007-10-04 02:56:51 +04:00
2005-09-12 20:49:24 +04:00
return bus ;
2005-04-17 02:20:36 +04:00
}
2008-07-03 00:50:29 +04:00
int __init pci_acpi_init ( void )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev = NULL ;
if ( pcibios_scanned )
return 0 ;
if ( acpi_noirq )
return 0 ;
printk ( KERN_INFO " PCI: Using ACPI for IRQ routing \n " ) ;
acpi_irq_penalty_init ( ) ;
pcibios_scanned + + ;
pcibios_enable_irq = acpi_pci_irq_enable ;
2005-07-28 07:02:00 +04:00
pcibios_disable_irq = acpi_pci_irq_disable ;
2005-04-17 02:20:36 +04:00
if ( pci_routeirq ) {
/*
* PCI IRQ routing is set up by pci_enable_device ( ) , but we
* also do it here in case there are still broken drivers that
* don ' t use pci_enable_device ( ) .
*/
printk ( KERN_INFO " PCI: Routing PCI interrupts for all devices because \" pci=routeirq \" specified \n " ) ;
2005-11-07 10:39:36 +03:00
for_each_pci_dev ( dev )
2005-04-17 02:20:36 +04:00
acpi_pci_irq_enable ( dev ) ;
2008-02-18 19:44:13 +03:00
}
2005-04-17 02:20:36 +04:00
return 0 ;
}