2005-06-23 03:43:23 +04:00
/*
* Copyright ( C ) 2001 Dave Engebretsen , IBM Corporation
* Copyright ( C ) 2003 Anton Blanchard < anton @ au . ibm . com > , IBM
*
* RTAS specific routines for PCI .
2005-11-04 03:42:26 +03:00
*
2005-06-23 03:43:23 +04:00
* Based on code from pci . c , chrp_pci . c and pSeries_pci . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
2005-11-04 03:42:26 +03:00
*
2005-06-23 03:43:23 +04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-11-04 03:42:26 +03:00
*
2005-06-23 03:43:23 +04:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/kernel.h>
# include <linux/threads.h>
# include <linux/pci.h>
# include <linux/string.h>
# include <linux/init.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/irq.h>
# include <asm/prom.h>
# include <asm/machdep.h>
# include <asm/pci-bridge.h>
# include <asm/iommu.h>
# include <asm/rtas.h>
2005-09-27 07:51:59 +04:00
# include <asm/mpic.h>
2005-09-27 20:50:25 +04:00
# include <asm/ppc-pci.h>
2006-11-13 01:27:39 +03:00
# include <asm/eeh.h>
2005-06-23 03:43:23 +04:00
/* RTAS tokens */
static int read_pci_config ;
static int write_pci_config ;
static int ibm_read_pci_config ;
static int ibm_write_pci_config ;
2005-11-04 03:42:26 +03:00
static inline int config_access_valid ( struct pci_dn * dn , int where )
2005-06-23 03:43:23 +04:00
{
if ( where < 256 )
return 1 ;
if ( where < 4096 & & dn - > pci_ext_config_space )
return 1 ;
return 0 ;
}
2005-11-04 03:55:19 +03:00
int rtas_read_config ( struct pci_dn * pdn , int where , int size , u32 * val )
2005-06-23 03:43:23 +04:00
{
int returnval = - 1 ;
unsigned long buid , addr ;
int ret ;
2005-11-04 03:42:26 +03:00
if ( ! pdn )
2005-06-23 03:43:23 +04:00
return PCIBIOS_DEVICE_NOT_FOUND ;
2005-09-06 07:17:54 +04:00
if ( ! config_access_valid ( pdn , where ) )
2005-06-23 03:43:23 +04:00
return PCIBIOS_BAD_REGISTER_NUMBER ;
2014-10-01 11:07:52 +04:00
# ifdef CONFIG_EEH
if ( pdn - > edev & & pdn - > edev - > pe & &
( pdn - > edev - > pe - > state & EEH_PE_CFG_BLOCKED ) )
return PCIBIOS_SET_FAILED ;
# endif
2005-06-23 03:43:23 +04:00
2006-08-16 16:04:14 +04:00
addr = rtas_config_addr ( pdn - > busno , pdn - > devfn , where ) ;
2005-09-06 07:17:54 +04:00
buid = pdn - > phb - > buid ;
2005-06-23 03:43:23 +04:00
if ( buid ) {
ret = rtas_call ( ibm_read_pci_config , 4 , 2 , & returnval ,
2005-11-04 03:42:26 +03:00
addr , BUID_HI ( buid ) , BUID_LO ( buid ) , size ) ;
2005-06-23 03:43:23 +04:00
} else {
ret = rtas_call ( read_pci_config , 2 , 2 , & returnval , addr , size ) ;
}
* val = returnval ;
if ( ret )
return PCIBIOS_DEVICE_NOT_FOUND ;
return PCIBIOS_SUCCESSFUL ;
}
static int rtas_pci_read_config ( struct pci_bus * bus ,
unsigned int devfn ,
int where , int size , u32 * val )
{
struct device_node * busdn , * dn ;
2014-04-24 12:00:12 +04:00
struct pci_dn * pdn ;
bool found = false ;
int ret ;
2005-06-23 03:43:23 +04:00
/* Search only direct children of the bus */
2014-04-24 12:00:12 +04:00
* val = 0xFFFFFFFF ;
busdn = pci_bus_to_OF_node ( bus ) ;
2005-11-04 03:42:26 +03:00
for ( dn = busdn - > child ; dn ; dn = dn - > sibling ) {
2014-04-24 12:00:12 +04:00
pdn = PCI_DN ( dn ) ;
2005-11-04 03:42:26 +03:00
if ( pdn & & pdn - > devfn = = devfn
2014-04-24 12:00:12 +04:00
& & of_device_is_available ( dn ) ) {
found = true ;
break ;
}
2005-11-04 03:42:26 +03:00
}
2005-09-06 07:17:54 +04:00
2014-04-24 12:00:12 +04:00
if ( ! found )
return PCIBIOS_DEVICE_NOT_FOUND ;
ret = rtas_read_config ( pdn , where , size , val ) ;
if ( * val = = EEH_IO_ERROR_VALUE ( size ) & &
2015-03-17 08:15:08 +03:00
eeh_dev_check_failure ( pdn_to_eeh_dev ( pdn ) ) )
2014-04-24 12:00:12 +04:00
return PCIBIOS_DEVICE_NOT_FOUND ;
return ret ;
2005-06-23 03:43:23 +04:00
}
2005-11-04 03:42:26 +03:00
int rtas_write_config ( struct pci_dn * pdn , int where , int size , u32 val )
2005-06-23 03:43:23 +04:00
{
unsigned long buid , addr ;
int ret ;
2005-11-04 03:42:26 +03:00
if ( ! pdn )
2005-06-23 03:43:23 +04:00
return PCIBIOS_DEVICE_NOT_FOUND ;
2005-09-06 07:17:54 +04:00
if ( ! config_access_valid ( pdn , where ) )
2005-06-23 03:43:23 +04:00
return PCIBIOS_BAD_REGISTER_NUMBER ;
2014-10-01 11:07:52 +04:00
# ifdef CONFIG_EEH
if ( pdn - > edev & & pdn - > edev - > pe & &
( pdn - > edev - > pe - > state & EEH_PE_CFG_BLOCKED ) )
return PCIBIOS_SET_FAILED ;
# endif
2005-06-23 03:43:23 +04:00
2006-08-16 16:04:14 +04:00
addr = rtas_config_addr ( pdn - > busno , pdn - > devfn , where ) ;
2005-09-06 07:17:54 +04:00
buid = pdn - > phb - > buid ;
2005-06-23 03:43:23 +04:00
if ( buid ) {
2005-11-04 03:42:26 +03:00
ret = rtas_call ( ibm_write_pci_config , 5 , 1 , NULL , addr ,
BUID_HI ( buid ) , BUID_LO ( buid ) , size , ( ulong ) val ) ;
2005-06-23 03:43:23 +04:00
} else {
ret = rtas_call ( write_pci_config , 3 , 1 , NULL , addr , size , ( ulong ) val ) ;
}
if ( ret )
return PCIBIOS_DEVICE_NOT_FOUND ;
return PCIBIOS_SUCCESSFUL ;
}
static int rtas_pci_write_config ( struct pci_bus * bus ,
unsigned int devfn ,
int where , int size , u32 val )
{
struct device_node * busdn , * dn ;
2014-04-24 12:00:12 +04:00
struct pci_dn * pdn ;
bool found = false ;
2005-06-23 03:43:23 +04:00
/* Search only direct children of the bus */
2014-04-24 12:00:12 +04:00
busdn = pci_bus_to_OF_node ( bus ) ;
2005-11-04 03:42:26 +03:00
for ( dn = busdn - > child ; dn ; dn = dn - > sibling ) {
2014-04-24 12:00:12 +04:00
pdn = PCI_DN ( dn ) ;
2005-11-04 03:42:26 +03:00
if ( pdn & & pdn - > devfn = = devfn
2014-04-24 12:00:12 +04:00
& & of_device_is_available ( dn ) ) {
found = true ;
break ;
}
2005-11-04 03:42:26 +03:00
}
2014-04-24 12:00:12 +04:00
if ( ! found )
return PCIBIOS_DEVICE_NOT_FOUND ;
2014-10-01 11:07:52 +04:00
return rtas_write_config ( pdn , where , size , val ) ;
2005-06-23 03:43:23 +04:00
}
2008-05-08 08:27:19 +04:00
static struct pci_ops rtas_pci_ops = {
2007-08-09 23:18:36 +04:00
. read = rtas_pci_read_config ,
. write = rtas_pci_write_config ,
2005-06-23 03:43:23 +04:00
} ;
2008-05-08 08:27:19 +04:00
static int is_python ( struct device_node * dev )
2005-06-23 03:43:23 +04:00
{
2007-04-03 16:26:41 +04:00
const char * model = of_get_property ( dev , " model " , NULL ) ;
2005-06-23 03:43:23 +04:00
if ( model & & strstr ( model , " Python " ) )
return 1 ;
return 0 ;
}
2005-12-13 10:01:21 +03:00
static void python_countermeasures ( struct device_node * dev )
2005-06-23 03:43:23 +04:00
{
2005-12-13 10:01:21 +03:00
struct resource registers ;
2005-06-23 03:43:23 +04:00
void __iomem * chip_regs ;
volatile u32 val ;
2005-12-13 10:01:21 +03:00
if ( of_address_to_resource ( dev , 0 , & registers ) ) {
printk ( KERN_ERR " Can't get address for Python workarounds ! \n " ) ;
2005-06-23 03:43:23 +04:00
return ;
2005-12-13 10:01:21 +03:00
}
2005-06-23 03:43:23 +04:00
/* Python's register file is 1 MB in size. */
2005-12-13 10:01:21 +03:00
chip_regs = ioremap ( registers . start & ~ ( 0xfffffUL ) , 0x100000 ) ;
2005-06-23 03:43:23 +04:00
2005-11-04 03:42:26 +03:00
/*
2005-06-23 03:43:23 +04:00
* Firmware doesn ' t always clear this bit which is critical
* for good performance - Anton
*/
# define PRG_CL_RESET_VALID 0x00010000
val = in_be32 ( chip_regs + 0xf6030 ) ;
if ( val & PRG_CL_RESET_VALID ) {
printk ( KERN_INFO " Python workaround: " ) ;
val & = ~ PRG_CL_RESET_VALID ;
out_be32 ( chip_regs + 0xf6030 , val ) ;
/*
* We must read it back for changes to
* take effect
*/
val = in_be32 ( chip_regs + 0xf6030 ) ;
printk ( " reg0: %x \n " , val ) ;
}
iounmap ( chip_regs ) ;
}
2013-03-08 05:47:58 +04:00
void __init init_pci_config_tokens ( void )
2005-06-23 03:43:23 +04:00
{
read_pci_config = rtas_token ( " read-pci-config " ) ;
write_pci_config = rtas_token ( " write-pci-config " ) ;
ibm_read_pci_config = rtas_token ( " ibm,read-pci-config " ) ;
ibm_write_pci_config = rtas_token ( " ibm,write-pci-config " ) ;
}
2013-03-08 05:47:58 +04:00
unsigned long get_phb_buid ( struct device_node * phb )
2005-06-23 03:43:23 +04:00
{
2006-11-11 09:25:06 +03:00
struct resource r ;
2005-06-23 03:43:23 +04:00
2006-11-11 09:25:06 +03:00
if ( ibm_read_pci_config = = - 1 )
2005-06-23 03:43:23 +04:00
return 0 ;
2006-11-11 09:25:06 +03:00
if ( of_address_to_resource ( phb , 0 , & r ) )
2005-06-23 03:43:23 +04:00
return 0 ;
2006-11-11 09:25:06 +03:00
return r . start ;
2005-06-23 03:43:23 +04:00
}
static int phb_set_bus_ranges ( struct device_node * dev ,
struct pci_controller * phb )
{
2013-09-23 16:17:54 +04:00
const __be32 * bus_range ;
2005-06-23 03:43:23 +04:00
unsigned int len ;
2007-04-03 16:26:41 +04:00
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
2005-06-23 03:43:23 +04:00
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) ) {
return 1 ;
}
2005-11-04 03:42:26 +03:00
2013-09-23 16:17:54 +04:00
phb - > first_busno = be32_to_cpu ( bus_range [ 0 ] ) ;
phb - > last_busno = be32_to_cpu ( bus_range [ 1 ] ) ;
2005-06-23 03:43:23 +04:00
return 0 ;
}
2012-12-22 02:04:10 +04:00
int rtas_setup_phb ( struct pci_controller * phb )
2005-06-23 03:43:23 +04:00
{
2007-12-10 06:33:21 +03:00
struct device_node * dev = phb - > dn ;
2006-11-11 09:25:08 +03:00
2005-06-23 03:43:23 +04:00
if ( is_python ( dev ) )
2005-12-13 10:01:21 +03:00
python_countermeasures ( dev ) ;
2005-06-23 03:43:23 +04:00
if ( phb_set_bus_ranges ( dev , phb ) )
return 1 ;
phb - > ops = & rtas_pci_ops ;
phb - > buid = get_phb_buid ( dev ) ;
return 0 ;
}