2020-05-01 09:58:50 -05:00
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2019-04-12 11:05:13 -05:00
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
# include <linux/pci.h>
# include "ops.h"
static
bool snd_sof_pci_update_bits_unlocked ( struct snd_sof_dev * sdev , u32 offset ,
u32 mask , u32 value )
{
struct pci_dev * pci = to_pci_dev ( sdev - > dev ) ;
unsigned int old , new ;
2019-05-06 17:02:23 +02:00
u32 ret = 0 ;
2019-04-12 11:05:13 -05:00
pci_read_config_dword ( pci , offset , & ret ) ;
old = ret ;
dev_dbg ( sdev - > dev , " Debug PCIR: %8.8x at %8.8x \n " , old & mask , offset ) ;
new = ( old & ~ mask ) | ( value & mask ) ;
if ( old = = new )
return false ;
pci_write_config_dword ( pci , offset , new ) ;
dev_dbg ( sdev - > dev , " Debug PCIW: %8.8x at %8.8x \n " , value ,
offset ) ;
return true ;
}
bool snd_sof_pci_update_bits ( struct snd_sof_dev * sdev , u32 offset ,
u32 mask , u32 value )
{
unsigned long flags ;
bool change ;
spin_lock_irqsave ( & sdev - > hw_lock , flags ) ;
change = snd_sof_pci_update_bits_unlocked ( sdev , offset , mask , value ) ;
spin_unlock_irqrestore ( & sdev - > hw_lock , flags ) ;
return change ;
}
EXPORT_SYMBOL ( snd_sof_pci_update_bits ) ;
bool snd_sof_dsp_update_bits_unlocked ( struct snd_sof_dev * sdev , u32 bar ,
u32 offset , u32 mask , u32 value )
{
unsigned int old , new ;
u32 ret ;
ret = snd_sof_dsp_read ( sdev , bar , offset ) ;
old = ret ;
new = ( old & ~ mask ) | ( value & mask ) ;
if ( old = = new )
return false ;
snd_sof_dsp_write ( sdev , bar , offset , new ) ;
return true ;
}
EXPORT_SYMBOL ( snd_sof_dsp_update_bits_unlocked ) ;
bool snd_sof_dsp_update_bits64_unlocked ( struct snd_sof_dev * sdev , u32 bar ,
u32 offset , u64 mask , u64 value )
{
u64 old , new ;
old = snd_sof_dsp_read64 ( sdev , bar , offset ) ;
new = ( old & ~ mask ) | ( value & mask ) ;
if ( old = = new )
return false ;
snd_sof_dsp_write64 ( sdev , bar , offset , new ) ;
return true ;
}
EXPORT_SYMBOL ( snd_sof_dsp_update_bits64_unlocked ) ;
/* This is for registers bits with attribute RWC */
bool snd_sof_dsp_update_bits ( struct snd_sof_dev * sdev , u32 bar , u32 offset ,
u32 mask , u32 value )
{
unsigned long flags ;
bool change ;
spin_lock_irqsave ( & sdev - > hw_lock , flags ) ;
change = snd_sof_dsp_update_bits_unlocked ( sdev , bar , offset , mask ,
value ) ;
spin_unlock_irqrestore ( & sdev - > hw_lock , flags ) ;
return change ;
}
EXPORT_SYMBOL ( snd_sof_dsp_update_bits ) ;
bool snd_sof_dsp_update_bits64 ( struct snd_sof_dev * sdev , u32 bar , u32 offset ,
u64 mask , u64 value )
{
unsigned long flags ;
bool change ;
spin_lock_irqsave ( & sdev - > hw_lock , flags ) ;
change = snd_sof_dsp_update_bits64_unlocked ( sdev , bar , offset , mask ,
value ) ;
spin_unlock_irqrestore ( & sdev - > hw_lock , flags ) ;
return change ;
}
EXPORT_SYMBOL ( snd_sof_dsp_update_bits64 ) ;
static
void snd_sof_dsp_update_bits_forced_unlocked ( struct snd_sof_dev * sdev , u32 bar ,
u32 offset , u32 mask , u32 value )
{
unsigned int old , new ;
u32 ret ;
ret = snd_sof_dsp_read ( sdev , bar , offset ) ;
old = ret ;
new = ( old & ~ mask ) | ( value & mask ) ;
snd_sof_dsp_write ( sdev , bar , offset , new ) ;
}
/* This is for registers bits with attribute RWC */
void snd_sof_dsp_update_bits_forced ( struct snd_sof_dev * sdev , u32 bar ,
u32 offset , u32 mask , u32 value )
{
unsigned long flags ;
spin_lock_irqsave ( & sdev - > hw_lock , flags ) ;
snd_sof_dsp_update_bits_forced_unlocked ( sdev , bar , offset , mask , value ) ;
spin_unlock_irqrestore ( & sdev - > hw_lock , flags ) ;
}
EXPORT_SYMBOL ( snd_sof_dsp_update_bits_forced ) ;
2021-12-23 13:36:13 +02:00
/**
* snd_sof_dsp_panic - handle a received DSP panic message
* @ sdev : Pointer to the device ' s sdev
* @ offset : offset of panic information
* @ non_recoverable : the panic is fatal , no recovery will be done by the caller
*/
void snd_sof_dsp_panic ( struct snd_sof_dev * sdev , u32 offset , bool non_recoverable )
2019-04-12 11:05:13 -05:00
{
/*
2021-12-23 13:36:09 +02:00
* if DSP is not ready and the dsp_oops_offset is not yet set , use the
* offset from the panic message .
2019-04-12 11:05:13 -05:00
*/
if ( ! sdev - > dsp_oops_offset )
sdev - > dsp_oops_offset = offset ;
2021-12-23 13:36:09 +02:00
/*
* Print warning if the offset from the panic message differs from
* dsp_oops_offset
*/
if ( sdev - > dsp_oops_offset ! = offset )
dev_warn ( sdev - > dev ,
" %s: dsp_oops_offset %zu differs from panic offset %u \n " ,
__func__ , sdev - > dsp_oops_offset , offset ) ;
2021-12-23 13:36:13 +02:00
/*
2021-12-23 13:36:23 +02:00
* Set the fw_state to crashed only in case of non recoverable DSP panic
* event .
* Use different message within the snd_sof_dsp_dbg_dump ( ) depending on
* the non_recoverable flag .
2021-12-23 13:36:13 +02:00
*/
2021-12-23 13:36:23 +02:00
sdev - > dbg_dump_printed = false ;
if ( non_recoverable ) {
2021-12-23 13:36:14 +02:00
snd_sof_dsp_dbg_dump ( sdev , " DSP panic! " ,
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX ) ;
2021-12-23 13:36:23 +02:00
sof_set_fw_state ( sdev , SOF_FW_CRASHED ) ;
2022-05-16 13:47:07 +03:00
sof_fw_trace_fw_crashed ( sdev ) ;
2021-12-23 13:36:23 +02:00
} else {
snd_sof_dsp_dbg_dump ( sdev ,
" DSP panic (recovery will be attempted) " ,
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX ) ;
2021-12-23 13:36:13 +02:00
}
2019-04-12 11:05:13 -05:00
}
EXPORT_SYMBOL ( snd_sof_dsp_panic ) ;