2005-04-16 15:20:36 -07:00
/*
* mmconfig . c - Low - level direct PCI config space access via MMCONFIG
*
* This is an 64 bit optimized version that always keeps the full mmconfig
* space mapped . This allows lockless config space operation .
*/
# include <linux/pci.h>
# include <linux/init.h>
2005-06-23 17:35:56 -07:00
# include <linux/acpi.h>
2005-12-12 22:17:11 -08:00
# include <linux/bitmap.h>
2006-04-07 19:49:30 +02:00
# include <asm/e820.h>
2005-04-16 15:20:36 -07:00
# include "pci.h"
2006-06-15 04:41:52 -04:00
/* aperture is up to 256MB but BIOS may reserve less */
# define MMCONFIG_APER_MIN (2 * 1024*1024)
# define MMCONFIG_APER_MAX (256 * 1024*1024)
2006-04-07 19:50:12 +02:00
/* Verify the first 16 busses. We assume that systems with more busses
get MCFG right . */
# define MAX_CHECK_BUS 16
2005-04-16 15:20:36 -07:00
2006-04-07 19:50:12 +02:00
static DECLARE_BITMAP ( fallback_slots , 32 * MAX_CHECK_BUS ) ;
2005-12-12 22:17:11 -08:00
2005-04-16 15:20:36 -07:00
/* Static virtual mapping of the MMCONFIG aperture */
2005-06-23 17:35:56 -07:00
struct mmcfg_virt {
struct acpi_table_mcfg_config * cfg ;
2005-12-15 09:17:44 +00:00
char __iomem * virt ;
2005-06-23 17:35:56 -07:00
} ;
static struct mmcfg_virt * pci_mmcfg_virt ;
2005-04-16 15:20:36 -07:00
2005-12-15 09:17:44 +00:00
static char __iomem * get_virt ( unsigned int seg , unsigned bus )
2005-04-16 15:20:36 -07:00
{
2005-06-23 17:35:56 -07:00
int cfg_num = - 1 ;
struct acpi_table_mcfg_config * cfg ;
while ( 1 ) {
+ + cfg_num ;
2006-01-27 02:03:50 +01:00
if ( cfg_num > = pci_mmcfg_config_num )
break ;
2005-06-23 17:35:56 -07:00
cfg = pci_mmcfg_virt [ cfg_num ] . cfg ;
if ( cfg - > pci_segment_group_number ! = seg )
continue ;
if ( ( cfg - > start_bus_number < = bus ) & &
( cfg - > end_bus_number > = bus ) )
return pci_mmcfg_virt [ cfg_num ] . virt ;
}
2006-01-27 02:03:50 +01:00
/* Handle more broken MCFG tables on Asus etc.
They only contain a single entry for bus 0 - 0. Assume
this applies to all busses . */
cfg = & pci_mmcfg_config [ 0 ] ;
if ( pci_mmcfg_config_num = = 1 & &
cfg - > pci_segment_group_number = = 0 & &
( cfg - > start_bus_number | cfg - > end_bus_number ) = = 0 )
2006-02-03 21:51:29 +01:00
return pci_mmcfg_virt [ 0 ] . virt ;
2006-01-27 02:03:50 +01:00
/* Fall back to type 0 */
2006-02-03 20:28:01 -05:00
return NULL ;
2005-06-23 17:35:56 -07:00
}
2005-12-15 09:17:44 +00:00
static char __iomem * pci_dev_base ( unsigned int seg , unsigned int bus , unsigned int devfn )
2005-06-23 17:35:56 -07:00
{
2005-12-15 09:17:44 +00:00
char __iomem * addr ;
2006-04-07 19:50:12 +02:00
if ( seg = = 0 & & bus < MAX_CHECK_BUS & &
test_bit ( 32 * bus + PCI_SLOT ( devfn ) , fallback_slots ) )
2005-12-12 22:17:11 -08:00
return NULL ;
addr = get_virt ( seg , bus ) ;
2005-12-12 22:17:10 -08:00
if ( ! addr )
return NULL ;
return addr + ( ( bus < < 20 ) | ( devfn < < 12 ) ) ;
2005-04-16 15:20:36 -07:00
}
static int pci_mmcfg_read ( unsigned int seg , unsigned int bus ,
unsigned int devfn , int reg , int len , u32 * value )
{
2005-12-15 09:17:44 +00:00
char __iomem * addr ;
2005-04-16 15:20:36 -07:00
2005-12-12 22:17:10 -08:00
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
2006-04-11 12:54:48 +02:00
if ( unlikely ( ( bus > 255 ) | | ( devfn > 255 ) | | ( reg > 4095 ) ) ) {
2006-04-07 19:50:15 +02:00
* value = - 1 ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2006-04-07 19:50:15 +02:00
}
2005-04-16 15:20:36 -07:00
2005-12-12 22:17:10 -08:00
addr = pci_dev_base ( seg , bus , devfn ) ;
if ( ! addr )
return pci_conf1_read ( seg , bus , devfn , reg , len , value ) ;
2005-04-16 15:20:36 -07:00
switch ( len ) {
case 1 :
* value = readb ( addr + reg ) ;
break ;
case 2 :
* value = readw ( addr + reg ) ;
break ;
case 4 :
* value = readl ( addr + reg ) ;
break ;
}
return 0 ;
}
static int pci_mmcfg_write ( unsigned int seg , unsigned int bus ,
unsigned int devfn , int reg , int len , u32 value )
{
2005-12-15 09:17:44 +00:00
char __iomem * addr ;
2005-04-16 15:20:36 -07:00
2005-12-12 22:17:10 -08:00
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
2005-04-16 15:20:36 -07:00
if ( unlikely ( ( bus > 255 ) | | ( devfn > 255 ) | | ( reg > 4095 ) ) )
return - EINVAL ;
2005-12-12 22:17:10 -08:00
addr = pci_dev_base ( seg , bus , devfn ) ;
if ( ! addr )
return pci_conf1_write ( seg , bus , devfn , reg , len , value ) ;
2005-04-16 15:20:36 -07:00
switch ( len ) {
case 1 :
writeb ( value , addr + reg ) ;
break ;
case 2 :
writew ( value , addr + reg ) ;
break ;
case 4 :
writel ( value , addr + reg ) ;
break ;
}
return 0 ;
}
static struct pci_raw_ops pci_mmcfg = {
. read = pci_mmcfg_read ,
. write = pci_mmcfg_write ,
} ;
2005-12-12 22:17:11 -08:00
/* K8 systems have some devices (typically in the builtin northbridge)
that are only accessible using type1
Normally this can be expressed in the MCFG by not listing them
and assigning suitable _SEGs , but this isn ' t implemented in some BIOS .
Instead try to discover all devices on bus 0 that are unreachable using MM
2006-04-07 19:50:12 +02:00
and fallback for them . */
2005-12-12 22:17:11 -08:00
static __init void unreachable_devices ( void )
{
2006-04-07 19:50:12 +02:00
int i , k ;
/* Use the max bus number from ACPI here? */
2006-04-11 12:54:51 +02:00
for ( k = 0 ; k < MAX_CHECK_BUS ; k + + ) {
2006-04-07 19:50:12 +02:00
for ( i = 0 ; i < 32 ; i + + ) {
u32 val1 ;
char __iomem * addr ;
pci_conf1_read ( 0 , k , PCI_DEVFN ( i , 0 ) , 0 , 4 , & val1 ) ;
if ( val1 = = 0xffffffff )
continue ;
addr = pci_dev_base ( 0 , k , PCI_DEVFN ( i , 0 ) ) ;
if ( addr = = NULL | | readl ( addr ) ! = val1 ) {
set_bit ( i + 32 * k , fallback_slots ) ;
printk ( KERN_NOTICE
" PCI: No mmconfig possible on device %x:%x \n " ,
k , i ) ;
}
2005-12-12 22:17:11 -08:00
}
}
}
2006-03-24 03:15:11 -08:00
void __init pci_mmcfg_init ( void )
2005-04-16 15:20:36 -07:00
{
2005-06-23 17:35:56 -07:00
int i ;
2005-04-16 15:20:36 -07:00
if ( ( pci_probe & PCI_PROBE_MMCONF ) = = 0 )
2006-03-24 03:15:11 -08:00
return ;
2005-06-23 17:35:56 -07:00
acpi_table_parse ( ACPI_MCFG , acpi_parse_mcfg ) ;
if ( ( pci_mmcfg_config_num = = 0 ) | |
( pci_mmcfg_config = = NULL ) | |
( pci_mmcfg_config [ 0 ] . base_address = = 0 ) )
2006-03-24 03:15:11 -08:00
return ;
2005-04-16 15:20:36 -07:00
2006-04-07 19:49:30 +02:00
if ( ! e820_all_mapped ( pci_mmcfg_config [ 0 ] . base_address ,
2006-06-15 04:41:52 -04:00
pci_mmcfg_config [ 0 ] . base_address + MMCONFIG_APER_MIN ,
2006-04-07 19:49:30 +02:00
E820_RESERVED ) ) {
2006-06-15 04:41:52 -04:00
printk ( KERN_ERR " PCI: BIOS Bug: MCFG area at %x is not E820-reserved \n " ,
pci_mmcfg_config [ 0 ] . base_address ) ;
2006-04-07 19:49:30 +02:00
printk ( KERN_ERR " PCI: Not using MMCONFIG. \n " ) ;
return ;
}
2005-04-16 15:20:36 -07:00
/* RED-PEN i386 doesn't do _nocache right now */
2005-06-23 17:35:56 -07:00
pci_mmcfg_virt = kmalloc ( sizeof ( * pci_mmcfg_virt ) * pci_mmcfg_config_num , GFP_KERNEL ) ;
if ( pci_mmcfg_virt = = NULL ) {
printk ( " PCI: Can not allocate memory for mmconfig structures \n " ) ;
2006-03-24 03:15:11 -08:00
return ;
2005-06-23 17:35:56 -07:00
}
for ( i = 0 ; i < pci_mmcfg_config_num ; + + i ) {
pci_mmcfg_virt [ i ] . cfg = & pci_mmcfg_config [ i ] ;
2006-06-15 04:41:52 -04:00
pci_mmcfg_virt [ i ] . virt = ioremap_nocache ( pci_mmcfg_config [ i ] . base_address ,
MMCONFIG_APER_MAX ) ;
2005-06-23 17:35:56 -07:00
if ( ! pci_mmcfg_virt [ i ] . virt ) {
printk ( " PCI: Cannot map mmconfig aperture for segment %d \n " ,
pci_mmcfg_config [ i ] . pci_segment_group_number ) ;
2006-03-24 03:15:11 -08:00
return ;
2005-06-23 17:35:56 -07:00
}
printk ( KERN_INFO " PCI: Using MMCONFIG at %x \n " , pci_mmcfg_config [ i ] . base_address ) ;
}
2005-04-16 15:20:36 -07:00
2005-12-12 22:17:11 -08:00
unreachable_devices ( ) ;
2005-04-16 15:20:36 -07:00
raw_pci_ops = & pci_mmcfg ;
pci_probe = ( pci_probe & ~ PCI_PROBE_MASK ) | PCI_PROBE_MMCONF ;
}