mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-02-02 06:29:47 +00:00
212 lines
12 KiB
C
212 lines
12 KiB
C
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2018-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef _INTR_NVSWITCH_H_
|
|
#define _INTR_NVSWITCH_H_
|
|
|
|
#include "error_nvswitch.h"
|
|
|
|
//
|
|
// Wrapper to track interrupt servicing
|
|
//
|
|
#define NVSWITCH_UNHANDLED_INIT(val) (unhandled = (val))
|
|
#define NVSWITCH_HANDLED(mask) (unhandled &= ~(mask))
|
|
|
|
#define NVSWITCH_UNHANDLED_CHECK(_device, _unhandled) \
|
|
do \
|
|
{ \
|
|
if (_unhandled) \
|
|
{ \
|
|
NVSWITCH_PRINT(_device, ERROR, \
|
|
"%s:%d unhandled interrupt! %x\n", \
|
|
__FUNCTION__, __LINE__, _unhandled); \
|
|
NVSWITCH_PRINT_SXID(_device, \
|
|
NVSWITCH_ERR_HW_HOST_UNHANDLED_INTERRUPT, \
|
|
"Fatal, unhandled interrupt\n"); \
|
|
NVSWITCH_LOG_FATAL_DATA(_device, _HW, \
|
|
_HW_HOST_UNHANDLED_INTERRUPT, 0, 0, NV_FALSE, &_unhandled);\
|
|
} \
|
|
} while(0)
|
|
|
|
//
|
|
// Wrappers for basic leaf interrupt handling
|
|
//
|
|
#define NVSWITCH_PENDING(_bit) ((bit = (_bit)) && (pending & (_bit)))
|
|
#define NVSWITCH_FIRST() (bit & report.raw_first) ? " (First)" : ""
|
|
|
|
//
|
|
// Report/log error interrupt helper.
|
|
//
|
|
|
|
//
|
|
// Print an intermediate point (non-leaf) in the interrupt tree.
|
|
//
|
|
#define NVSWITCH_REPORT_TREE(_logenum) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "Intermediate, Link %02d \n", link); \
|
|
} while(0)
|
|
|
|
// Log correctable errors
|
|
#define NVSWITCH_REPORT_CORRECTABLE(_logenum, _str) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR ## _logenum, \
|
|
"Correctable, Link %02d %s%s\n", link, _str, NVSWITCH_FIRST()); \
|
|
NVSWITCH_LOG_NONFATAL_DATA(device, _HW, _logenum, \
|
|
link, 0, NV_TRUE, &report); \
|
|
if (nvswitch_lib_notify_client_events(device, \
|
|
NVSWITCH_DEVICE_EVENT_NONFATAL) != NVL_SUCCESS) \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n", \
|
|
__FUNCTION__); \
|
|
} \
|
|
} while(0)
|
|
|
|
// Log uncorrectable error that is not fatal to the fabric
|
|
#define NVSWITCH_REPORT_NONFATAL(_logenum, _str) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR ## _logenum, \
|
|
"Non-fatal, Link %02d %s%s\n", link, _str, NVSWITCH_FIRST()); \
|
|
NVSWITCH_LOG_NONFATAL_DATA(device, _HW, _logenum, \
|
|
link, 0, NV_FALSE, &report, _str); \
|
|
if (nvswitch_lib_notify_client_events(device, \
|
|
NVSWITCH_DEVICE_EVENT_NONFATAL) != NVL_SUCCESS) \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n", \
|
|
__FUNCTION__); \
|
|
} \
|
|
} while(0)
|
|
|
|
// Log uncorrectable error that is fatal to the fabric
|
|
#define NVSWITCH_REPORT_FATAL(_logenum, _str, device_fatal) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR ## _logenum, \
|
|
"Fatal, Link %02d %s%s\n", link, _str, NVSWITCH_FIRST()); \
|
|
NVSWITCH_LOG_FATAL_DATA(device, _HW, _logenum, \
|
|
link, 0, NV_FALSE, &report, _str); \
|
|
nvswitch_set_fatal_error(device, device_fatal, link); \
|
|
if (nvswitch_lib_notify_client_events(device, \
|
|
NVSWITCH_DEVICE_EVENT_FATAL) != NVL_SUCCESS) \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n",\
|
|
__FUNCTION__); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define NVSWITCH_REPORT_PRI_ERROR_NONFATAL(_logenum, _str, instance, chiplet, err_data) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR ## _logenum, \
|
|
"Non-fatal, %s, instance=%d, chiplet=%d\n", _str, instance, chiplet); \
|
|
NVSWITCH_LOG_NONFATAL_DATA(device, _HW, _logenum, \
|
|
instance, chiplet, NV_FALSE, &err_data, _str); \
|
|
if (nvswitch_lib_notify_client_events(device, \
|
|
NVSWITCH_DEVICE_EVENT_NONFATAL) != NVL_SUCCESS) \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n", \
|
|
__FUNCTION__); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define NVSWITCH_REPORT_PRI_ERROR_FATAL(_logenum, _str, device_fatal, instance, chiplet, err_data) \
|
|
do \
|
|
{ \
|
|
NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR ## _logenum, \
|
|
"Fatal, %s, instance=%d, chiplet=%d\n", _str, instance, chiplet); \
|
|
NVSWITCH_LOG_FATAL_DATA(device, _HW, _logenum, \
|
|
instance, chiplet, NV_FALSE, &err_data, _str); \
|
|
nvswitch_set_fatal_error(device, device_fatal, 0); \
|
|
if (nvswitch_lib_notify_client_events(device, \
|
|
NVSWITCH_DEVICE_EVENT_FATAL) != NVL_SUCCESS) \
|
|
{ \
|
|
NVSWITCH_PRINT(device, ERROR, "%s: Failed to notify event\n", \
|
|
__FUNCTION__); \
|
|
} \
|
|
} while(0)
|
|
|
|
/*
|
|
* Automatically determine if error is fatal to the fabric based on
|
|
* if it is contained and will lock the port.
|
|
*/
|
|
#define NVSWITCH_REPORT_CONTAIN(_logenum, _str, device_fatal) \
|
|
do \
|
|
{ \
|
|
if (bit & contain) \
|
|
{ \
|
|
NVSWITCH_REPORT_FATAL(_logenum, _str, device_fatal); \
|
|
} \
|
|
else \
|
|
{ \
|
|
NVSWITCH_REPORT_NONFATAL(_logenum, _str); \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* REPORT_*_DATA macros - optionally log data record for additional HW state. This
|
|
* is typically a captured packet, but there are a few other cases.
|
|
*
|
|
* Most interrupt controllers only latch additional data for errors tagged as first.
|
|
* For those cases use _FIRST to only log the data record when it is accurate. If
|
|
* two errors are detected in the same cycle, they will both be set in first.
|
|
*/
|
|
#define NVSWITCH_REPORT_DATA(_logenum, _data) \
|
|
NVSWITCH_LOG_NONFATAL_DATA(device, _HW, _logenum, link, 0, NV_TRUE, &_data)
|
|
|
|
#define NVSWITCH_REPORT_DATA_FIRST(_logenum, _data) \
|
|
do \
|
|
{ \
|
|
if (report.raw_first & bit) \
|
|
{ \
|
|
NVSWITCH_REPORT_DATA(_logenum, _data); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define NVSWITCH_REPORT_CONTAIN_DATA(_logenum, _data) \
|
|
do \
|
|
{ \
|
|
if (bit & contain) \
|
|
{ \
|
|
NVSWITCH_LOG_FATAL_DATA(device, _HW, _logenum, link, \
|
|
0, NV_FALSE, &_data); \
|
|
} \
|
|
else \
|
|
{ \
|
|
NVSWITCH_LOG_NONFATAL_DATA(device, _HW, _logenum, link, \
|
|
0, NV_FALSE, &data); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define NVSWITCH_REPORT_CONTAIN_DATA_FIRST(_logenum, _data) \
|
|
do \
|
|
{ \
|
|
if (bit & report.raw_first) \
|
|
{ \
|
|
NVSWITCH_REPORT_CONTAIN_DATA(_logenum, _data); \
|
|
} \
|
|
} while(0)
|
|
|
|
#endif //_INTR_NVSWITCH_H_
|