* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ka_pci_pub.h"
#include "ka_kernel_def_pub.h"
#include "res_drv.h"
#include "res_drv_mini_v2.h"
#include "res_drv_cloud_v1.h"
#include "res_drv_cloud_v2.h"
#include "res_drv_mini_v3.h"
#include "res_drv_cloud_v4.h"
#include "comm_kernel_interface.h"
#include "devdrv_util.h"
#include "devdrv_pci.h"
#include "devdrv_adapt.h"
const ka_pci_device_id_t g_devdrv_tbl[] = {
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V1_DEVICE), HISI_CLOUD_V1 },
{ KA_PCI_VDEVICE(HUAWEI, MINI_V2_DEVICE), HISI_MINI_V2 },
{ KA_PCI_VDEVICE(HUAWEI, MINI_V2_2P_DEVICE), HISI_MINI_V2 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V2_DEVICE), HISI_CLOUD_V2 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V2_2P_DEVICE), HISI_CLOUD_V2 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V2_HCCS_IEP_DEVICE), HISI_CLOUD_V2 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V2_VF_DEVICE), HISI_CLOUD_V2 },
{ DEVDRV_DIVERSITY_PCIE_VENDOR_ID, MINI_V2_DEVICE, KA_PCI_ANY_ID,
KA_PCI_ANY_ID, 0, 0, HISI_MINI_V2 },
{ KA_PCI_VDEVICE(HUAWEI, MINI_V3_DEVICE), HISI_MINI_V3 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V4_DEVICE), HISI_CLOUD_V4 },
{ KA_PCI_VDEVICE(HUAWEI, CLOUD_V5_DEVICE), HISI_CLOUD_V5 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_HK, MINI_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_MINI_V2 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_KL, MINI_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_MINI_V2 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_HK, CLOUD_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_CLOUD_V2 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_KL, CLOUD_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_CLOUD_V2 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_CJ, CLOUD_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_CLOUD_V2 },
{ DEVDRV_PCI_SUBSYS_PRIVATE_VENDOR_CJ, MINI_V2_DEVICE, KA_PCI_ANY_ID, KA_PCI_ANY_ID, 0, 0, HISI_MINI_V2 },
{}};
KA_MODULE_DEVICE_TABLE(pci, g_devdrv_tbl);
int devdrv_get_device_id_tbl_num(void)
{
return (int)(sizeof(g_devdrv_tbl) / sizeof(ka_pci_device_id_t));
}
int (*devdrv_res_init_func[HISI_CHIP_NUM])(struct devdrv_pci_ctrl *pci_ctrl) = {
[HISI_CLOUD_V1] = devdrv_cloud_v1_res_init,
[HISI_MINI_V2] = devdrv_mini_v2_res_init,
[HISI_CLOUD_V2] = devdrv_cloud_v2_res_init,
[HISI_MINI_V3] = devdrv_mini_v3_res_init,
[HISI_CLOUD_V4] = devdrv_cloud_v4_res_init,
[HISI_CLOUD_V5] = devdrv_cloud_v4_res_init,
};
void devdrv_peer_ctrl_init(void)
{
return;
}
int devdrv_get_product(void)
{
return HOST_PRODUCT_DC;
}
void devdrv_shutdown(ka_pci_dev_t *pdev)
{
if (devdrv_get_host_type() == HOST_TYPE_NORMAL) {
devdrv_info("Shutdown, pci remove driver.\n");
drv_pcie_remove(pdev);
}
return;
}
static u64 g_aer_critical_cnt = 0;
static u64 g_aer_noncritical_cnt = 0;
STATIC ka_pci_ers_result_t devdrv_error_detected(ka_pci_dev_t *pdev, ka_pci_channel_state_t state)
{
struct devdrv_pci_ctrl *pci_ctrl = devdrv_get_pdev_main_davinci_dev(pdev);
ka_pci_ers_result_t ret = KA_PCI_ERS_RESULT_NEED_RESET;
if (pci_ctrl == NULL) {
devdrv_err("pci_ctrl is invalid.\n");
return KA_PCI_ERS_RESULT_NEED_RESET;
}
devdrv_warn("Error detected. (dev_id=%u; state=%d)\n", pci_ctrl->dev_id, (int)state);
devdrv_notify_blackbox_err(pci_ctrl->dev_id, DEVDRV_PCIE_AER_ERROR);
switch (state) {
case ka_pci_channel_io_normal:
g_aer_noncritical_cnt++;
devdrv_err("Channel is in normal state. (dev_id=%d; aer_noncritical_cnt=%llu)\n",
pci_ctrl->dev_id, g_aer_noncritical_cnt);
ret = KA_PCI_ERS_RESULT_CAN_RECOVER;
break;
case ka_pci_channel_io_frozen:
g_aer_critical_cnt++;
devdrv_err("Channel is blocked. (dev_id=%u; aer_critical_cnt=%llu)\n",
pci_ctrl->dev_id, g_aer_critical_cnt);
if (ka_pci_is_enabled(pdev) != 0) {
ka_pci_disable_pcie_error_reporting(pdev);
ka_pci_clear_master(pdev);
ka_pci_release_regions(pdev);
ka_pci_disable_device(pdev);
}
ret = KA_PCI_ERS_RESULT_NEED_RESET;
break;
case ka_pci_channel_io_perm_failure:
ret = KA_PCI_ERS_RESULT_DISCONNECT;
break;
default:
ret = KA_PCI_ERS_RESULT_NEED_RESET;
break;
}
return ret;
}
STATIC ka_pci_ers_result_t devdrv_slot_reset(ka_pci_dev_t *pdev)
{
u8 byte = 0;
int ret;
devdrv_info("Enter slot reset.\n");
if (ka_pci_enable_device(pdev) != 0) {
devdrv_err("Call ka_pci_enable_device failed.\n");
return KA_PCI_ERS_RESULT_DISCONNECT;
}
ka_pci_read_config_byte(pdev, 0x8, &byte);
if (byte == 0xff) {
devdrv_err("Slot_reset failed. got another pci error.\n");
return KA_PCI_ERS_RESULT_DISCONNECT;
}
if (ka_pci_request_regions(pdev, "devdrv") != 0) {
devdrv_err("Call ka_pci_request_regions failed.\n");
return KA_PCI_ERS_RESULT_DISCONNECT;
}
if (ka_mm_dma_set_mask_and_coherent(ka_pci_get_dev(pdev), KA_DMA_BIT_MASK(DEVDRV_DMA_BIT_MASK_64)) != 0) {
devdrv_err("dma_set_mask 64 bit failed.\n");
ret = ka_mm_dma_set_mask_and_coherent(ka_pci_get_dev(pdev), KA_DMA_BIT_MASK(DEVDRV_DMA_BIT_MASK_32));
if (ret != 0) {
devdrv_err("dma_set_mask failed. (ret=%d)\n", ret);
return KA_PCI_ERS_RESULT_DISCONNECT;
}
}
ka_pci_set_master(pdev);
devdrv_err("The resume of top business(vnic/hdc/devmm) still need to do.\n");
return KA_PCI_ERS_RESULT_RECOVERED;
}
STATIC void devdrv_error_resume(ka_pci_dev_t *pdev)
{
devdrv_info("Enter pcie reporting resume.\n");
ka_pci_aer_clear_status(pdev);
ka_pci_enable_pcie_error_reporting(pdev);
}
const ka_pci_error_handlers_t g_devdrv_err_handler = {
ka_pci_error_detected(devdrv_error_detected)
ka_pci_slot_reset(devdrv_slot_reset)
ka_pci_resume(devdrv_error_resume)
};
void devdrv_traffic_and_manage_dma_chan_config(struct devdrv_dma_dev *dma_dev)
{
dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_start_id =
dma_dev->data_chan[DEVDRV_DMA_DATA_PCIE_MSG].chan_start_id +
dma_dev->data_chan[DEVDRV_DMA_DATA_PCIE_MSG].chan_num;
if (dma_dev->remote_chan_num <= dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_start_id) {
dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_start_id = 0;
}
dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_num =
dma_dev->remote_chan_num - dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_start_id;
dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].last_use_chan =
dma_dev->data_chan[DEVDRV_DMA_DATA_TRAFFIC].chan_start_id;
}
#ifndef CFG_FEATURE_PCIE_SENTRY
bool devdrv_is_sentry_work_mode(void)
{
return false;
}
#endif
void devdrv_load_half_resume(struct devdrv_pci_ctrl *pci_ctrl)
{
return;
}
__attribute__((unused)) int drv_pcie_suspend(ka_device_t *dev)
{
return 0;
}
__attribute__((unused)) int drv_pcie_resume_notify(ka_device_t *dev)
{
return 0;
}