@ -21,46 +21,61 @@
# include <linux/io.h>
# include <asm/cacheflush.h>
# include <asm/hardware/gic.h>
# include <asm/smp_scu.h>
# include <asm/unified.h>
# include <asm/fiq.h>
# include <mach/smp.h>
# include <mach/cns3xxx.h>
# include "cns3xxx.h"
static struct fiq_handler fh = {
. name = " cns3xxx-fiq "
} ;
static unsigned int fiq_buffer [ 8 ] ;
struct fiq_req {
union {
struct {
const void * addr ;
size_t size ;
} map ;
struct {
const void * addr ;
size_t size ;
} unmap ;
struct {
const void * start ;
const void * end ;
} flush ;
} ;
volatile uint flags ;
void __iomem * reg ;
} ____cacheline_aligned ;
extern unsigned int fiq_number [ 2 ] ;
DEFINE_PER_CPU ( struct fiq_req , fiq_data ) ;
# define FIQ_ENABLED 0x80000000
# define FIQ_GENERATE 0x00010000
# define FIQ_GENERATE 0x00010000
# define CNS3XXX_MAP_AREA 0x01000000
# define CNS3XXX_UNMAP_AREA 0x02000000
# define CNS3XXX_FLUSH_RANGE 0x03000000
extern void cns3xxx_secondary_startup ( void ) ;
extern unsigned char cns3xxx_fiq_start , cns3xxx_fiq_end ;
extern unsigned int fiq_number [ 2 ] ;
extern struct cpu_cache_fns cpu_cache ;
struct cpu_cache_fns cpu_cache_save ;
# define SCU_CPU_STATUS 0x08
static void __iomem * scu_base ;
static void __init cns3xxx_set_fiq_regs ( void )
static inline void __ cpu init cns3xxx_set_fiq_regs ( unsigned int cpu )
{
struct pt_regs FIQ_regs ;
unsigned int cpu = smp_processor_id ( ) ;
if ( cpu ) {
FIQ_regs . ARM_ip = ( unsigned int ) & fiq_buffer [ 4 ] ;
FIQ_regs . ARM_sp = ( unsigned int ) MISC_FIQ_CPU ( 0 ) ;
} else {
FIQ_regs . ARM_ip = ( unsigned int ) & fiq_buffer [ 0 ] ;
FIQ_regs . ARM_sp = ( unsigned int ) MISC_FIQ_CPU ( 1 ) ;
}
struct fiq_req * fiq_req = & per_cpu ( fiq_data , ! cpu ) ;
FIQ_regs . ARM_r8 = 0 ;
FIQ_regs . ARM_ip = ( unsigned int ) fiq_req ;
FIQ_regs . ARM_sp = ( int ) MISC_FIQ_CPU ( ! cpu ) ;
fiq_req - > reg = MISC_FIQ_CPU ( ! cpu ) ;
set_fiq_regs ( & FIQ_regs ) ;
}
@ -74,16 +89,10 @@ static void __init cns3xxx_init_fiq(void)
fiqhandler_length = & cns3xxx_fiq_end - & cns3xxx_fiq_start ;
ret = claim_fiq ( & fh ) ;
if ( ret ) {
if ( ret )
return ;
}
set_fiq_handler ( fiqhandler_start , fiqhandler_length ) ;
fiq_buffer [ 0 ] = ( unsigned int ) & fiq_number [ 0 ] ;
fiq_buffer [ 3 ] = 0 ;
fiq_buffer [ 4 ] = ( unsigned int ) & fiq_number [ 1 ] ;
fiq_buffer [ 7 ] = 0 ;
}
@ -104,17 +113,10 @@ static DEFINE_SPINLOCK(boot_lock);
static void __cpuinit cns3xxx_secondary_init ( unsigned int cpu )
{
/*
* if any interrupts are already enabled for the primary
* core ( e . g . timer irq ) , then they will not have been enabled
* for us : do so
*/
gic_secondary_init ( 0 ) ;
/*
* Setup Secondary Core FIQ regs
*/
cns3xxx_set_fiq_regs ( ) ;
cns3xxx_set_fiq_regs ( 1 ) ;
/*
* let the primary processor know we ' re out of the
@ -122,14 +124,6 @@ static void __cpuinit cns3xxx_secondary_init(unsigned int cpu)
*/
write_pen_release ( - 1 ) ;
/*
* Fixup DMA Operations
*
*/
cpu_cache . dma_map_area = ( void * ) smp_dma_map_area ;
cpu_cache . dma_unmap_area = ( void * ) smp_dma_unmap_area ;
cpu_cache . dma_flush_range = ( void * ) smp_dma_flush_range ;
/*
* Synchronise with the boot thread .
*/
@ -162,7 +156,7 @@ static int __cpuinit cns3xxx_boot_secondary(unsigned int cpu, struct task_struct
* the boot monitor to read the system wide flags register ,
* and branch to the address found there .
*/
gic_raise_softirq( cpumask_of ( cpu ) , 1 ) ;
arch_send_wakeup_ipi_mask( cpumask_of ( cpu ) ) ; ;
timeout = jiffies + ( 1 * HZ ) ;
while ( time_before ( jiffies , timeout ) ) {
@ -204,8 +198,6 @@ static void __init cns3xxx_smp_init_cpus(void)
break ;
}
ncores = i ;
set_smp_cross_call ( gic_raise_softirq ) ;
}
static void __init cns3xxx_smp_prepare_cpus ( unsigned int max_cpus )
@ -238,111 +230,105 @@ static void __init cns3xxx_smp_prepare_cpus(unsigned int max_cpus)
* Setup FIQ ' s for main cpu
*/
cns3xxx_init_fiq ( ) ;
cns3xxx_set_fiq_regs ( ) ;
memcpy ( ( void * ) & cpu_cache_save , ( void * ) & cpu_cache , sizeof ( struct cpu_cache_fns ) ) ;
cns3xxx_set_fiq_regs ( 0 ) ;
}
extern void v6_dma_map_area ( const void * , size_t , int ) ;
extern void v6_dma_unmap_area ( const void * , size_t , int ) ;
extern void v6_dma_flush_range ( const void * , const void * ) ;
extern void v6_flush_kern_dcache_area ( void * , size_t ) ;
static inline unsigned long cns3xxx_cpu_id ( void )
void fiq_dma_map_area ( const void * addr , size_t size , int dir )
{
unsigned long cpu ;
asm volatile (
" mrc p15, 0, %0, c0, c0, 5 @ cns3xxx_cpu_id \n "
: " =r " ( cpu ) : : " memory " , " cc " ) ;
return ( cpu & 0xf ) ;
}
void smp_dma_map_area ( const void * addr , size_t size , int dir )
{
unsigned int cpu ;
unsigned long flags ;
struct fiq_req * req ;
raw_local_irq_save ( flags ) ;
cpu = cns3xxx_cpu_id ( ) ;
if ( cpu ) {
fiq_buffer [ 1 ] = ( unsigned int ) addr ;
fiq_buffer [ 2 ] = size ;
fiq_buffer [ 3 ] = dir | CNS3XXX_MAP_AREA | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 1 ) ) ;
cpu_cache_save . dma_map_area ( addr , size , dir ) ;
while ( ( fiq_buffer [ 3 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
} else {
fiq_buffer [ 5 ] = ( unsigned int ) addr ;
fiq_buffer [ 6 ] = size ;
fiq_buffer [ 7 ] = dir | CNS3XXX_MAP_AREA | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 0 ) ) ;
cpu_cache_save . dma_map_area ( addr , size , dir ) ;
while ( ( fiq_buffer [ 7 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
/* currently, not possible to take cpu0 down, so only check cpu1 */
if ( ! cpu_online ( 1 ) ) {
raw_local_irq_restore ( flags ) ;
v6_dma_map_area ( addr , size , dir ) ;
return ;
}
req = this_cpu_ptr ( & fiq_data ) ;
req - > map . addr = addr ;
req - > map . size = size ;
req - > flags = dir | CNS3XXX_MAP_AREA ;
smp_mb ( ) ;
writel_relaxed ( FIQ_GENERATE , req - > reg ) ;
v6_dma_map_area ( addr , size , dir ) ;
while ( req - > flags )
barrier ( ) ;
raw_local_irq_restore ( flags ) ;
}
void smp_dma_unmap_area ( const void * addr , size_t size , int dir )
void fiq _dma_unmap_area( const void * addr , size_t size , int dir )
{
unsigned int cpu ;
unsigned long flags ;
struct fiq_req * req ;
raw_local_irq_save ( flags ) ;
cpu = cns3xxx_cpu_id ( ) ;
if ( cpu ) {
fiq_buffer [ 1 ] = ( unsigned int ) addr ;
fiq_buffer [ 2 ] = size ;
fiq_buffer [ 3 ] = dir | CNS3XXX_UNMAP_AREA | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 1 ) ) ;
cpu_cache_save . dma_unmap_area ( addr , size , dir ) ;
while ( ( fiq_buffer [ 3 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
} else {
fiq_buffer [ 5 ] = ( unsigned int ) addr ;
fiq_buffer [ 6 ] = size ;
fiq_buffer [ 7 ] = dir | CNS3XXX_UNMAP_AREA | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 0 ) ) ;
cpu_cache_save . dma_unmap_area ( addr , size , dir ) ;
while ( ( fiq_buffer [ 7 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
/* currently, not possible to take cpu0 down, so only check cpu1 */
if ( ! cpu_online ( 1 ) ) {
raw_local_irq_restore ( flags ) ;
v6_dma_unmap_area ( addr , size , dir ) ;
return ;
}
req = this_cpu_ptr ( & fiq_data ) ;
req - > unmap . addr = addr ;
req - > unmap . size = size ;
req - > flags = dir | CNS3XXX_UNMAP_AREA ;
smp_mb ( ) ;
writel_relaxed ( FIQ_GENERATE , req - > reg ) ;
v6_dma_unmap_area ( addr , size , dir ) ;
while ( req - > flags )
barrier ( ) ;
raw_local_irq_restore ( flags ) ;
}
void smp_dma_flush_range ( const void * start , const void * end )
void fiq _dma_flush_range( const void * start , const void * end )
{
unsigned int cpu ;
unsigned long flags ;
struct fiq_req * req ;
raw_local_irq_save ( flags ) ;
cpu = cns3xxx_cpu_id ( ) ;
if ( cpu ) {
fiq_buffer [ 1 ] = ( unsigned int ) start ;
fiq_buffer [ 2 ] = ( unsigned int ) end ;
fiq_buffer [ 3 ] = CNS3XXX_FLUSH_RANGE | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 1 ) ) ;
cpu_cache_save . dma_flush_range ( start , end ) ;
while ( ( fiq_buffer [ 3 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
} else {
fiq_buffer [ 5 ] = ( unsigned int ) start ;
fiq_buffer [ 6 ] = ( unsigned int ) end ;
fiq_buffer [ 7 ] = CNS3XXX_FLUSH_RANGE | FIQ_ENABLED ;
smp_mb ( ) ;
__raw_writel ( FIQ_GENERATE , MISC_FIQ_CPU ( 0 ) ) ;
cpu_cache_save . dma_flush_range ( start , end ) ;
while ( ( fiq_buffer [ 7 ] ) & FIQ_ENABLED ) { barrier ( ) ; }
/* currently, not possible to take cpu0 down, so only check cpu1 */
if ( ! cpu_online ( 1 ) ) {
raw_local_irq_restore ( flags ) ;
v6_dma_flush_range ( start , end ) ;
return ;
}
req = this_cpu_ptr ( & fiq_data ) ;
req - > flush . start = start ;
req - > flush . end = end ;
req - > flags = CNS3XXX_FLUSH_RANGE ;
smp_mb ( ) ;
writel_relaxed ( FIQ_GENERATE , req - > reg ) ;
v6_dma_flush_range ( start , end ) ;
while ( req - > flags )
barrier ( ) ;
raw_local_irq_restore ( flags ) ;
}
void fiq_flush_kern_dcache_area ( void * addr , size_t size )
{
fiq_dma_flush_range ( addr , addr + size ) ;
}
struct smp_operations cns3xxx_smp_ops __initdata = {
. smp_init_cpus = cns3xxx_smp_init_cpus ,
. smp_prepare_cpus = cns3xxx_smp_prepare_cpus ,