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>
2005-04-17 02:20:36 +04:00
# include "pci.h"
2007-10-04 02:56:51 +04:00
struct pci_root_info {
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 ;
2007-11-17 18:27:01 +03:00
if ( info - > res_num > = PCI_BUS_NUM_RESOURCES )
return AE_OK ;
2007-10-04 02:56:51 +04:00
status = resource_to_addr ( acpi_res , & addr ) ;
if ( ACPI_SUCCESS ( status ) )
info - > res_num + + ;
return AE_OK ;
}
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 ;
2007-11-17 18:27:01 +03:00
if ( info - > res_num > = PCI_BUS_NUM_RESOURCES )
return AE_OK ;
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 ;
res = & info - > res [ info - > res_num ] ;
res - > name = info - > name ;
res - > flags = flags ;
res - > start = addr . minimum + addr . translation_offset ;
res - > end = res - > start + addr . address_length - 1 ;
res - > child = NULL ;
if ( insert_resource ( root , res ) ) {
printk ( KERN_ERR " PCI: Failed to allocate 0x%lx-0x%lx "
" from %s for %s \n " , ( unsigned long ) res - > start ,
( unsigned long ) res - > end , root - > name , info - > name ) ;
} else {
info - > bus - > resource [ info - > res_num ] = res ;
info - > res_num + + ;
}
return AE_OK ;
}
static void
adjust_transparent_bridge_resources ( struct pci_bus * bus )
{
struct pci_dev * dev ;
list_for_each_entry ( dev , & bus - > devices , bus_list ) {
int i ;
u16 class = dev - > class > > 8 ;
if ( class = = PCI_CLASS_BRIDGE_PCI & & dev - > transparent ) {
for ( i = 3 ; i < PCI_BUS_NUM_RESOURCES ; i + + )
dev - > subordinate - > resource [ i ] =
dev - > bus - > resource [ i - 3 ] ;
}
}
}
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 ;
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 ) ;
if ( info . res_num )
adjust_transparent_bridge_resources ( bus ) ;
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 ) {
printk ( KERN_WARNING " PCI: Multiple domains not supported "
" (dom %d, bus %d) \n " , domain , busnum ) ;
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 ) {
printk ( KERN_ERR " PCI: OOM, not probing PCI bus %02x \n " , busnum ) ;
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 ) ;
} else
bus = pci_scan_bus_parented ( NULL , busnum , & pci_root_ops , sd ) ;
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 )
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
printk ( KERN_DEBUG " bus %02x -> pxm %d -> node %d \n " ,
2008-04-19 12:30:16 +04:00
busnum , pxm , node ) ;
# else
printk ( KERN_DEBUG " bus %02x -> node %d \n " ,
busnum , 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
if ( bus & & ( pci_probe & PCI_USE__CRS ) )
2008-02-09 01:00:52 +03:00
get_current_resources ( device , busnum , domain , bus ) ;
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
# ifdef CONFIG_X86_IO_APIC
if ( acpi_ioapic )
print_IO_APIC ( ) ;
# endif
return 0 ;
}