2007-05-08 18:00:38 -07:00
/*
* Copyright ( c ) 2007 Cisco Systems , Inc . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
2007-07-12 17:50:45 +03:00
# include <linux/workqueue.h>
2007-05-08 18:00:38 -07:00
# include "mlx4.h"
2007-07-12 17:50:45 +03:00
enum {
MLX4_CATAS_POLL_INTERVAL = 5 * HZ ,
} ;
static DEFINE_SPINLOCK ( catas_lock ) ;
static LIST_HEAD ( catas_list ) ;
static struct workqueue_struct * catas_wq ;
static struct work_struct catas_work ;
static int internal_err_reset = 1 ;
module_param ( internal_err_reset , int , 0644 ) ;
MODULE_PARM_DESC ( internal_err_reset ,
" Reset device on internal errors if non-zero (default 1) " ) ;
static void dump_err_buf ( struct mlx4_dev * dev )
2007-05-08 18:00:38 -07:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
int i ;
2007-07-12 17:50:45 +03:00
mlx4_err ( dev , " Internal error detected: \n " ) ;
2007-05-08 18:00:38 -07:00
for ( i = 0 ; i < priv - > fw . catas_size ; + + i )
mlx4_err ( dev , " buf[%02x]: %08x \n " ,
i , swab32 ( readl ( priv - > catas_err . map + i ) ) ) ;
2007-07-12 17:50:45 +03:00
}
2007-05-08 18:00:38 -07:00
2007-07-12 17:50:45 +03:00
static void poll_catas ( unsigned long dev_ptr )
{
struct mlx4_dev * dev = ( struct mlx4_dev * ) dev_ptr ;
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
if ( readl ( priv - > catas_err . map ) ) {
dump_err_buf ( dev ) ;
mlx4_dispatch_event ( dev , MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR , 0 , 0 ) ;
if ( internal_err_reset ) {
spin_lock ( & catas_lock ) ;
list_add ( & priv - > catas_err . list , & catas_list ) ;
spin_unlock ( & catas_lock ) ;
queue_work ( catas_wq , & catas_work ) ;
}
} else
mod_timer ( & priv - > catas_err . timer ,
round_jiffies ( jiffies + MLX4_CATAS_POLL_INTERVAL ) ) ;
2007-05-08 18:00:38 -07:00
}
2007-07-12 17:50:45 +03:00
static void catas_reset ( struct work_struct * work )
{
struct mlx4_priv * priv , * tmppriv ;
struct mlx4_dev * dev ;
LIST_HEAD ( tlist ) ;
int ret ;
spin_lock_irq ( & catas_lock ) ;
list_splice_init ( & catas_list , & tlist ) ;
spin_unlock_irq ( & catas_lock ) ;
list_for_each_entry_safe ( priv , tmppriv , & tlist , catas_err . list ) {
ret = mlx4_restart_one ( priv - > dev . pdev ) ;
dev = & priv - > dev ;
if ( ret )
mlx4_err ( dev , " Reset failed (%d) \n " , ret ) ;
else
mlx4_dbg ( dev , " Reset succeeded \n " ) ;
}
}
void mlx4_start_catas_poll ( struct mlx4_dev * dev )
2007-05-08 18:00:38 -07:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
unsigned long addr ;
2007-07-12 17:50:45 +03:00
INIT_LIST_HEAD ( & priv - > catas_err . list ) ;
init_timer ( & priv - > catas_err . timer ) ;
priv - > catas_err . map = NULL ;
2007-05-08 18:00:38 -07:00
addr = pci_resource_start ( dev - > pdev , priv - > fw . catas_bar ) +
priv - > fw . catas_offset ;
priv - > catas_err . map = ioremap ( addr , priv - > fw . catas_size * 4 ) ;
2007-07-12 17:50:45 +03:00
if ( ! priv - > catas_err . map ) {
mlx4_warn ( dev , " Failed to map internal error buffer at 0x%lx \n " ,
2007-05-08 18:00:38 -07:00
addr ) ;
2007-07-12 17:50:45 +03:00
return ;
}
2007-05-08 18:00:38 -07:00
2007-07-12 17:50:45 +03:00
priv - > catas_err . timer . data = ( unsigned long ) dev ;
priv - > catas_err . timer . function = poll_catas ;
priv - > catas_err . timer . expires =
round_jiffies ( jiffies + MLX4_CATAS_POLL_INTERVAL ) ;
add_timer ( & priv - > catas_err . timer ) ;
2007-05-08 18:00:38 -07:00
}
2007-07-12 17:50:45 +03:00
void mlx4_stop_catas_poll ( struct mlx4_dev * dev )
2007-05-08 18:00:38 -07:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
2007-07-12 17:50:45 +03:00
del_timer_sync ( & priv - > catas_err . timer ) ;
2007-05-08 18:00:38 -07:00
if ( priv - > catas_err . map )
iounmap ( priv - > catas_err . map ) ;
2007-07-12 17:50:45 +03:00
spin_lock_irq ( & catas_lock ) ;
list_del ( & priv - > catas_err . list ) ;
spin_unlock_irq ( & catas_lock ) ;
}
int __init mlx4_catas_init ( void )
{
INIT_WORK ( & catas_work , catas_reset ) ;
catas_wq = create_singlethread_workqueue ( " mlx4_err " ) ;
if ( ! catas_wq )
return - ENOMEM ;
return 0 ;
}
void mlx4_catas_cleanup ( void )
{
destroy_workqueue ( catas_wq ) ;
2007-05-08 18:00:38 -07:00
}