2019-05-19 16:51:48 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-03-17 12:10:32 +03:00
/*
* Adaptec AAC series RAID controller driver
* ( c ) Copyright 2001 Red Hat Inc .
*
* based on the old aacraid driver that is . .
* Adaptec aacraid device driver for Linux .
*
* Copyright ( c ) 2000 - 2010 Adaptec , Inc .
2017-02-03 02:53:36 +03:00
* 2010 - 2015 PMC - Sierra , Inc . ( aacraid @ pmc - sierra . com )
* 2016 - 2017 Microsemi Corp . ( aacraid @ microsemi . com )
2011-03-17 12:10:32 +03:00
*
* Module Name :
* src . c
*
* Abstract : Hardware Device Interface for PMC SRC based controllers
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <linux/completion.h>
# include <linux/time.h>
# include <linux/interrupt.h>
# include <scsi/scsi_host.h>
# include "aacraid.h"
2015-03-26 17:41:25 +03:00
static int aac_src_get_sync_status ( struct aac_dev * dev ) ;
2015-04-10 11:53:38 +03:00
static irqreturn_t aac_src_intr_message ( int irq , void * dev_id )
2011-03-17 12:10:32 +03:00
{
2015-03-26 17:41:25 +03:00
struct aac_msix_ctx * ctx ;
struct aac_dev * dev ;
2011-03-17 12:10:32 +03:00
unsigned long bellbits , bellbits_shifted ;
2015-03-26 17:41:25 +03:00
int vector_no ;
int isFastResponse , mode ;
2011-03-17 12:10:32 +03:00
u32 index , handle ;
2015-03-26 17:41:25 +03:00
ctx = ( struct aac_msix_ctx * ) dev_id ;
dev = ctx - > dev ;
vector_no = ctx - > vector_no ;
if ( dev - > msi_enabled ) {
mode = AAC_INT_MODE_MSI ;
if ( vector_no = = 0 ) {
bellbits = src_readl ( dev , MUnit . ODR_MSI ) ;
if ( bellbits & 0x40000 )
mode | = AAC_INT_MODE_AIF ;
if ( bellbits & 0x1000 )
mode | = AAC_INT_MODE_SYNC ;
2011-03-17 12:10:32 +03:00
}
} else {
2015-03-26 17:41:25 +03:00
mode = AAC_INT_MODE_INTX ;
bellbits = src_readl ( dev , MUnit . ODR_R ) ;
if ( bellbits & PmDoorBellResponseSent ) {
bellbits = PmDoorBellResponseSent ;
src_writel ( dev , MUnit . ODR_C , bellbits ) ;
src_readl ( dev , MUnit . ODR_C ) ;
} else {
bellbits_shifted = ( bellbits > > SRC_ODR_SHIFT ) ;
2012-07-14 16:48:51 +04:00
src_writel ( dev , MUnit . ODR_C , bellbits ) ;
src_readl ( dev , MUnit . ODR_C ) ;
2015-03-26 17:41:25 +03:00
if ( bellbits_shifted & DoorBellAifPending )
mode | = AAC_INT_MODE_AIF ;
else if ( bellbits_shifted & OUTBOUNDDOORBELL_0 )
mode | = AAC_INT_MODE_SYNC ;
}
}
if ( mode & AAC_INT_MODE_SYNC ) {
unsigned long sflags ;
struct list_head * entry ;
int send_it = 0 ;
extern int aac_sync_mode ;
if ( ! aac_sync_mode & & ! dev - > msi_enabled ) {
2013-06-18 15:32:07 +04:00
src_writel ( dev , MUnit . ODR_C , bellbits ) ;
src_readl ( dev , MUnit . ODR_C ) ;
2015-03-26 17:41:25 +03:00
}
2013-06-18 15:32:07 +04:00
2015-03-26 17:41:25 +03:00
if ( dev - > sync_fib ) {
if ( dev - > sync_fib - > callback )
dev - > sync_fib - > callback ( dev - > sync_fib - > callback_data ,
dev - > sync_fib ) ;
spin_lock_irqsave ( & dev - > sync_fib - > event_lock , sflags ) ;
if ( dev - > sync_fib - > flags & FIB_CONTEXT_FLAG_WAIT ) {
dev - > management_fib_count - - ;
2018-12-11 00:32:41 +03:00
complete ( & dev - > sync_fib - > event_wait ) ;
2012-07-14 16:48:51 +04:00
}
2015-03-26 17:41:25 +03:00
spin_unlock_irqrestore ( & dev - > sync_fib - > event_lock ,
sflags ) ;
spin_lock_irqsave ( & dev - > sync_lock , sflags ) ;
if ( ! list_empty ( & dev - > sync_fib_list ) ) {
entry = dev - > sync_fib_list . next ;
dev - > sync_fib = list_entry ( entry ,
struct fib ,
fiblink ) ;
list_del ( entry ) ;
send_it = 1 ;
} else {
dev - > sync_fib = NULL ;
}
spin_unlock_irqrestore ( & dev - > sync_lock , sflags ) ;
if ( send_it ) {
aac_adapter_sync_cmd ( dev , SEND_SYNCHRONOUS_FIB ,
( u32 ) dev - > sync_fib - > hw_fib_pa ,
0 , 0 , 0 , 0 , 0 ,
NULL , NULL , NULL , NULL , NULL ) ;
2012-02-09 10:51:04 +04:00
}
2011-03-17 12:10:32 +03:00
}
2015-03-26 17:41:25 +03:00
if ( ! dev - > msi_enabled )
mode = 0 ;
2011-03-17 12:10:32 +03:00
}
2015-03-26 17:41:25 +03:00
if ( mode & AAC_INT_MODE_AIF ) {
/* handle AIF */
2017-02-03 02:53:22 +03:00
if ( dev - > sa_firmware ) {
u32 events = src_readl ( dev , MUnit . SCR0 ) ;
aac_intr_normal ( dev , events , 1 , 0 , NULL ) ;
writel ( events , & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
src_writel ( dev , MUnit . IDR , 1 < < 23 ) ;
} else {
if ( dev - > aif_thread & & dev - > fsa_dev )
aac_intr_normal ( dev , 0 , 2 , 0 , NULL ) ;
}
2015-03-26 17:41:25 +03:00
if ( dev - > msi_enabled )
aac_src_access_devreg ( dev , AAC_CLEAR_AIF_BIT ) ;
mode = 0 ;
2011-03-17 12:10:32 +03:00
}
2015-03-26 17:41:25 +03:00
if ( mode ) {
index = dev - > host_rrq_idx [ vector_no ] ;
for ( ; ; ) {
isFastResponse = 0 ;
/* remove toggle bit (31) */
2017-02-03 02:53:22 +03:00
handle = le32_to_cpu ( ( dev - > host_rrq [ index ] )
& 0x7fffffff ) ;
/* check fast response bits (30, 1) */
2015-03-26 17:41:25 +03:00
if ( handle & 0x40000000 )
isFastResponse = 1 ;
handle & = 0x0000ffff ;
if ( handle = = 0 )
break ;
2017-02-03 02:53:22 +03:00
handle > > = 2 ;
2015-03-26 17:41:25 +03:00
if ( dev - > msi_enabled & & dev - > max_msix > 1 )
atomic_dec ( & dev - > rrq_outstanding [ vector_no ] ) ;
2017-02-03 02:53:22 +03:00
aac_intr_normal ( dev , handle , 0 , isFastResponse , NULL ) ;
2015-03-26 17:41:25 +03:00
dev - > host_rrq [ index + + ] = 0 ;
if ( index = = ( vector_no + 1 ) * dev - > vector_cap )
index = vector_no * dev - > vector_cap ;
dev - > host_rrq_idx [ vector_no ] = index ;
}
mode = 0 ;
}
return IRQ_HANDLED ;
2011-03-17 12:10:32 +03:00
}
/**
* aac_src_disable_interrupt - Disable interrupts
* @ dev : Adapter
*/
static void aac_src_disable_interrupt ( struct aac_dev * dev )
{
src_writel ( dev , MUnit . OIMR , dev - > OIMR = 0xffffffff ) ;
}
/**
* aac_src_enable_interrupt_message - Enable interrupts
* @ dev : Adapter
*/
static void aac_src_enable_interrupt_message ( struct aac_dev * dev )
{
2015-03-26 17:41:25 +03:00
aac_src_access_devreg ( dev , AAC_ENABLE_INTERRUPT ) ;
2011-03-17 12:10:32 +03:00
}
/**
* src_sync_cmd - send a command and wait
* @ dev : Adapter
* @ command : Command to execute
* @ p1 : first parameter
2020-07-21 19:41:15 +03:00
* @ p2 : second parameter
* @ p3 : third parameter
* @ p4 : forth parameter
* @ p5 : fifth parameter
* @ p6 : sixth parameter
* @ status : adapter status
* @ r1 : first return value
* @ r2 : second return valu
* @ r3 : third return value
* @ r4 : forth return value
2011-03-17 12:10:32 +03:00
*
* This routine will send a synchronous command to the adapter and wait
* for its completion .
*/
static int src_sync_cmd ( struct aac_dev * dev , u32 command ,
u32 p1 , u32 p2 , u32 p3 , u32 p4 , u32 p5 , u32 p6 ,
u32 * status , u32 * r1 , u32 * r2 , u32 * r3 , u32 * r4 )
{
unsigned long start ;
2015-03-26 17:41:28 +03:00
unsigned long delay ;
2011-03-17 12:10:32 +03:00
int ok ;
/*
* Write the command into Mailbox 0
*/
writel ( command , & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
/*
* Write the parameters into Mailboxes 1 - 6
*/
writel ( p1 , & dev - > IndexRegs - > Mailbox [ 1 ] ) ;
writel ( p2 , & dev - > IndexRegs - > Mailbox [ 2 ] ) ;
writel ( p3 , & dev - > IndexRegs - > Mailbox [ 3 ] ) ;
writel ( p4 , & dev - > IndexRegs - > Mailbox [ 4 ] ) ;
/*
* Clear the synch command doorbell to start on a clean slate .
*/
2015-03-26 17:41:25 +03:00
if ( ! dev - > msi_enabled )
src_writel ( dev ,
MUnit . ODR_C ,
OUTBOUNDDOORBELL_0 < < SRC_ODR_SHIFT ) ;
2011-03-17 12:10:32 +03:00
/*
* Disable doorbell interrupts
*/
src_writel ( dev , MUnit . OIMR , dev - > OIMR = 0xffffffff ) ;
/*
* Force the completion of the mask register write before issuing
* the interrupt .
*/
src_readl ( dev , MUnit . OIMR ) ;
/*
* Signal that there is a new synch command
*/
src_writel ( dev , MUnit . IDR , INBOUNDDOORBELL_0 < < SRC_IDR_SHIFT ) ;
2018-02-07 19:40:56 +03:00
if ( ( ! dev - > sync_mode | | command ! = SEND_SYNCHRONOUS_FIB ) & &
! dev - > in_soft_reset ) {
2012-02-09 10:51:04 +04:00
ok = 0 ;
start = jiffies ;
2011-03-17 12:10:32 +03:00
2015-03-26 17:41:28 +03:00
if ( command = = IOP_RESET_ALWAYS ) {
/* Wait up to 10 sec */
delay = 10 * HZ ;
} else {
/* Wait up to 5 minutes */
delay = 300 * HZ ;
}
while ( time_before ( jiffies , start + delay ) ) {
2012-02-09 10:51:04 +04:00
udelay ( 5 ) ; /* Delay 5 microseconds to let Mon960 get info. */
/*
* Mon960 will set doorbell0 bit when it has completed the command .
*/
2015-03-26 17:41:25 +03:00
if ( aac_src_get_sync_status ( dev ) & OUTBOUNDDOORBELL_0 ) {
2012-02-09 10:51:04 +04:00
/*
* Clear the doorbell .
*/
2015-03-26 17:41:25 +03:00
if ( dev - > msi_enabled )
aac_src_access_devreg ( dev ,
AAC_CLEAR_SYNC_BIT ) ;
else
src_writel ( dev ,
MUnit . ODR_C ,
OUTBOUNDDOORBELL_0 < < SRC_ODR_SHIFT ) ;
2012-02-09 10:51:04 +04:00
ok = 1 ;
break ;
}
/*
* Yield the processor in case we are slow
*/
msleep ( 1 ) ;
2011-03-17 12:10:32 +03:00
}
2012-02-09 10:51:04 +04:00
if ( unlikely ( ok ! = 1 ) ) {
/*
* Restore interrupt mask even though we timed out
*/
aac_adapter_enable_int ( dev ) ;
return - ETIMEDOUT ;
}
/*
* Pull the synch status from Mailbox 0.
*/
if ( status )
* status = readl ( & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
if ( r1 )
* r1 = readl ( & dev - > IndexRegs - > Mailbox [ 1 ] ) ;
if ( r2 )
* r2 = readl ( & dev - > IndexRegs - > Mailbox [ 2 ] ) ;
if ( r3 )
* r3 = readl ( & dev - > IndexRegs - > Mailbox [ 3 ] ) ;
if ( r4 )
* r4 = readl ( & dev - > IndexRegs - > Mailbox [ 4 ] ) ;
2015-03-26 17:41:25 +03:00
if ( command = = GET_COMM_PREFERRED_SETTINGS )
dev - > max_msix =
readl ( & dev - > IndexRegs - > Mailbox [ 5 ] ) & 0xFFFF ;
2012-02-09 10:51:04 +04:00
/*
* Clear the synch command doorbell .
*/
2015-03-26 17:41:25 +03:00
if ( ! dev - > msi_enabled )
src_writel ( dev ,
MUnit . ODR_C ,
OUTBOUNDDOORBELL_0 < < SRC_ODR_SHIFT ) ;
2011-03-17 12:10:32 +03:00
}
2012-02-09 10:51:04 +04:00
/*
* Restore interrupt mask
*/
2011-03-17 12:10:32 +03:00
aac_adapter_enable_int ( dev ) ;
return 0 ;
}
/**
* aac_src_interrupt_adapter - interrupt adapter
* @ dev : Adapter
*
* Send an interrupt to the i960 and breakpoint it .
*/
static void aac_src_interrupt_adapter ( struct aac_dev * dev )
{
src_sync_cmd ( dev , BREAKPOINT_REQUEST ,
0 , 0 , 0 , 0 , 0 , 0 ,
NULL , NULL , NULL , NULL , NULL ) ;
}
/**
* aac_src_notify_adapter - send an event to the adapter
* @ dev : Adapter
* @ event : Event to send
*
* Notify the i960 that something it probably cares about has
* happened .
*/
static void aac_src_notify_adapter ( struct aac_dev * dev , u32 event )
{
switch ( event ) {
case AdapNormCmdQue :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_1 < < SRC_ODR_SHIFT ) ;
break ;
case HostNormRespNotFull :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_4 < < SRC_ODR_SHIFT ) ;
break ;
case AdapNormRespQue :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_2 < < SRC_ODR_SHIFT ) ;
break ;
case HostNormCmdNotFull :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_3 < < SRC_ODR_SHIFT ) ;
break ;
case FastIo :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_6 < < SRC_ODR_SHIFT ) ;
break ;
case AdapPrintfDone :
src_writel ( dev , MUnit . ODR_C ,
INBOUNDDOORBELL_5 < < SRC_ODR_SHIFT ) ;
break ;
default :
BUG ( ) ;
break ;
}
}
/**
* aac_src_start_adapter - activate adapter
* @ dev : Adapter
*
* Start up processing on an i960 based AAC adapter
*/
static void aac_src_start_adapter ( struct aac_dev * dev )
{
2017-02-03 02:53:17 +03:00
union aac_init * init ;
2015-03-26 17:41:25 +03:00
int i ;
2011-03-17 12:10:32 +03:00
2012-07-14 16:48:51 +04:00
/* reset host_rrq_idx first */
2015-03-26 17:41:25 +03:00
for ( i = 0 ; i < dev - > max_msix ; i + + ) {
dev - > host_rrq_idx [ i ] = i * dev - > vector_cap ;
atomic_set ( & dev - > rrq_outstanding [ i ] , 0 ) ;
}
2017-02-03 02:53:22 +03:00
atomic_set ( & dev - > msix_counter , 0 ) ;
2015-03-26 17:41:25 +03:00
dev - > fibs_pushed_no = 0 ;
2012-07-14 16:48:51 +04:00
2011-03-17 12:10:32 +03:00
init = dev - > init ;
2017-02-03 02:53:17 +03:00
if ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE3 ) {
2018-06-18 18:26:47 +03:00
init - > r8 . host_elapsed_seconds =
cpu_to_le32 ( ktime_get_real_seconds ( ) ) ;
2017-02-03 02:53:17 +03:00
src_sync_cmd ( dev , INIT_STRUCT_BASE_ADDRESS ,
2017-02-07 15:59:30 +03:00
lower_32_bits ( dev - > init_pa ) ,
upper_32_bits ( dev - > init_pa ) ,
2017-02-03 02:53:17 +03:00
sizeof ( struct _r8 ) +
( AAC_MAX_HRRQ - 1 ) * sizeof ( struct _rrq ) ,
0 , 0 , 0 , NULL , NULL , NULL , NULL , NULL ) ;
} else {
2018-06-18 18:26:47 +03:00
init - > r7 . host_elapsed_seconds =
cpu_to_le32 ( ktime_get_real_seconds ( ) ) ;
2017-02-03 02:53:17 +03:00
// We can only use a 32 bit address here
src_sync_cmd ( dev , INIT_STRUCT_BASE_ADDRESS ,
( u32 ) ( ulong ) dev - > init_pa , 0 , 0 , 0 , 0 , 0 ,
NULL , NULL , NULL , NULL , NULL ) ;
}
2011-03-17 12:10:32 +03:00
}
/**
* aac_src_check_health
* @ dev : device to check if healthy
*
* Will attempt to determine if the specified adapter is alive and
* capable of handling requests , returning 0 if alive .
*/
static int aac_src_check_health ( struct aac_dev * dev )
{
u32 status = src_readl ( dev , MUnit . OMR ) ;
2017-02-16 23:51:21 +03:00
/*
* Check to see if the board panic ' d .
*/
if ( unlikely ( status & KERNEL_PANIC ) )
goto err_blink ;
2011-03-17 12:10:32 +03:00
/*
* Check to see if the board failed any self tests .
*/
if ( unlikely ( status & SELF_TEST_FAILED ) )
2017-02-16 23:51:21 +03:00
goto err_out ;
2011-03-17 12:10:32 +03:00
/*
2017-02-16 23:51:21 +03:00
* Check to see if the board failed any self tests .
2011-03-17 12:10:32 +03:00
*/
2017-02-16 23:51:21 +03:00
if ( unlikely ( status & MONITOR_PANIC ) )
goto err_out ;
2011-03-17 12:10:32 +03:00
/*
* Wait for the adapter to be up and running .
*/
if ( unlikely ( ! ( status & KERNEL_UP_AND_RUNNING ) ) )
return - 3 ;
/*
* Everything is OK
*/
return 0 ;
2017-02-16 23:51:21 +03:00
err_out :
return - 1 ;
err_blink :
2017-03-02 20:21:33 +03:00
return ( status > > 16 ) & 0xFF ;
2011-03-17 12:10:32 +03:00
}
2017-02-03 02:53:29 +03:00
static inline u32 aac_get_vector ( struct aac_dev * dev )
{
return atomic_inc_return ( & dev - > msix_counter ) % dev - > max_msix ;
}
2011-03-17 12:10:32 +03:00
/**
* aac_src_deliver_message
* @ fib : fib to issue
*
* Will send a fib , returning 0 if successful .
*/
static int aac_src_deliver_message ( struct fib * fib )
{
struct aac_dev * dev = fib - > dev ;
struct aac_queue * q = & dev - > queues - > queue [ AdapNormCmdQueue ] ;
u32 fibsize ;
2012-06-12 00:14:36 +04:00
dma_addr_t address ;
2011-03-17 12:10:32 +03:00
struct aac_fib_xporthdr * pFibX ;
2017-02-03 02:53:29 +03:00
int native_hba ;
2015-08-28 13:38:36 +03:00
# if !defined(writeq)
unsigned long flags ;
# endif
2016-02-04 02:06:00 +03:00
u16 vector_no ;
2011-03-17 12:10:32 +03:00
2015-03-26 17:41:30 +03:00
atomic_inc ( & q - > numpending ) ;
2011-03-17 12:10:32 +03:00
2017-02-03 02:53:29 +03:00
native_hba = ( fib - > flags & FIB_CONTEXT_FLAG_NATIVE_HBA ) ? 1 : 0 ;
if ( dev - > msi_enabled & & dev - > max_msix > 1 & &
( native_hba | | fib - > hw_fib_va - > header . Command ! = AifRequest ) ) {
if ( ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE3 )
& & dev - > sa_firmware )
vector_no = aac_get_vector ( dev ) ;
else
vector_no = fib - > vector_no ;
if ( native_hba ) {
2017-02-03 02:53:31 +03:00
if ( fib - > flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF ) {
struct aac_hba_tm_req * tm_req ;
tm_req = ( struct aac_hba_tm_req * )
fib - > hw_fib_va ;
if ( tm_req - > iu_type = =
HBA_IU_TYPE_SCSI_TM_REQ ) {
( ( struct aac_hba_tm_req * )
fib - > hw_fib_va ) - > reply_qid
= vector_no ;
( ( struct aac_hba_tm_req * )
fib - > hw_fib_va ) - > request_id
+ = ( vector_no < < 16 ) ;
} else {
( ( struct aac_hba_reset_req * )
fib - > hw_fib_va ) - > reply_qid
= vector_no ;
( ( struct aac_hba_reset_req * )
fib - > hw_fib_va ) - > request_id
+ = ( vector_no < < 16 ) ;
}
} else {
( ( struct aac_hba_cmd_req * )
fib - > hw_fib_va ) - > reply_qid
= vector_no ;
( ( struct aac_hba_cmd_req * )
fib - > hw_fib_va ) - > request_id
+ = ( vector_no < < 16 ) ;
}
2017-02-03 02:53:29 +03:00
} else {
fib - > hw_fib_va - > header . Handle + = ( vector_no < < 16 ) ;
}
2016-02-04 02:06:00 +03:00
} else {
vector_no = 0 ;
2015-03-26 17:41:25 +03:00
}
2016-02-04 02:06:00 +03:00
atomic_inc ( & dev - > rrq_outstanding [ vector_no ] ) ;
2017-02-03 02:53:29 +03:00
if ( native_hba ) {
2012-07-14 16:48:51 +04:00
address = fib - > hw_fib_pa ;
2017-02-03 02:53:29 +03:00
fibsize = ( fib - > hbacmd_size + 127 ) / 128 - 1 ;
if ( fibsize > 31 )
fibsize = 31 ;
2012-07-14 16:48:51 +04:00
address | = fibsize ;
2017-02-03 02:53:29 +03:00
# if defined(writeq)
src_writeq ( dev , MUnit . IQN_L , ( u64 ) address ) ;
# else
spin_lock_irqsave ( & fib - > dev - > iq_lock , flags ) ;
src_writel ( dev , MUnit . IQN_H ,
upper_32_bits ( address ) & 0xffffffff ) ;
src_writel ( dev , MUnit . IQN_L , address & 0xffffffff ) ;
spin_unlock_irqrestore ( & fib - > dev - > iq_lock , flags ) ;
# endif
2012-07-14 16:48:51 +04:00
} else {
2017-02-03 02:53:29 +03:00
if ( dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE2 | |
dev - > comm_interface = = AAC_COMM_MESSAGE_TYPE3 ) {
/* Calculate the amount to the fibsize bits */
fibsize = ( le16_to_cpu ( fib - > hw_fib_va - > header . Size )
+ 127 ) / 128 - 1 ;
/* New FIB header, 32-bit */
address = fib - > hw_fib_pa ;
fib - > hw_fib_va - > header . StructType = FIB_MAGIC2 ;
fib - > hw_fib_va - > header . SenderFibAddress =
cpu_to_le32 ( ( u32 ) address ) ;
fib - > hw_fib_va - > header . u . TimeStamp = 0 ;
2017-02-07 15:59:30 +03:00
WARN_ON ( upper_32_bits ( address ) ! = 0L ) ;
2017-02-03 02:53:29 +03:00
} else {
/* Calculate the amount to the fibsize bits */
fibsize = ( sizeof ( struct aac_fib_xporthdr ) +
le16_to_cpu ( fib - > hw_fib_va - > header . Size )
+ 127 ) / 128 - 1 ;
/* Fill XPORT header */
pFibX = ( struct aac_fib_xporthdr * )
( ( unsigned char * ) fib - > hw_fib_va -
sizeof ( struct aac_fib_xporthdr ) ) ;
pFibX - > Handle = fib - > hw_fib_va - > header . Handle ;
pFibX - > HostAddress =
cpu_to_le64 ( ( u64 ) fib - > hw_fib_pa ) ;
pFibX - > Size = cpu_to_le32 (
le16_to_cpu ( fib - > hw_fib_va - > header . Size ) ) ;
address = fib - > hw_fib_pa -
( u64 ) sizeof ( struct aac_fib_xporthdr ) ;
}
if ( fibsize > 31 )
fibsize = 31 ;
2012-07-14 16:48:51 +04:00
address | = fibsize ;
2017-02-03 02:53:29 +03:00
2015-08-28 13:38:36 +03:00
# if defined(writeq)
2017-02-03 02:53:29 +03:00
src_writeq ( dev , MUnit . IQ_L , ( u64 ) address ) ;
2015-08-28 13:38:36 +03:00
# else
2017-02-03 02:53:29 +03:00
spin_lock_irqsave ( & fib - > dev - > iq_lock , flags ) ;
src_writel ( dev , MUnit . IQ_H ,
upper_32_bits ( address ) & 0xffffffff ) ;
src_writel ( dev , MUnit . IQ_L , address & 0xffffffff ) ;
spin_unlock_irqrestore ( & fib - > dev - > iq_lock , flags ) ;
2015-08-28 13:38:36 +03:00
# endif
2017-02-03 02:53:29 +03:00
}
2011-03-17 12:10:32 +03:00
return 0 ;
}
/**
* aac_src_ioremap
2020-07-21 19:41:15 +03:00
* @ dev : device ioremap
2011-03-17 12:10:32 +03:00
* @ size : mapping resize request
*
*/
static int aac_src_ioremap ( struct aac_dev * dev , u32 size )
{
if ( ! size ) {
2012-03-29 19:23:46 +04:00
iounmap ( dev - > regs . src . bar1 ) ;
dev - > regs . src . bar1 = NULL ;
2011-03-17 12:10:32 +03:00
iounmap ( dev - > regs . src . bar0 ) ;
2012-02-09 10:51:04 +04:00
dev - > base = dev - > regs . src . bar0 = NULL ;
2011-03-17 12:10:32 +03:00
return 0 ;
}
dev - > regs . src . bar1 = ioremap ( pci_resource_start ( dev - > pdev , 2 ) ,
AAC_MIN_SRC_BAR1_SIZE ) ;
dev - > base = NULL ;
if ( dev - > regs . src . bar1 = = NULL )
return - 1 ;
2012-06-11 22:05:02 +04:00
dev - > base = dev - > regs . src . bar0 = ioremap ( dev - > base_start , size ) ;
2011-03-17 12:10:32 +03:00
if ( dev - > base = = NULL ) {
iounmap ( dev - > regs . src . bar1 ) ;
dev - > regs . src . bar1 = NULL ;
return - 1 ;
}
dev - > IndexRegs = & ( ( struct src_registers __iomem * )
2012-02-09 10:51:04 +04:00
dev - > base ) - > u . tupelo . IndexRegs ;
return 0 ;
}
/**
* aac_srcv_ioremap
2020-07-21 19:41:15 +03:00
* @ dev : device ioremap
2012-02-09 10:51:04 +04:00
* @ size : mapping resize request
*
*/
static int aac_srcv_ioremap ( struct aac_dev * dev , u32 size )
{
if ( ! size ) {
iounmap ( dev - > regs . src . bar0 ) ;
dev - > base = dev - > regs . src . bar0 = NULL ;
return 0 ;
}
2017-02-03 02:53:22 +03:00
dev - > regs . src . bar1 =
ioremap ( pci_resource_start ( dev - > pdev , 2 ) , AAC_MIN_SRCV_BAR1_SIZE ) ;
dev - > base = NULL ;
if ( dev - > regs . src . bar1 = = NULL )
return - 1 ;
2012-06-11 22:05:02 +04:00
dev - > base = dev - > regs . src . bar0 = ioremap ( dev - > base_start , size ) ;
2017-02-03 02:53:22 +03:00
if ( dev - > base = = NULL ) {
iounmap ( dev - > regs . src . bar1 ) ;
dev - > regs . src . bar1 = NULL ;
2012-02-09 10:51:04 +04:00
return - 1 ;
2017-02-03 02:53:22 +03:00
}
2012-02-09 10:51:04 +04:00
dev - > IndexRegs = & ( ( struct src_registers __iomem * )
dev - > base ) - > u . denali . IndexRegs ;
2011-03-17 12:10:32 +03:00
return 0 ;
}
2017-02-16 23:51:16 +03:00
void aac_set_intx_mode ( struct aac_dev * dev )
2017-02-03 02:53:33 +03:00
{
if ( dev - > msi_enabled ) {
aac_src_access_devreg ( dev , AAC_ENABLE_INTX ) ;
dev - > msi_enabled = 0 ;
msleep ( 5000 ) ; /* Delay 5 seconds */
}
}
2018-02-07 19:40:57 +03:00
static void aac_clear_omr ( struct aac_dev * dev )
{
u32 omr_value = 0 ;
omr_value = src_readl ( dev , MUnit . OMR ) ;
/*
* Check for PCI Errors or Kernel Panic
*/
if ( ( omr_value = = INVALID_OMR ) | | ( omr_value & KERNEL_PANIC ) )
omr_value = 0 ;
/*
* Preserve MSIX Value if any
*/
src_writel ( dev , MUnit . OMR , omr_value & AAC_INT_MODE_MSIX ) ;
src_readl ( dev , MUnit . OMR ) ;
}
2017-02-16 23:51:22 +03:00
static void aac_dump_fw_fib_iop_reset ( struct aac_dev * dev )
{
__le32 supported_options3 ;
if ( ! aac_fib_dump )
return ;
supported_options3 = dev - > supplement_adapter_info . supported_options3 ;
if ( ! ( supported_options3 & AAC_OPTION_SUPPORTED3_IOP_RESET_FIB_DUMP ) )
return ;
aac_adapter_sync_cmd ( dev , IOP_RESET_FW_FIB_DUMP ,
0 , 0 , 0 , 0 , 0 , 0 , NULL , NULL , NULL , NULL , NULL ) ;
}
2017-05-10 19:39:45 +03:00
static bool aac_is_ctrl_up_and_running ( struct aac_dev * dev )
{
bool ctrl_up = true ;
unsigned long status , start ;
bool is_up = false ;
start = jiffies ;
do {
schedule ( ) ;
status = src_readl ( dev , MUnit . OMR ) ;
if ( status = = 0xffffffff )
status = 0 ;
if ( status & KERNEL_BOOTING ) {
start = jiffies ;
continue ;
}
if ( time_after ( jiffies , start + HZ * SOFT_RESET_TIME ) ) {
ctrl_up = false ;
break ;
}
is_up = status & KERNEL_UP_AND_RUNNING ;
} while ( ! is_up ) ;
return ctrl_up ;
}
2019-10-15 09:22:00 +03:00
static void aac_src_drop_io ( struct aac_dev * dev )
{
if ( ! dev - > soft_reset_support )
return ;
aac_adapter_sync_cmd ( dev , DROP_IO ,
0 , 0 , 0 , 0 , 0 , 0 , NULL , NULL , NULL , NULL , NULL ) ;
}
2017-05-10 19:39:44 +03:00
static void aac_notify_fw_of_iop_reset ( struct aac_dev * dev )
2011-03-17 12:10:32 +03:00
{
2017-05-10 19:39:44 +03:00
aac_adapter_sync_cmd ( dev , IOP_RESET_ALWAYS , 0 , 0 , 0 , 0 , 0 , 0 , NULL ,
NULL , NULL , NULL , NULL ) ;
2019-10-15 09:22:00 +03:00
aac_src_drop_io ( dev ) ;
2017-05-10 19:39:44 +03:00
}
2011-03-17 12:10:32 +03:00
2017-05-10 19:39:44 +03:00
static void aac_send_iop_reset ( struct aac_dev * dev )
{
2017-02-16 23:51:22 +03:00
aac_dump_fw_fib_iop_reset ( dev ) ;
2017-05-10 19:39:44 +03:00
aac_notify_fw_of_iop_reset ( dev ) ;
2017-02-03 02:53:33 +03:00
aac_set_intx_mode ( dev ) ;
2018-02-07 19:40:57 +03:00
aac_clear_omr ( dev ) ;
2017-05-10 19:39:43 +03:00
src_writel ( dev , MUnit . IDR , IOP_SRC_RESET_MASK ) ;
2017-09-19 18:11:55 +03:00
msleep ( 5000 ) ;
2017-02-03 02:53:33 +03:00
}
static void aac_send_hardware_soft_reset ( struct aac_dev * dev )
{
u_int32_t val ;
2018-02-07 19:40:57 +03:00
aac_clear_omr ( dev ) ;
2017-02-03 02:53:33 +03:00
val = readl ( ( ( char * ) ( dev - > base ) + IBW_SWR_OFFSET ) ) ;
val | = 0x01 ;
writel ( val , ( ( char * ) ( dev - > base ) + IBW_SWR_OFFSET ) ) ;
msleep_interruptible ( 20000 ) ;
}
static int aac_src_restart_adapter ( struct aac_dev * dev , int bled , u8 reset_type )
{
2017-05-10 19:39:45 +03:00
bool is_ctrl_up ;
2017-05-10 19:39:46 +03:00
int ret = 0 ;
2017-02-03 02:53:33 +03:00
if ( bled < 0 )
goto invalid_out ;
if ( bled )
2017-05-10 19:39:51 +03:00
dev_err ( & dev - > pdev - > dev , " adapter kernel panic'd %x. \n " , bled ) ;
2015-03-26 17:41:25 +03:00
2017-02-16 23:51:20 +03:00
/*
* When there is a BlinkLED , IOP_RESET has not effect
*/
if ( bled > = 2 & & dev - > sa_firmware & & reset_type & HW_IOP_RESET )
reset_type & = ~ HW_IOP_RESET ;
2017-02-03 02:53:33 +03:00
dev - > a_ops . adapter_enable_int = aac_src_disable_interrupt ;
2015-03-26 17:41:25 +03:00
2017-05-10 19:39:51 +03:00
dev_err ( & dev - > pdev - > dev , " Controller reset type is %d \n " , reset_type ) ;
2017-05-10 19:39:47 +03:00
if ( reset_type & HW_IOP_RESET ) {
2017-05-10 19:39:51 +03:00
dev_info ( & dev - > pdev - > dev , " Issuing IOP reset \n " ) ;
2017-05-10 19:39:44 +03:00
aac_send_iop_reset ( dev ) ;
2017-05-10 19:39:45 +03:00
/*
* Creates a delay or wait till up and running comes thru
*/
is_ctrl_up = aac_is_ctrl_up_and_running ( dev ) ;
if ( ! is_ctrl_up )
dev_err ( & dev - > pdev - > dev , " IOP reset failed \n " ) ;
2017-05-10 19:39:51 +03:00
else {
2018-01-15 18:18:36 +03:00
dev_info ( & dev - > pdev - > dev , " IOP reset succeeded \n " ) ;
2017-05-10 19:39:45 +03:00
goto set_startup ;
2017-05-10 19:39:51 +03:00
}
2017-05-10 19:39:47 +03:00
}
2017-05-10 19:39:45 +03:00
2017-05-10 19:39:47 +03:00
if ( ! dev - > sa_firmware ) {
2017-05-10 19:39:51 +03:00
dev_err ( & dev - > pdev - > dev , " ARC Reset attempt failed \n " ) ;
2017-05-10 19:39:47 +03:00
ret = - ENODEV ;
goto out ;
}
2017-05-10 19:39:46 +03:00
2017-05-10 19:39:47 +03:00
if ( reset_type & HW_SOFT_RESET ) {
2017-05-10 19:39:51 +03:00
dev_info ( & dev - > pdev - > dev , " Issuing SOFT reset \n " ) ;
2017-05-10 19:39:46 +03:00
aac_send_hardware_soft_reset ( dev ) ;
dev - > msi_enabled = 0 ;
is_ctrl_up = aac_is_ctrl_up_and_running ( dev ) ;
if ( ! is_ctrl_up ) {
dev_err ( & dev - > pdev - > dev , " SOFT reset failed \n " ) ;
ret = - ENODEV ;
goto out ;
2017-05-10 19:39:51 +03:00
} else
2018-01-15 18:18:36 +03:00
dev_info ( & dev - > pdev - > dev , " SOFT reset succeeded \n " ) ;
2011-03-17 12:10:32 +03:00
}
2017-05-10 19:39:45 +03:00
set_startup :
2011-03-17 12:10:32 +03:00
if ( startup_timeout < 300 )
startup_timeout = 300 ;
2017-05-10 19:39:46 +03:00
out :
return ret ;
2017-05-10 19:39:47 +03:00
invalid_out :
if ( src_readl ( dev , MUnit . OMR ) & KERNEL_PANIC )
ret = - ENODEV ;
goto out ;
2011-03-17 12:10:32 +03:00
}
/**
* aac_src_select_comm - Select communications method
* @ dev : Adapter
* @ comm : communications method
*/
2016-09-04 09:47:10 +03:00
static int aac_src_select_comm ( struct aac_dev * dev , int comm )
2011-03-17 12:10:32 +03:00
{
switch ( comm ) {
case AAC_COMM_MESSAGE :
dev - > a_ops . adapter_intr = aac_src_intr_message ;
dev - > a_ops . adapter_deliver = aac_src_deliver_message ;
break ;
default :
return 1 ;
}
return 0 ;
}
/**
* aac_src_init - initialize an Cardinal Frey Bar card
* @ dev : device to configure
*
*/
int aac_src_init ( struct aac_dev * dev )
{
unsigned long start ;
unsigned long status ;
int restart = 0 ;
int instance = dev - > id ;
const char * name = dev - > name ;
dev - > a_ops . adapter_ioremap = aac_src_ioremap ;
dev - > a_ops . adapter_comm = aac_src_select_comm ;
dev - > base_size = AAC_MIN_SRC_BAR0_SIZE ;
if ( aac_adapter_ioremap ( dev , dev - > base_size ) ) {
printk ( KERN_WARNING " %s: unable to map adapter. \n " , name ) ;
goto error_iounmap ;
}
/* Failure to reset here is an option ... */
dev - > a_ops . adapter_sync_cmd = src_sync_cmd ;
dev - > a_ops . adapter_enable_int = aac_src_disable_interrupt ;
2017-11-18 00:14:54 +03:00
if ( dev - > init_reset ) {
dev - > init_reset = false ;
if ( ! aac_src_restart_adapter ( dev , 0 , IOP_HWSOFT_RESET ) )
+ + restart ;
}
2011-03-17 12:10:32 +03:00
/*
* Check to see if the board panic ' d while booting .
*/
status = src_readl ( dev , MUnit . OMR ) ;
if ( status & KERNEL_PANIC ) {
2017-02-03 02:53:33 +03:00
if ( aac_src_restart_adapter ( dev ,
aac_src_check_health ( dev ) , IOP_HWSOFT_RESET ) )
2011-03-17 12:10:32 +03:00
goto error_iounmap ;
+ + restart ;
}
/*
* Check to see if the board failed any self tests .
*/
status = src_readl ( dev , MUnit . OMR ) ;
if ( status & SELF_TEST_FAILED ) {
printk ( KERN_ERR " %s%d: adapter self-test failed. \n " ,
dev - > name , instance ) ;
goto error_iounmap ;
}
/*
* Check to see if the monitor panic ' d while booting .
*/
if ( status & MONITOR_PANIC ) {
printk ( KERN_ERR " %s%d: adapter monitor panic. \n " ,
dev - > name , instance ) ;
goto error_iounmap ;
}
start = jiffies ;
/*
* Wait for the adapter to be up and running . Wait up to 3 minutes
*/
while ( ! ( ( status = src_readl ( dev , MUnit . OMR ) ) &
KERNEL_UP_AND_RUNNING ) ) {
if ( ( restart & &
( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) ) | |
time_after ( jiffies , start + HZ * startup_timeout ) ) {
printk ( KERN_ERR " %s%d: adapter kernel failed to start, init status = %lx. \n " ,
dev - > name , instance , status ) ;
goto error_iounmap ;
}
if ( ! restart & &
( ( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) | |
time_after ( jiffies , start + HZ *
( ( startup_timeout > 60 )
? ( startup_timeout - 60 )
: ( startup_timeout / 2 ) ) ) ) ) {
if ( likely ( ! aac_src_restart_adapter ( dev ,
2017-02-03 02:53:33 +03:00
aac_src_check_health ( dev ) , IOP_HWSOFT_RESET ) ) )
2011-03-17 12:10:32 +03:00
start = jiffies ;
+ + restart ;
}
msleep ( 1 ) ;
}
if ( restart & & aac_commit )
aac_commit = 1 ;
/*
* Fill in the common function dispatch table .
*/
dev - > a_ops . adapter_interrupt = aac_src_interrupt_adapter ;
dev - > a_ops . adapter_disable_int = aac_src_disable_interrupt ;
2015-03-26 17:41:28 +03:00
dev - > a_ops . adapter_enable_int = aac_src_disable_interrupt ;
2011-03-17 12:10:32 +03:00
dev - > a_ops . adapter_notify = aac_src_notify_adapter ;
dev - > a_ops . adapter_sync_cmd = src_sync_cmd ;
dev - > a_ops . adapter_check_health = aac_src_check_health ;
dev - > a_ops . adapter_restart = aac_src_restart_adapter ;
2015-08-28 13:38:34 +03:00
dev - > a_ops . adapter_start = aac_src_start_adapter ;
2011-03-17 12:10:32 +03:00
/*
* First clear out all interrupts . Then enable the one ' s that we
* can handle .
*/
aac_adapter_comm ( dev , AAC_COMM_MESSAGE ) ;
aac_adapter_disable_int ( dev ) ;
src_writel ( dev , MUnit . ODR_C , 0xffffffff ) ;
aac_adapter_enable_int ( dev ) ;
if ( aac_init_adapter ( dev ) = = NULL )
goto error_iounmap ;
if ( dev - > comm_interface ! = AAC_COMM_MESSAGE_TYPE1 )
goto error_iounmap ;
2015-08-28 13:38:35 +03:00
dev - > msi = ! pci_enable_msi ( dev - > pdev ) ;
2011-03-17 12:10:32 +03:00
2015-03-26 17:41:25 +03:00
dev - > aac_msix [ 0 ] . vector_no = 0 ;
dev - > aac_msix [ 0 ] . dev = dev ;
2011-03-17 12:10:32 +03:00
if ( request_irq ( dev - > pdev - > irq , dev - > a_ops . adapter_intr ,
2015-03-26 17:41:25 +03:00
IRQF_SHARED , " aacraid " , & ( dev - > aac_msix [ 0 ] ) ) < 0 ) {
2011-03-17 12:10:32 +03:00
if ( dev - > msi )
pci_disable_msi ( dev - > pdev ) ;
printk ( KERN_ERR " %s%d: Interrupt unavailable. \n " ,
name , instance ) ;
goto error_iounmap ;
}
dev - > dbg_base = pci_resource_start ( dev - > pdev , 2 ) ;
dev - > dbg_base_mapped = dev - > regs . src . bar1 ;
dev - > dbg_size = AAC_MIN_SRC_BAR1_SIZE ;
2015-03-26 17:41:28 +03:00
dev - > a_ops . adapter_enable_int = aac_src_enable_interrupt_message ;
2011-03-17 12:10:32 +03:00
aac_adapter_enable_int ( dev ) ;
2012-02-09 10:51:04 +04:00
if ( ! dev - > sync_mode ) {
/*
* Tell the adapter that all is configured , and it can
* start accepting requests
*/
aac_src_start_adapter ( dev ) ;
}
return 0 ;
error_iounmap :
return - 1 ;
}
2018-02-07 19:40:56 +03:00
static int aac_src_wait_sync ( struct aac_dev * dev , int * status )
{
unsigned long start = jiffies ;
unsigned long usecs = 0 ;
int delay = 5 * HZ ;
int rc = 1 ;
while ( time_before ( jiffies , start + delay ) ) {
/*
* Delay 5 microseconds to let Mon960 get info .
*/
udelay ( 5 ) ;
/*
* Mon960 will set doorbell0 bit when it has completed the
* command .
*/
if ( aac_src_get_sync_status ( dev ) & OUTBOUNDDOORBELL_0 ) {
/*
* Clear : the doorbell .
*/
if ( dev - > msi_enabled )
aac_src_access_devreg ( dev , AAC_CLEAR_SYNC_BIT ) ;
else
src_writel ( dev , MUnit . ODR_C ,
OUTBOUNDDOORBELL_0 < < SRC_ODR_SHIFT ) ;
rc = 0 ;
break ;
}
/*
* Yield the processor in case we are slow
*/
usecs = 1 * USEC_PER_MSEC ;
usleep_range ( usecs , usecs + 50 ) ;
}
/*
* Pull the synch status from Mailbox 0.
*/
if ( status & & ! rc ) {
status [ 0 ] = readl ( & dev - > IndexRegs - > Mailbox [ 0 ] ) ;
status [ 1 ] = readl ( & dev - > IndexRegs - > Mailbox [ 1 ] ) ;
status [ 2 ] = readl ( & dev - > IndexRegs - > Mailbox [ 2 ] ) ;
status [ 3 ] = readl ( & dev - > IndexRegs - > Mailbox [ 3 ] ) ;
status [ 4 ] = readl ( & dev - > IndexRegs - > Mailbox [ 4 ] ) ;
}
return rc ;
}
/**
* aac_src_soft_reset - perform soft reset to speed up
* access
*
* Assumptions : That the controller is in a state where we can
* bring it back to life with an init struct . We can only use
* fast sync commands , as the timeout is 5 seconds .
*
* @ dev : device to configure
*
*/
static int aac_src_soft_reset ( struct aac_dev * dev )
{
u32 status_omr = src_readl ( dev , MUnit . OMR ) ;
u32 status [ 5 ] ;
int rc = 1 ;
int state = 0 ;
char * state_str [ 7 ] = {
" GET_ADAPTER_PROPERTIES Failed " ,
" GET_ADAPTER_PROPERTIES timeout " ,
" SOFT_RESET not supported " ,
" DROP_IO Failed " ,
" DROP_IO timeout " ,
" Check Health failed "
} ;
if ( status_omr = = INVALID_OMR )
return 1 ; // pcie hosed
if ( ! ( status_omr & KERNEL_UP_AND_RUNNING ) )
return 1 ; // not up and running
/*
* We go into soft reset mode to allow us to handle response
*/
dev - > in_soft_reset = 1 ;
dev - > msi_enabled = status_omr & AAC_INT_MODE_MSIX ;
/* Get adapter properties */
rc = aac_adapter_sync_cmd ( dev , GET_ADAPTER_PROPERTIES , 0 , 0 , 0 ,
0 , 0 , 0 , status + 0 , status + 1 , status + 2 , status + 3 , status + 4 ) ;
if ( rc )
goto out ;
state + + ;
if ( aac_src_wait_sync ( dev , status ) ) {
rc = 1 ;
goto out ;
}
state + + ;
if ( ! ( status [ 1 ] & le32_to_cpu ( AAC_OPT_EXTENDED ) & &
( status [ 4 ] & le32_to_cpu ( AAC_EXTOPT_SOFT_RESET ) ) ) ) {
rc = 2 ;
goto out ;
}
if ( ( status [ 1 ] & le32_to_cpu ( AAC_OPT_EXTENDED ) ) & &
( status [ 4 ] & le32_to_cpu ( AAC_EXTOPT_SA_FIRMWARE ) ) )
dev - > sa_firmware = 1 ;
state + + ;
rc = aac_adapter_sync_cmd ( dev , DROP_IO , 0 , 0 , 0 , 0 , 0 , 0 ,
status + 0 , status + 1 , status + 2 , status + 3 , status + 4 ) ;
if ( rc )
goto out ;
state + + ;
if ( aac_src_wait_sync ( dev , status ) ) {
rc = 3 ;
goto out ;
}
if ( status [ 1 ] )
dev_err ( & dev - > pdev - > dev , " %s: %d outstanding I/O pending \n " ,
__func__ , status [ 1 ] ) ;
state + + ;
rc = aac_src_check_health ( dev ) ;
out :
dev - > in_soft_reset = 0 ;
dev - > msi_enabled = 0 ;
if ( rc )
dev_err ( & dev - > pdev - > dev , " %s: %s status = %d " , __func__ ,
state_str [ state ] , rc ) ;
2019-02-02 13:40:52 +03:00
return rc ;
2018-02-07 19:40:56 +03:00
}
2012-02-09 10:51:04 +04:00
/**
* aac_srcv_init - initialize an SRCv card
* @ dev : device to configure
*
*/
int aac_srcv_init ( struct aac_dev * dev )
{
unsigned long start ;
unsigned long status ;
int restart = 0 ;
int instance = dev - > id ;
const char * name = dev - > name ;
dev - > a_ops . adapter_ioremap = aac_srcv_ioremap ;
dev - > a_ops . adapter_comm = aac_src_select_comm ;
dev - > base_size = AAC_MIN_SRCV_BAR0_SIZE ;
if ( aac_adapter_ioremap ( dev , dev - > base_size ) ) {
printk ( KERN_WARNING " %s: unable to map adapter. \n " , name ) ;
goto error_iounmap ;
}
/* Failure to reset here is an option ... */
dev - > a_ops . adapter_sync_cmd = src_sync_cmd ;
dev - > a_ops . adapter_enable_int = aac_src_disable_interrupt ;
2017-11-18 00:14:54 +03:00
if ( dev - > init_reset ) {
dev - > init_reset = false ;
2018-02-07 19:40:56 +03:00
if ( aac_src_soft_reset ( dev ) ) {
aac_src_restart_adapter ( dev , 0 , IOP_HWSOFT_RESET ) ;
2017-11-18 00:14:54 +03:00
+ + restart ;
2018-02-07 19:40:56 +03:00
}
2017-11-18 00:14:54 +03:00
}
2013-03-19 11:07:26 +04:00
/*
* Check to see if flash update is running .
* Wait for the adapter to be up and running . Wait up to 5 minutes
*/
status = src_readl ( dev , MUnit . OMR ) ;
if ( status & FLASH_UPD_PENDING ) {
start = jiffies ;
do {
status = src_readl ( dev , MUnit . OMR ) ;
if ( time_after ( jiffies , start + HZ * FWUPD_TIMEOUT ) ) {
printk ( KERN_ERR " %s%d: adapter flash update failed. \n " ,
dev - > name , instance ) ;
goto error_iounmap ;
}
} while ( ! ( status & FLASH_UPD_SUCCESS ) & &
! ( status & FLASH_UPD_FAILED ) ) ;
/* Delay 10 seconds.
* Because right now FW is doing a soft reset ,
* do not read scratch pad register at this time
*/
ssleep ( 10 ) ;
}
2011-03-17 12:10:32 +03:00
/*
2012-02-09 10:51:04 +04:00
* Check to see if the board panic ' d while booting .
2011-03-17 12:10:32 +03:00
*/
2012-02-09 10:51:04 +04:00
status = src_readl ( dev , MUnit . OMR ) ;
if ( status & KERNEL_PANIC ) {
2017-02-03 02:53:33 +03:00
if ( aac_src_restart_adapter ( dev ,
aac_src_check_health ( dev ) , IOP_HWSOFT_RESET ) )
2012-02-09 10:51:04 +04:00
goto error_iounmap ;
+ + restart ;
}
/*
* Check to see if the board failed any self tests .
*/
status = src_readl ( dev , MUnit . OMR ) ;
if ( status & SELF_TEST_FAILED ) {
printk ( KERN_ERR " %s%d: adapter self-test failed. \n " , dev - > name , instance ) ;
goto error_iounmap ;
}
/*
* Check to see if the monitor panic ' d while booting .
*/
if ( status & MONITOR_PANIC ) {
printk ( KERN_ERR " %s%d: adapter monitor panic. \n " , dev - > name , instance ) ;
goto error_iounmap ;
}
2018-02-07 19:40:56 +03:00
2012-02-09 10:51:04 +04:00
start = jiffies ;
/*
* Wait for the adapter to be up and running . Wait up to 3 minutes
*/
2018-02-07 19:40:56 +03:00
do {
status = src_readl ( dev , MUnit . OMR ) ;
if ( status = = INVALID_OMR )
status = 0 ;
2012-02-09 10:51:04 +04:00
if ( ( restart & &
( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) ) | |
time_after ( jiffies , start + HZ * startup_timeout ) ) {
printk ( KERN_ERR " %s%d: adapter kernel failed to start, init status = %lx. \n " ,
dev - > name , instance , status ) ;
goto error_iounmap ;
}
if ( ! restart & &
( ( status & ( KERNEL_PANIC | SELF_TEST_FAILED | MONITOR_PANIC ) ) | |
time_after ( jiffies , start + HZ *
( ( startup_timeout > 60 )
? ( startup_timeout - 60 )
: ( startup_timeout / 2 ) ) ) ) ) {
2017-02-03 02:53:33 +03:00
if ( likely ( ! aac_src_restart_adapter ( dev ,
aac_src_check_health ( dev ) , IOP_HWSOFT_RESET ) ) )
2012-02-09 10:51:04 +04:00
start = jiffies ;
+ + restart ;
}
msleep ( 1 ) ;
2018-02-07 19:40:56 +03:00
} while ( ! ( status & KERNEL_UP_AND_RUNNING ) ) ;
2012-02-09 10:51:04 +04:00
if ( restart & & aac_commit )
aac_commit = 1 ;
/*
* Fill in the common function dispatch table .
*/
dev - > a_ops . adapter_interrupt = aac_src_interrupt_adapter ;
dev - > a_ops . adapter_disable_int = aac_src_disable_interrupt ;
2015-03-26 17:41:28 +03:00
dev - > a_ops . adapter_enable_int = aac_src_disable_interrupt ;
2012-02-09 10:51:04 +04:00
dev - > a_ops . adapter_notify = aac_src_notify_adapter ;
dev - > a_ops . adapter_sync_cmd = src_sync_cmd ;
dev - > a_ops . adapter_check_health = aac_src_check_health ;
dev - > a_ops . adapter_restart = aac_src_restart_adapter ;
2015-08-28 13:38:34 +03:00
dev - > a_ops . adapter_start = aac_src_start_adapter ;
2012-02-09 10:51:04 +04:00
/*
* First clear out all interrupts . Then enable the one ' s that we
* can handle .
*/
aac_adapter_comm ( dev , AAC_COMM_MESSAGE ) ;
aac_adapter_disable_int ( dev ) ;
src_writel ( dev , MUnit . ODR_C , 0xffffffff ) ;
aac_adapter_enable_int ( dev ) ;
2011-03-17 12:10:32 +03:00
2012-02-09 10:51:04 +04:00
if ( aac_init_adapter ( dev ) = = NULL )
goto error_iounmap ;
2017-02-03 02:53:17 +03:00
if ( ( dev - > comm_interface ! = AAC_COMM_MESSAGE_TYPE2 ) & &
( dev - > comm_interface ! = AAC_COMM_MESSAGE_TYPE3 ) )
2012-02-09 10:51:04 +04:00
goto error_iounmap ;
2015-03-26 17:41:25 +03:00
if ( dev - > msi_enabled )
aac_src_access_devreg ( dev , AAC_ENABLE_MSIX ) ;
2015-08-28 13:38:38 +03:00
if ( aac_acquire_irq ( dev ) )
goto error_iounmap ;
2017-02-03 02:53:22 +03:00
dev - > dbg_base = pci_resource_start ( dev - > pdev , 2 ) ;
dev - > dbg_base_mapped = dev - > regs . src . bar1 ;
dev - > dbg_size = AAC_MIN_SRCV_BAR1_SIZE ;
2015-03-26 17:41:28 +03:00
dev - > a_ops . adapter_enable_int = aac_src_enable_interrupt_message ;
2012-02-09 10:51:04 +04:00
aac_adapter_enable_int ( dev ) ;
if ( ! dev - > sync_mode ) {
/*
* Tell the adapter that all is configured , and it can
* start accepting requests
*/
aac_src_start_adapter ( dev ) ;
}
2011-03-17 12:10:32 +03:00
return 0 ;
error_iounmap :
return - 1 ;
}
2012-02-09 10:51:04 +04:00
2015-03-26 17:41:25 +03:00
void aac_src_access_devreg ( struct aac_dev * dev , int mode )
{
u_int32_t val ;
switch ( mode ) {
case AAC_ENABLE_INTERRUPT :
src_writel ( dev ,
MUnit . OIMR ,
dev - > OIMR = ( dev - > msi_enabled ?
AAC_INT_ENABLE_TYPE1_MSIX :
AAC_INT_ENABLE_TYPE1_INTX ) ) ;
break ;
case AAC_DISABLE_INTERRUPT :
src_writel ( dev ,
MUnit . OIMR ,
dev - > OIMR = AAC_INT_DISABLE_ALL ) ;
break ;
case AAC_ENABLE_MSIX :
/* set bit 6 */
val = src_readl ( dev , MUnit . IDR ) ;
val | = 0x40 ;
src_writel ( dev , MUnit . IDR , val ) ;
src_readl ( dev , MUnit . IDR ) ;
/* unmask int. */
val = PMC_ALL_INTERRUPT_BITS ;
src_writel ( dev , MUnit . IOAR , val ) ;
val = src_readl ( dev , MUnit . OIMR ) ;
src_writel ( dev ,
MUnit . OIMR ,
val & ( ~ ( PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0 ) ) ) ;
break ;
case AAC_DISABLE_MSIX :
/* reset bit 6 */
val = src_readl ( dev , MUnit . IDR ) ;
val & = ~ 0x40 ;
src_writel ( dev , MUnit . IDR , val ) ;
src_readl ( dev , MUnit . IDR ) ;
break ;
case AAC_CLEAR_AIF_BIT :
/* set bit 5 */
val = src_readl ( dev , MUnit . IDR ) ;
val | = 0x20 ;
src_writel ( dev , MUnit . IDR , val ) ;
src_readl ( dev , MUnit . IDR ) ;
break ;
case AAC_CLEAR_SYNC_BIT :
/* set bit 4 */
val = src_readl ( dev , MUnit . IDR ) ;
val | = 0x10 ;
src_writel ( dev , MUnit . IDR , val ) ;
src_readl ( dev , MUnit . IDR ) ;
break ;
case AAC_ENABLE_INTX :
/* set bit 7 */
val = src_readl ( dev , MUnit . IDR ) ;
val | = 0x80 ;
src_writel ( dev , MUnit . IDR , val ) ;
src_readl ( dev , MUnit . IDR ) ;
/* unmask int. */
val = PMC_ALL_INTERRUPT_BITS ;
src_writel ( dev , MUnit . IOAR , val ) ;
src_readl ( dev , MUnit . IOAR ) ;
val = src_readl ( dev , MUnit . OIMR ) ;
src_writel ( dev , MUnit . OIMR ,
val & ( ~ ( PMC_GLOBAL_INT_BIT2 ) ) ) ;
break ;
default :
break ;
}
}
static int aac_src_get_sync_status ( struct aac_dev * dev )
{
2018-02-07 19:40:58 +03:00
int msix_val = 0 ;
int legacy_val = 0 ;
2015-03-26 17:41:25 +03:00
2018-02-07 19:40:58 +03:00
msix_val = src_readl ( dev , MUnit . ODR_MSI ) & SRC_MSI_READ_MASK ? 1 : 0 ;
2015-03-26 17:41:25 +03:00
2018-02-07 19:40:58 +03:00
if ( ! dev - > msi_enabled ) {
/*
* if Legacy int status indicates cmd is not complete
* sample MSIx register to see if it indiactes cmd complete ,
* if yes set the controller in MSIx mode and consider cmd
* completed
*/
legacy_val = src_readl ( dev , MUnit . ODR_R ) > > SRC_ODR_SHIFT ;
if ( ! ( legacy_val & 1 ) & & msix_val )
dev - > msi_enabled = 1 ;
return legacy_val ;
}
2015-03-26 17:41:25 +03:00
2018-02-07 19:40:58 +03:00
return msix_val ;
2015-03-26 17:41:25 +03:00
}