@ -122,7 +122,7 @@ struct talitos_private {
struct device * dev ;
struct platform_device * ofdev ;
void __iomem * reg ;
int irq ;
int irq [ 2 ] ;
/* SEC version geometry (from device tree node) */
unsigned int num_channels ;
@ -146,7 +146,7 @@ struct talitos_private {
atomic_t last_chan ____cacheline_aligned ;
/* request callback tasklet */
struct tasklet_struct done_task ;
struct tasklet_struct done_task [ 2 ] ;
/* list of registered algorithms */
struct list_head alg_list ;
@ -226,13 +226,19 @@ static int reset_device(struct device *dev)
{
struct talitos_private * priv = dev_get_drvdata ( dev ) ;
unsigned int timeout = TALITOS_TIMEOUT ;
u32 mcr = TALITOS_MCR_SWR ;
setbits32 ( priv - > reg + TALITOS_MCR , TALITOS_MCR_SWR ) ;
setbits32 ( priv - > reg + TALITOS_MCR , mcr ) ;
while ( ( in_be32 ( priv - > reg + TALITOS_MCR ) & TALITOS_MCR_SWR )
& & - - timeout )
cpu_relax ( ) ;
if ( priv - > irq [ 1 ] ! = NO_IRQ ) {
mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3 ;
setbits32 ( priv - > reg + TALITOS_MCR , mcr ) ;
}
if ( timeout = = 0 ) {
dev_err ( dev , " failed to reset device \n " ) ;
return - EIO ;
@ -401,21 +407,32 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/*
* process completed requests for channels that have done status
*/
static void talitos_done ( unsigned long data )
{
struct device * dev = ( struct device * ) data ;
struct talitos_private * priv = dev_get_drvdata ( dev ) ;
int ch ;
for ( ch = 0 ; ch < priv - > num_channels ; ch + + )
flush_channel ( dev , ch , 0 , 0 ) ;
/* At this point, all completed channels have been processed.
* Unmask done interrupts for channels completed later on .
*/
setbits32 ( priv - > reg + TALITOS_IMR , TALITOS_IMR_INIT ) ;
setbits32 ( priv - > reg + TALITOS_IMR_LO , TALITOS_IMR_LO_INIT ) ;
}
# define DEF_TALITOS_DONE(name, ch_done_mask) \
static void talitos_done_ # # name ( unsigned long data ) \
{ \
struct device * dev = ( struct device * ) data ; \
struct talitos_private * priv = dev_get_drvdata ( dev ) ; \
\
if ( ch_done_mask & 1 ) \
flush_channel ( dev , 0 , 0 , 0 ) ; \
if ( priv - > num_channels = = 1 ) \
goto out ; \
if ( ch_done_mask & ( 1 < < 2 ) ) \
flush_channel ( dev , 1 , 0 , 0 ) ; \
if ( ch_done_mask & ( 1 < < 4 ) ) \
flush_channel ( dev , 2 , 0 , 0 ) ; \
if ( ch_done_mask & ( 1 < < 6 ) ) \
flush_channel ( dev , 3 , 0 , 0 ) ; \
\
out : \
/* At this point, all completed channels have been processed */ \
/* Unmask done interrupts for channels completed later on. */ \
setbits32 ( priv - > reg + TALITOS_IMR , ch_done_mask ) ; \
setbits32 ( priv - > reg + TALITOS_IMR_LO , TALITOS_IMR_LO_INIT ) ; \
}
DEF_TALITOS_DONE ( 4 ch , TALITOS_ISR_4CHDONE )
DEF_TALITOS_DONE ( ch0_2 , TALITOS_ISR_CH_0_2_DONE )
DEF_TALITOS_DONE ( ch1_3 , TALITOS_ISR_CH_1_3_DONE )
/*
* locate current ( offending ) descriptor
@ -584,7 +601,7 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
}
}
}
if ( reset_dev | | isr & ~ TALITOS_ISR_CHERR | | isr_lo ) {
if ( reset_dev | | isr & ~ TALITOS_ISR_4 CHERR | | isr_lo ) {
dev_err ( dev , " done overflow, internal time out, or rngu error: "
" ISR 0x%08x_%08x \n " , isr , isr_lo ) ;
@ -597,30 +614,35 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
}
}
static irqreturn_t talitos_interrupt ( int irq , void * data )
{
struct device * dev = data ;
struct talitos_private * priv = dev_get_drvdata ( dev ) ;
u32 isr , isr_lo ;
isr = in_be32 ( priv - > reg + TALITOS_ISR ) ;
isr_lo = in_be32 ( priv - > reg + TALITOS_ISR_LO ) ;
/* Acknowledge interrupt */
out_be32 ( priv - > reg + TALITOS_ICR , isr ) ;
out_be32 ( priv - > reg + TALITOS_ICR_LO , isr_lo ) ;
if ( unlikely ( ( isr & ~ TALITOS_ISR_CHDONE ) | | isr_lo ) )
talitos_error ( ( unsigned long ) data , isr , isr_lo ) ;
else
if ( likely ( isr & TALITOS_ISR_CHDONE ) ) {
/* mask further done interrupts. */
clrbits32 ( priv - > reg + TALITOS_IMR , TALITOS_IMR_DONE ) ;
/* done_task will unmask done interrupts at exit */
tasklet_schedule ( & priv - > done_task ) ;
}
return ( isr | | isr_lo ) ? IRQ_HANDLED : IRQ_NONE ;
}
# define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \
static irqreturn_t talitos_interrupt_ # # name ( int irq , void * data ) \
{ \
struct device * dev = data ; \
struct talitos_private * priv = dev_get_drvdata ( dev ) ; \
u32 isr , isr_lo ; \
\
isr = in_be32 ( priv - > reg + TALITOS_ISR ) ; \
isr_lo = in_be32 ( priv - > reg + TALITOS_ISR_LO ) ; \
/* Acknowledge interrupt */ \
out_be32 ( priv - > reg + TALITOS_ICR , isr & ( ch_done_mask | ch_err_mask ) ) ; \
out_be32 ( priv - > reg + TALITOS_ICR_LO , isr_lo ) ; \
\
if ( unlikely ( ( isr & ~ TALITOS_ISR_4CHDONE ) & ch_err_mask | | isr_lo ) ) \
talitos_error ( ( unsigned long ) data , isr , isr_lo ) ; \
else \
if ( likely ( isr & ch_done_mask ) ) { \
/* mask further done interrupts. */ \
clrbits32 ( priv - > reg + TALITOS_IMR , ch_done_mask ) ; \
/* done_task will unmask done interrupts at exit */ \
tasklet_schedule ( & priv - > done_task [ tlet ] ) ; \
} \
\
return ( isr & ( ch_done_mask | ch_err_mask ) | | isr_lo ) ? IRQ_HANDLED : \
IRQ_NONE ; \
}
DEF_TALITOS_INTERRUPT ( 4 ch , TALITOS_ISR_4CHDONE , TALITOS_ISR_4CHERR , 0 )
DEF_TALITOS_INTERRUPT ( ch0_2 , TALITOS_ISR_CH_0_2_DONE , TALITOS_ISR_CH_0_2_ERR , 0 )
DEF_TALITOS_INTERRUPT ( ch1_3 , TALITOS_ISR_CH_1_3_DONE , TALITOS_ISR_CH_1_3_ERR , 1 )
/*
* hwrng
@ -2558,12 +2580,15 @@ static int talitos_remove(struct platform_device *ofdev)
kfree ( priv - > chan ) ;
if ( priv - > irq ! = NO_IRQ ) {
free_irq ( priv - > irq , dev ) ;
irq_dispose_mapping ( priv - > irq ) ;
}
for ( i = 0 ; i < 2 ; i + + )
if ( priv - > irq [ i ] ! = NO_IRQ ) {
free_irq ( priv - > irq [ i ] , dev ) ;
irq_dispose_mapping ( priv - > irq [ i ] ) ;
}
tasklet_kill ( & priv - > done_task ) ;
tasklet_kill ( & priv - > done_task [ 0 ] ) ;
if ( priv - > irq [ 1 ] ! = NO_IRQ )
tasklet_kill ( & priv - > done_task [ 1 ] ) ;
iounmap ( priv - > reg ) ;
@ -2628,6 +2653,54 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
return t_alg ;
}
static int talitos_probe_irq ( struct platform_device * ofdev )
{
struct device * dev = & ofdev - > dev ;
struct device_node * np = ofdev - > dev . of_node ;
struct talitos_private * priv = dev_get_drvdata ( dev ) ;
int err ;
priv - > irq [ 0 ] = irq_of_parse_and_map ( np , 0 ) ;
if ( priv - > irq [ 0 ] = = NO_IRQ ) {
dev_err ( dev , " failed to map irq \n " ) ;
return - EINVAL ;
}
priv - > irq [ 1 ] = irq_of_parse_and_map ( np , 1 ) ;
/* get the primary irq line */
if ( priv - > irq [ 1 ] = = NO_IRQ ) {
err = request_irq ( priv - > irq [ 0 ] , talitos_interrupt_4ch , 0 ,
dev_driver_string ( dev ) , dev ) ;
goto primary_out ;
}
err = request_irq ( priv - > irq [ 0 ] , talitos_interrupt_ch0_2 , 0 ,
dev_driver_string ( dev ) , dev ) ;
if ( err )
goto primary_out ;
/* get the secondary irq line */
err = request_irq ( priv - > irq [ 1 ] , talitos_interrupt_ch1_3 , 0 ,
dev_driver_string ( dev ) , dev ) ;
if ( err ) {
dev_err ( dev , " failed to request secondary irq \n " ) ;
irq_dispose_mapping ( priv - > irq [ 1 ] ) ;
priv - > irq [ 1 ] = NO_IRQ ;
}
return err ;
primary_out :
if ( err ) {
dev_err ( dev , " failed to request primary irq \n " ) ;
irq_dispose_mapping ( priv - > irq [ 0 ] ) ;
priv - > irq [ 0 ] = NO_IRQ ;
}
return err ;
}
static int talitos_probe ( struct platform_device * ofdev )
{
struct device * dev = & ofdev - > dev ;
@ -2644,28 +2717,22 @@ static int talitos_probe(struct platform_device *ofdev)
priv - > ofdev = ofdev ;
tasklet_init ( & priv - > done_task , talitos_done , ( unsigned long ) dev ) ;
INIT_LIST_HEAD ( & priv - > alg_list ) ;
priv - > irq = irq_of_parse_and_map ( np , 0 ) ;
if ( priv - > irq = = NO_IRQ ) {
dev_err ( dev , " failed to map irq \n " ) ;
err = - EINVAL ;
err = talitos_probe_irq ( ofdev ) ;
if ( err )
goto err_out ;
}
/* get the irq line */
err = request_irq ( priv - > irq , talitos_interrupt , 0 ,
dev_driver_string ( dev ) , dev ) ;
if ( err ) {
dev_err ( dev , " failed to request irq %d \n " , priv - > irq ) ;
irq_dispose_mapping ( priv - > irq ) ;
priv - > irq = NO_IRQ ;
goto err_out ;
if ( priv - > irq [ 1 ] = = NO_IRQ ) {
tasklet_init ( & priv - > done_task [ 0 ] , talitos_done_4ch ,
( unsigned long ) dev ) ;
} else {
tasklet_init ( & priv - > done_task [ 0 ] , talitos_done_ch0_2 ,
( unsigned long ) dev ) ;
tasklet_init ( & priv - > done_task [ 1 ] , talitos_done_ch1_3 ,
( unsigned long ) dev ) ;
}
INIT_LIST_HEAD ( & priv - > alg_list ) ;
priv - > reg = of_iomap ( np , 0 ) ;
if ( ! priv - > reg ) {
dev_err ( dev , " failed to of_iomap \n " ) ;
@ -2713,9 +2780,11 @@ static int talitos_probe(struct platform_device *ofdev)
goto err_out ;
}
for ( i = 0 ; i < priv - > num_channels ; i + + )
priv - > chan [ i ] . reg = priv - > reg + TALITOS_CH_BASE_OFFSET +
TALITOS_CH_STRIDE * ( i + 1 ) ;
for ( i = 0 ; i < priv - > num_channels ; i + + ) {
priv - > chan [ i ] . reg = priv - > reg + TALITOS_CH_STRIDE * ( i + 1 ) ;
if ( ( priv - > irq [ 1 ] = = NO_IRQ ) | | ! ( i & 1 ) )
priv - > chan [ i ] . reg + = TALITOS_CH_BASE_OFFSET ;
}
for ( i = 0 ; i < priv - > num_channels ; i + + ) {
spin_lock_init ( & priv - > chan [ i ] . head_lock ) ;