2006-09-18 23:16:23 +01:00
/*
* arch / arm / plat - iop / pci . c
*
* PCI support for the Intel IOP32X and IOP33X processors
*
* Author : Rory Bolt < rorybolt @ pacbell . net >
* Copyright ( C ) 2002 Rory Bolt
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <asm/io.h>
# include <asm/irq.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <asm/signal.h>
2006-09-18 23:16:23 +01:00
# include <asm/system.h>
# include <asm/hardware.h>
# include <asm/mach/pci.h>
# include <asm/hardware/iop3xx.h>
// #define DEBUG
# ifdef DEBUG
# define DBG(x...) printk(x)
# else
# define DBG(x...) do { } while (0)
# endif
/*
* This routine builds either a type0 or type1 configuration command . If the
* bus is on the 803 xx then a type0 made , else a type1 is created .
*/
static u32 iop3xx_cfg_address ( struct pci_bus * bus , int devfn , int where )
{
struct pci_sys_data * sys = bus - > sysdata ;
u32 addr ;
if ( sys - > busnr = = bus - > number )
addr = 1 < < ( PCI_SLOT ( devfn ) + 16 ) | ( PCI_SLOT ( devfn ) < < 11 ) ;
else
addr = bus - > number < < 16 | PCI_SLOT ( devfn ) < < 11 | 1 ;
addr | = PCI_FUNC ( devfn ) < < 8 | ( where & ~ 3 ) ;
return addr ;
}
/*
* This routine checks the status of the last configuration cycle . If an error
* was detected it returns a 1 , else it returns a 0. The errors being checked
* are parity , master abort , target abort ( master and target ) . These types of
2007-05-02 17:59:44 +01:00
* errors occur during a config cycle where there is no device , like during
2006-09-18 23:16:23 +01:00
* the discovery stage .
*/
static int iop3xx_pci_status ( void )
{
unsigned int status ;
int ret = 0 ;
/*
* Check the status registers .
*/
status = * IOP3XX_ATUSR ;
if ( status & 0xf900 ) {
DBG ( " \t \t \t PCI: P0 - status = 0x%08x \n " , status ) ;
* IOP3XX_ATUSR = status & 0xf900 ;
ret = 1 ;
}
status = * IOP3XX_ATUISR ;
if ( status & 0x679f ) {
DBG ( " \t \t \t PCI: P1 - status = 0x%08x \n " , status ) ;
* IOP3XX_ATUISR = status & 0x679f ;
ret = 1 ;
}
return ret ;
}
/*
* Simply write the address register and read the configuration
2007-05-11 20:40:30 +01:00
* data . Note that the 4 nops ensure that we are able to handle
2006-09-18 23:16:23 +01:00
* a delayed abort ( in theory . )
*/
2007-05-15 01:03:36 +01:00
static u32 iop3xx_read ( unsigned long addr )
2006-09-18 23:16:23 +01:00
{
u32 val ;
__asm__ __volatile__ (
" str %1, [%2] \n \t "
" ldr %0, [%3] \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
: " =r " ( val )
: " r " ( addr ) , " r " ( IOP3XX_OCCAR ) , " r " ( IOP3XX_OCCDR ) ) ;
return val ;
}
/*
* The read routines must check the error status of the last configuration
* cycle . If there was an error , the routine returns all hex f ' s .
*/
static int
iop3xx_read_config ( struct pci_bus * bus , unsigned int devfn , int where ,
int size , u32 * value )
{
unsigned long addr = iop3xx_cfg_address ( bus , devfn , where ) ;
u32 val = iop3xx_read ( addr ) > > ( ( where & 3 ) * 8 ) ;
if ( iop3xx_pci_status ( ) )
val = 0xffffffff ;
* value = val ;
return PCIBIOS_SUCCESSFUL ;
}
static int
iop3xx_write_config ( struct pci_bus * bus , unsigned int devfn , int where ,
int size , u32 value )
{
unsigned long addr = iop3xx_cfg_address ( bus , devfn , where ) ;
u32 val ;
if ( size ! = 4 ) {
val = iop3xx_read ( addr ) ;
if ( iop3xx_pci_status ( ) )
return PCIBIOS_SUCCESSFUL ;
where = ( where & 3 ) * 8 ;
if ( size = = 1 )
val & = ~ ( 0xff < < where ) ;
else
val & = ~ ( 0xffff < < where ) ;
* IOP3XX_OCCDR = val | value < < where ;
} else {
asm volatile (
" str %1, [%2] \n \t "
" str %0, [%3] \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
:
: " r " ( value ) , " r " ( addr ) ,
" r " ( IOP3XX_OCCAR ) , " r " ( IOP3XX_OCCDR ) ) ;
}
return PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops iop3xx_ops = {
. read = iop3xx_read_config ,
. write = iop3xx_write_config ,
} ;
/*
* When a PCI device does not exist during config cycles , the 80200 gets a
* bus error instead of returning 0xffffffff . This handler simply returns .
*/
static int
iop3xx_pci_abort ( unsigned long addr , unsigned int fsr , struct pt_regs * regs )
{
DBG ( " PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx \n " ,
addr , fsr , regs - > ARM_pc , regs - > ARM_lr ) ;
/*
* If it was an imprecise abort , then we need to correct the
* return address to be _after_ the instruction .
*/
if ( fsr & ( 1 < < 10 ) )
regs - > ARM_pc + = 4 ;
return 0 ;
}
int iop3xx_pci_setup ( int nr , struct pci_sys_data * sys )
{
struct resource * res ;
if ( nr ! = 0 )
return 0 ;
res = kzalloc ( 2 * sizeof ( struct resource ) , GFP_KERNEL ) ;
if ( ! res )
panic ( " PCI: unable to alloc resources " ) ;
2007-02-13 17:11:04 +01:00
res [ 0 ] . start = IOP3XX_PCI_LOWER_IO_PA ;
res [ 0 ] . end = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1 ;
2006-09-18 23:16:23 +01:00
res [ 0 ] . name = " IOP3XX PCI I/O Space " ;
res [ 0 ] . flags = IORESOURCE_IO ;
request_resource ( & ioport_resource , & res [ 0 ] ) ;
res [ 1 ] . start = IOP3XX_PCI_LOWER_MEM_PA ;
res [ 1 ] . end = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1 ;
res [ 1 ] . name = " IOP3XX PCI Memory Space " ;
res [ 1 ] . flags = IORESOURCE_MEM ;
request_resource ( & iomem_resource , & res [ 1 ] ) ;
sys - > mem_offset = IOP3XX_PCI_LOWER_MEM_PA - IOP3XX_PCI_LOWER_MEM_BA ;
2007-02-13 17:11:04 +01:00
sys - > io_offset = IOP3XX_PCI_LOWER_IO_PA - IOP3XX_PCI_LOWER_IO_BA ;
2006-09-18 23:16:23 +01:00
sys - > resource [ 0 ] = & res [ 0 ] ;
sys - > resource [ 1 ] = & res [ 1 ] ;
sys - > resource [ 2 ] = NULL ;
return 1 ;
}
struct pci_bus * iop3xx_pci_scan_bus ( int nr , struct pci_sys_data * sys )
{
return pci_scan_bus ( sys - > busnr , & iop3xx_ops , sys ) ;
}
2007-05-02 17:59:44 +01:00
void __init iop3xx_atu_setup ( void )
{
/* BAR 0 ( Disabled ) */
* IOP3XX_IAUBAR0 = 0x0 ;
* IOP3XX_IABAR0 = 0x0 ;
* IOP3XX_IATVR0 = 0x0 ;
* IOP3XX_IALR0 = 0x0 ;
/* BAR 1 ( Disabled ) */
* IOP3XX_IAUBAR1 = 0x0 ;
* IOP3XX_IABAR1 = 0x0 ;
* IOP3XX_IALR1 = 0x0 ;
/* BAR 2 (1:1 mapping with Physical RAM) */
/* Set limit and enable */
* IOP3XX_IALR2 = ~ ( ( u32 ) IOP3XX_MAX_RAM_SIZE - 1 ) & ~ 0x1 ;
* IOP3XX_IAUBAR2 = 0x0 ;
/* Align the inbound bar with the base of memory */
* IOP3XX_IABAR2 = PHYS_OFFSET |
PCI_BASE_ADDRESS_MEM_TYPE_64 |
PCI_BASE_ADDRESS_MEM_PREFETCH ;
* IOP3XX_IATVR2 = PHYS_OFFSET ;
/* Outbound window 0 */
* IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA ;
* IOP3XX_OUMWTVR0 = 0 ;
/* Outbound window 1 */
* IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE ;
* IOP3XX_OUMWTVR1 = 0 ;
/* BAR 3 ( Disabled ) */
* IOP3XX_IAUBAR3 = 0x0 ;
* IOP3XX_IABAR3 = 0x0 ;
* IOP3XX_IATVR3 = 0x0 ;
* IOP3XX_IALR3 = 0x0 ;
/* Setup the I/O Bar
*/
* IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA ; ;
/* Enable inbound and outbound cycles
*/
* IOP3XX_ATUCMD | = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_PARITY | PCI_COMMAND_SERR ;
* IOP3XX_ATUCR | = IOP3XX_ATUCR_OUT_EN ;
}
void __init iop3xx_atu_disable ( void )
{
* IOP3XX_ATUCMD = 0 ;
* IOP3XX_ATUCR = 0 ;
/* wait for cycles to quiesce */
while ( * IOP3XX_PCSR & ( IOP3XX_PCSR_OUT_Q_BUSY |
IOP3XX_PCSR_IN_Q_BUSY ) )
cpu_relax ( ) ;
/* BAR 0 ( Disabled ) */
* IOP3XX_IAUBAR0 = 0x0 ;
* IOP3XX_IABAR0 = 0x0 ;
* IOP3XX_IATVR0 = 0x0 ;
* IOP3XX_IALR0 = 0x0 ;
/* BAR 1 ( Disabled ) */
* IOP3XX_IAUBAR1 = 0x0 ;
* IOP3XX_IABAR1 = 0x0 ;
* IOP3XX_IALR1 = 0x0 ;
/* BAR 2 ( Disabled ) */
* IOP3XX_IAUBAR2 = 0x0 ;
* IOP3XX_IABAR2 = 0x0 ;
* IOP3XX_IATVR2 = 0x0 ;
* IOP3XX_IALR2 = 0x0 ;
/* BAR 3 ( Disabled ) */
* IOP3XX_IAUBAR3 = 0x0 ;
* IOP3XX_IABAR3 = 0x0 ;
* IOP3XX_IATVR3 = 0x0 ;
* IOP3XX_IALR3 = 0x0 ;
/* Clear the outbound windows */
* IOP3XX_OIOWTVR = 0 ;
/* Outbound window 0 */
* IOP3XX_OMWTVR0 = 0 ;
* IOP3XX_OUMWTVR0 = 0 ;
/* Outbound window 1 */
* IOP3XX_OMWTVR1 = 0 ;
* IOP3XX_OUMWTVR1 = 0 ;
}
/* Flag to determine whether the ATU is initialized and the PCI bus scanned */
int init_atu ;
2007-05-15 01:03:36 +01:00
void __init iop3xx_pci_preinit ( void )
2006-09-18 23:16:23 +01:00
{
2007-05-02 17:59:44 +01:00
if ( iop3xx_get_init_atu ( ) = = IOP3XX_INIT_ATU_ENABLE ) {
iop3xx_atu_disable ( ) ;
iop3xx_atu_setup ( ) ;
}
2006-09-18 23:16:23 +01:00
DBG ( " PCI: Intel 803xx PCI init code. \n " ) ;
DBG ( " ATU: IOP3XX_ATUCMD=0x%04x \n " , * IOP3XX_ATUCMD ) ;
DBG ( " ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x \n " ,
* IOP3XX_OMWTVR0 ,
* IOP3XX_OIOWTVR ) ;
DBG ( " ATU: IOP3XX_ATUCR=0x%08x \n " , * IOP3XX_ATUCR ) ;
DBG ( " ATU: IOP3XX_IABAR0=0x%08x IOP3XX_IALR0=0x%08x IOP3XX_IATVR0=%08x \n " ,
* IOP3XX_IABAR0 , * IOP3XX_IALR0 , * IOP3XX_IATVR0 ) ;
DBG ( " ATU: IOP3XX_OMWTVR0=0x%08x \n " , * IOP3XX_OMWTVR0 ) ;
DBG ( " ATU: IOP3XX_IABAR1=0x%08x IOP3XX_IALR1=0x%08x \n " ,
* IOP3XX_IABAR1 , * IOP3XX_IALR1 ) ;
DBG ( " ATU: IOP3XX_ERBAR=0x%08x IOP3XX_ERLR=0x%08x IOP3XX_ERTVR=%08x \n " ,
* IOP3XX_ERBAR , * IOP3XX_ERLR , * IOP3XX_ERTVR ) ;
DBG ( " ATU: IOP3XX_IABAR2=0x%08x IOP3XX_IALR2=0x%08x IOP3XX_IATVR2=%08x \n " ,
* IOP3XX_IABAR2 , * IOP3XX_IALR2 , * IOP3XX_IATVR2 ) ;
DBG ( " ATU: IOP3XX_IABAR3=0x%08x IOP3XX_IALR3=0x%08x IOP3XX_IATVR3=%08x \n " ,
* IOP3XX_IABAR3 , * IOP3XX_IALR3 , * IOP3XX_IATVR3 ) ;
hook_fault_code ( 16 + 6 , iop3xx_pci_abort , SIGBUS , " imprecise external abort " ) ;
}
2007-05-02 17:59:44 +01:00
/* allow init_atu to be user overridden */
static int __init iop3xx_init_atu_setup ( char * str )
{
init_atu = IOP3XX_INIT_ATU_DEFAULT ;
if ( str ) {
while ( * str ! = ' \0 ' ) {
switch ( * str ) {
case ' y ' :
case ' Y ' :
init_atu = IOP3XX_INIT_ATU_ENABLE ;
break ;
case ' n ' :
case ' N ' :
init_atu = IOP3XX_INIT_ATU_DISABLE ;
break ;
case ' , ' :
case ' = ' :
break ;
default :
printk ( KERN_DEBUG " \" %s \" malformed at "
" character: \' %c \' " ,
__FUNCTION__ ,
* str ) ;
* ( str + 1 ) = ' \0 ' ;
}
str + + ;
}
}
return 1 ;
}
__setup ( " iop3xx_init_atu " , iop3xx_init_atu_setup ) ;