hifc/hifc/hifc_lld.c

897 lines
22 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Huawei Hifc PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": [COMM]" fmt
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/io-mapping.h>
#include <linux/interrupt.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/rtc.h>
#include <linux/aer.h>
#include <linux/debugfs.h>
#include "hifc_knl_adp.h"
#include "hifc_hw.h"
#include "hifc_hwif.h"
#include "hifc_api_cmd.h"
#include "hifc_mgmt.h"
#include "hifc_lld.h"
#include "hifc_dbgtool_knl.h"
#include "hifc_tool.h"
#define HIFC_PCI_CFG_REG_BAR 0
#define HIFC_PCI_INTR_REG_BAR 2
#define HIFC_PCI_DB_BAR 4
#define HIFC_SECOND_BASE 1000
#define HIFC_SYNC_YEAR_OFFSET 1900
#define HIFC_SYNC_MONTH_OFFSET 1
#define HIFC_DRV_DESC "Huawei(R) Intelligent Network Interface Card Driver"
#define HIFCVF_DRV_DESC "Huawei(R) Intelligent Virtual Function Network Driver"
MODULE_AUTHOR("Huawei Technologies CO., Ltd");
MODULE_DESCRIPTION(HIFC_DRV_DESC);
MODULE_VERSION(HIFC_DRV_VERSION);
MODULE_LICENSE("GPL");
#define HIFC_EVENT_PROCESS_TIMEOUT 10000
#define FIND_BIT(num, n) (((num) & (1UL << (n))) ? 1 : 0)
#define SET_BIT(num, n) ((num) | (1UL << (n)))
#define CLEAR_BIT(num, n) ((num) & (~(1UL << (n))))
#define MAX_CARD_ID 64
static u64 card_bit_map;
LIST_HEAD(g_hifc_chip_list);
enum hifc_lld_status {
HIFC_NODE_CHANGE = BIT(0),
};
struct hifc_lld_lock {
/* lock for chip list */
struct mutex lld_mutex;
unsigned long status;
atomic_t dev_ref_cnt;
};
static struct hifc_lld_lock g_lld_lock;
#define WAIT_LLD_DEV_HOLD_TIMEOUT (10 * 60 * 1000) /* 10minutes */
#define WAIT_LLD_DEV_NODE_CHANGED (10 * 60 * 1000) /* 10minutes */
#define WAIT_LLD_DEV_REF_CNT_EMPTY (2 * 60 * 1000) /* 2minutes */
void hifc_event_process(void *adapter, struct hifc_event_info *event);
void *hifc_get_ppf_hwdev_by_pdev(struct pci_dev *pdev);
/* node in chip_node will changed, tools or driver can't get node
* during this situation
*/
static void lld_lock_chip_node(void)
{
u32 loop_cnt;
mutex_lock(&g_lld_lock.lld_mutex);
loop_cnt = 0;
while (loop_cnt < WAIT_LLD_DEV_NODE_CHANGED) {
if (!test_and_set_bit(HIFC_NODE_CHANGE, &g_lld_lock.status))
break;
loop_cnt++;
if (loop_cnt % 10000 == 0)
pr_warn("Wait for lld node change complete for %us\n",
loop_cnt / 1000);
usleep_range(900, 1000);
}
if (loop_cnt == WAIT_LLD_DEV_NODE_CHANGED)
pr_warn("Wait for lld node change complete timeout when try to get lld lock\n");
loop_cnt = 0;
while (loop_cnt < WAIT_LLD_DEV_REF_CNT_EMPTY) {
if (!atomic_read(&g_lld_lock.dev_ref_cnt))
break;
loop_cnt++;
if (loop_cnt % 10000 == 0)
pr_warn("Wait for lld dev unused for %us, reference count: %d\n",
loop_cnt / 1000,
atomic_read(&g_lld_lock.dev_ref_cnt));
usleep_range(900, 1000);
}
if (loop_cnt == WAIT_LLD_DEV_REF_CNT_EMPTY)
pr_warn("Wait for lld dev unused timeout\n");
mutex_unlock(&g_lld_lock.lld_mutex);
}
static void lld_unlock_chip_node(void)
{
clear_bit(HIFC_NODE_CHANGE, &g_lld_lock.status);
}
/* When tools or other drivers want to get node of chip_node, use this function
* to prevent node be freed
*/
void lld_dev_hold(void)
{
u32 loop_cnt = 0;
/* ensure there have not any chip node in changing */
mutex_lock(&g_lld_lock.lld_mutex);
while (loop_cnt < WAIT_LLD_DEV_HOLD_TIMEOUT) {
if (!test_bit(HIFC_NODE_CHANGE, &g_lld_lock.status))
break;
loop_cnt++;
if (loop_cnt % 10000 == 0)
pr_warn("Wait lld node change complete for %us\n",
loop_cnt / 1000);
usleep_range(900, 1000);
}
if (loop_cnt == WAIT_LLD_DEV_HOLD_TIMEOUT)
pr_warn("Wait lld node change complete timeout when try to hode lld dev\n");
atomic_inc(&g_lld_lock.dev_ref_cnt);
mutex_unlock(&g_lld_lock.lld_mutex);
}
void lld_dev_put(void)
{
atomic_dec(&g_lld_lock.dev_ref_cnt);
}
static void hifc_lld_lock_init(void)
{
mutex_init(&g_lld_lock.lld_mutex);
atomic_set(&g_lld_lock.dev_ref_cnt, 0);
}
extern int hifc_probe(struct hifc_lld_dev *lld_dev,
void **uld_dev, char *uld_dev_name);
static int attach_uld(struct hifc_pcidev *dev)
{
void *uld_dev = NULL;
int err;
mutex_lock(&dev->pdev_mutex);
if (dev->init_state < HIFC_INIT_STATE_HWDEV_INITED) {
sdk_err(&dev->pcidev->dev, "SDK init failed, can not attach uld\n");
err = -EFAULT;
goto out_unlock;
}
err = hifc_stateful_init(dev->hwdev);
if (err)
goto out_unlock;
err = hifc_probe(&dev->lld_dev, &uld_dev, dev->uld_dev_name);
if (err || !uld_dev) {
sdk_err(&dev->pcidev->dev,
"Failed to add object for driver to pcie device\n");
goto probe_failed;
}
dev->uld_dev = uld_dev;
mutex_unlock(&dev->pdev_mutex);
sdk_info(&dev->pcidev->dev,
"Attach driver to pcie device succeed\n");
return 0;
probe_failed:
hifc_stateful_deinit(dev->hwdev);
out_unlock:
mutex_unlock(&dev->pdev_mutex);
return err;
}
extern void hifc_remove(struct hifc_lld_dev *lld_dev, void *uld_dev);
static void detach_uld(struct hifc_pcidev *dev)
{
u32 cnt = 0;
mutex_lock(&dev->pdev_mutex);
while (cnt < HIFC_EVENT_PROCESS_TIMEOUT) {
if (!test_and_set_bit(SERVICE_T_FC, &dev->state))
break;
usleep_range(900, 1000);
cnt++;
}
hifc_remove(&dev->lld_dev, dev->uld_dev);
dev->uld_dev = NULL;
hifc_stateful_deinit(dev->hwdev);
if (cnt < HIFC_EVENT_PROCESS_TIMEOUT)
clear_bit(SERVICE_T_FC, &dev->state);
sdk_info(&dev->pcidev->dev,
"Detach driver from pcie device succeed\n");
mutex_unlock(&dev->pdev_mutex);
}
static void hifc_sync_time_to_fmw(struct hifc_pcidev *pdev_pri)
{
struct tm tm = {0};
u64 tv_msec;
int err;
tv_msec = ktime_to_ms(ktime_get_real());
err = hifc_sync_time(pdev_pri->hwdev, tv_msec);
if (err) {
sdk_err(&pdev_pri->pcidev->dev, "Synchronize UTC time to firmware failed, errno:%d.\n",
err);
} else {
time64_to_tm(tv_msec / MSEC_PER_SEC, 0, &tm);
sdk_info(&pdev_pri->pcidev->dev, "Synchronize UTC time to firmware succeed. UTC time %ld-%02d-%02d %02d:%02d:%02d.\n",
tm.tm_year + HIFC_SYNC_YEAR_OFFSET,
tm.tm_mon + HIFC_SYNC_MONTH_OFFSET,
tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
}
}
#define MAX_VER_FIELD_LEN 4
#define MAX_VER_SPLIT_NUM 4
struct mctp_hdr {
u16 resp_code;
u16 reason_code;
u32 manufacture_id;
u8 cmd_rsvd;
u8 major_cmd;
u8 sub_cmd;
u8 spc_field;
};
struct mctp_bdf_info {
struct mctp_hdr hdr; /* spc_field: pf index */
u8 rsvd;
u8 bus;
u8 device;
u8 function;
};
static void __mctp_set_hdr(struct mctp_hdr *hdr,
struct hifc_mctp_host_info *mctp_info)
{
u32 manufacture_id = 0x07DB;
hdr->cmd_rsvd = 0;
hdr->major_cmd = mctp_info->major_cmd;
hdr->sub_cmd = mctp_info->sub_cmd;
hdr->manufacture_id = cpu_to_be32(manufacture_id);
hdr->resp_code = cpu_to_be16(hdr->resp_code);
hdr->reason_code = cpu_to_be16(hdr->reason_code);
}
static void __mctp_get_bdf(struct hifc_pcidev *pci_adapter,
struct hifc_mctp_host_info *mctp_info)
{
struct pci_dev *pdev = pci_adapter->pcidev;
struct mctp_bdf_info *bdf_info = mctp_info->data;
bdf_info->bus = pdev->bus->number;
bdf_info->device = (u8)(pdev->devfn >> 3); /* 5bits in devfn */
bdf_info->function = (u8)(pdev->devfn & 0x7); /* 3bits in devfn */
memset(&bdf_info->hdr, 0, sizeof(bdf_info->hdr));
__mctp_set_hdr(&bdf_info->hdr, mctp_info);
bdf_info->hdr.spc_field =
(u8)hifc_global_func_id_hw(pci_adapter->hwdev);
mctp_info->data_len = sizeof(*bdf_info);
}
#define MCTP_PUBLIC_SUB_CMD_BDF 0x1
static void __mctp_get_host_info(struct hifc_pcidev *dev,
struct hifc_mctp_host_info *mctp_info)
{
#define COMMAND_UNSUPPORTED 3
struct mctp_hdr *hdr;
if (((((u16)mctp_info->major_cmd) << 8) | mctp_info->sub_cmd) ==
MCTP_PUBLIC_SUB_CMD_BDF) {
__mctp_get_bdf(dev, mctp_info);
} else {
hdr = mctp_info->data;
hdr->reason_code = COMMAND_UNSUPPORTED;
__mctp_set_hdr(hdr, mctp_info);
mctp_info->data_len = sizeof(*hdr);
}
}
void *hifc_get_ppf_hwdev_by_pdev(struct pci_dev *pdev)
{
struct hifc_pcidev *pci_adapter;
struct card_node *chip_node;
struct hifc_pcidev *dev;
if (!pdev)
return NULL;
pci_adapter = pci_get_drvdata(pdev);
if (!pci_adapter)
return NULL;
chip_node = pci_adapter->chip_node;
lld_dev_hold();
list_for_each_entry(dev, &chip_node->func_list, node) {
if (dev->hwdev && hifc_func_type(dev->hwdev) == TYPE_PPF) {
lld_dev_put();
return dev->hwdev;
}
}
lld_dev_put();
return NULL;
}
void hifc_event(struct hifc_lld_dev *lld_dev, void *uld_dev,
struct hifc_event_info *event);
void hifc_event_process(void *adapter, struct hifc_event_info *event)
{
struct hifc_pcidev *dev = adapter;
if (event->type == HIFC_EVENT_FMW_ACT_NTC)
return hifc_sync_time_to_fmw(dev);
else if (event->type == HIFC_EVENT_MCTP_GET_HOST_INFO)
return __mctp_get_host_info(dev, &event->mctp_info);
if (test_and_set_bit(SERVICE_T_FC, &dev->state)) {
sdk_warn(&dev->pcidev->dev, "Event: 0x%x can't handler is in detach\n",
event->type);
return;
}
hifc_event(&dev->lld_dev, dev->uld_dev, event);
clear_bit(SERVICE_T_FC, &dev->state);
}
static int mapping_bar(struct pci_dev *pdev, struct hifc_pcidev *pci_adapter)
{
u64 dwqe_addr;
pci_adapter->cfg_reg_base = pci_ioremap_bar(pdev, HIFC_PCI_CFG_REG_BAR);
if (!pci_adapter->cfg_reg_base) {
sdk_err(&pci_adapter->pcidev->dev,
"Failed to map configuration regs\n");
return -ENOMEM;
}
pci_adapter->intr_reg_base = pci_ioremap_bar(pdev,
HIFC_PCI_INTR_REG_BAR);
if (!pci_adapter->intr_reg_base) {
sdk_err(&pci_adapter->pcidev->dev,
"Failed to map interrupt regs\n");
goto map_intr_bar_err;
}
pci_adapter->db_base_phy = pci_resource_start(pdev, HIFC_PCI_DB_BAR);
pci_adapter->db_base = ioremap(pci_adapter->db_base_phy,
HIFC_DB_DWQE_SIZE);
if (!pci_adapter->db_base) {
sdk_err(&pci_adapter->pcidev->dev,
"Failed to map doorbell regs\n");
goto map_db_err;
}
dwqe_addr = pci_adapter->db_base_phy + HIFC_DB_DWQE_SIZE;
#if defined(__aarch64__)
/* arm do not support call ioremap_wc() */
pci_adapter->dwqe_mapping = __ioremap(dwqe_addr, HIFC_DB_DWQE_SIZE,
__pgprot(PROT_DEVICE_nGnRnE));
#else
pci_adapter->dwqe_mapping = io_mapping_create_wc(dwqe_addr,
HIFC_DB_DWQE_SIZE);
#endif /* end of "defined(__aarch64__)" */
if (!pci_adapter->dwqe_mapping) {
sdk_err(&pci_adapter->pcidev->dev, "Failed to io_mapping_create_wc\n");
goto mapping_dwqe_err;
}
return 0;
mapping_dwqe_err:
iounmap(pci_adapter->db_base);
map_db_err:
iounmap(pci_adapter->intr_reg_base);
map_intr_bar_err:
iounmap(pci_adapter->cfg_reg_base);
return -ENOMEM;
}
static void unmapping_bar(struct hifc_pcidev *pci_adapter)
{
#if defined(__aarch64__)
iounmap(pci_adapter->dwqe_mapping);
#else
io_mapping_free(pci_adapter->dwqe_mapping);
#endif /* end of "defined(__aarch64__)" */
iounmap(pci_adapter->db_base);
iounmap(pci_adapter->intr_reg_base);
iounmap(pci_adapter->cfg_reg_base);
}
static int alloc_chip_node(struct hifc_pcidev *pci_adapter)
{
struct card_node *chip_node;
unsigned char i;
unsigned char parent_bus_number = 0;
if (!pci_is_root_bus(pci_adapter->pcidev->bus))
parent_bus_number = pci_adapter->pcidev->bus->parent->number;
if (parent_bus_number != 0) {
list_for_each_entry(chip_node, &g_hifc_chip_list, node) {
if (chip_node->dp_bus_num == parent_bus_number) {
pci_adapter->chip_node = chip_node;
return 0;
}
}
}
for (i = 0; i < MAX_CARD_ID; i++) {
if (!FIND_BIT(card_bit_map, i)) {
card_bit_map = (u64)SET_BIT(card_bit_map, i);
break;
}
}
if (i == MAX_CARD_ID) {
sdk_err(&pci_adapter->pcidev->dev,
"Failed to alloc card id\n");
return -EFAULT;
}
chip_node = kzalloc(sizeof(*chip_node), GFP_KERNEL);
if (!chip_node) {
card_bit_map = CLEAR_BIT(card_bit_map, i);
sdk_err(&pci_adapter->pcidev->dev,
"Failed to alloc chip node\n");
return -ENOMEM;
}
chip_node->dbgtool_attr_file.name = kzalloc(IFNAMSIZ, GFP_KERNEL);
if (!(chip_node->dbgtool_attr_file.name)) {
kfree(chip_node);
card_bit_map = CLEAR_BIT(card_bit_map, i);
sdk_err(&pci_adapter->pcidev->dev,
"Failed to alloc dbgtool attr file name\n");
return -ENOMEM;
}
/* parent bus number */
chip_node->dp_bus_num = parent_bus_number;
snprintf(chip_node->chip_name, IFNAMSIZ, "%s%d", HIFC_CHIP_NAME, i);
snprintf((char *)chip_node->dbgtool_attr_file.name,
IFNAMSIZ, "%s%d", HIFC_CHIP_NAME, i);
sdk_info(&pci_adapter->pcidev->dev,
"Add new chip %s to global list succeed\n",
chip_node->chip_name);
list_add_tail(&chip_node->node, &g_hifc_chip_list);
INIT_LIST_HEAD(&chip_node->func_list);
pci_adapter->chip_node = chip_node;
mutex_init(&chip_node->sfp_mutex);
return 0;
}
static void free_chip_node(struct hifc_pcidev *pci_adapter)
{
struct card_node *chip_node = pci_adapter->chip_node;
u32 id;
int err;
if (list_empty(&chip_node->func_list)) {
list_del(&chip_node->node);
sdk_info(&pci_adapter->pcidev->dev,
"Delete chip %s from global list succeed\n",
chip_node->chip_name);
err = sscanf(chip_node->chip_name, HIFC_CHIP_NAME "%u", &id);
if (err < 0)
sdk_err(&pci_adapter->pcidev->dev, "Failed to get hifc id\n");
card_bit_map = CLEAR_BIT(card_bit_map, id);
kfree(chip_node->dbgtool_attr_file.name);
kfree(chip_node);
}
}
static int config_pci_dma_mask(struct pci_dev *pdev)
{
int err;
err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
sdk_warn(&pdev->dev, "Couldn't set 64-bit DMA mask\n");
err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
sdk_err(&pdev->dev, "Failed to set DMA mask\n");
return err;
}
}
err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
sdk_warn(&pdev->dev,
"Couldn't set 64-bit coherent DMA mask\n");
err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
sdk_err(&pdev->dev,
"Failed to set coherent DMA mask\n");
return err;
}
}
return 0;
}
static int hifc_pci_init(struct pci_dev *pdev)
{
struct hifc_pcidev *pci_adapter = NULL;
int err;
pci_adapter = kzalloc(sizeof(*pci_adapter), GFP_KERNEL);
if (!pci_adapter) {
sdk_err(&pdev->dev,
"Failed to alloc pci device adapter\n");
return -ENOMEM;
}
pci_adapter->pcidev = pdev;
mutex_init(&pci_adapter->pdev_mutex);
pci_set_drvdata(pdev, pci_adapter);
err = pci_enable_device(pdev);
if (err) {
sdk_err(&pdev->dev, "Failed to enable PCI device\n");
goto pci_enable_err;
}
err = pci_request_regions(pdev, HIFC_DRV_NAME);
if (err) {
sdk_err(&pdev->dev, "Failed to request regions\n");
goto pci_regions_err;
}
// pci_enable_pcie_error_reporting(pdev);
pci_set_master(pdev);
err = config_pci_dma_mask(pdev);
if (err)
goto dma_mask_err;
return 0;
dma_mask_err:
pci_clear_master(pdev);
pci_release_regions(pdev);
pci_regions_err:
pci_disable_device(pdev);
pci_enable_err:
pci_set_drvdata(pdev, NULL);
kfree(pci_adapter);
return err;
}
static void hifc_pci_deinit(struct pci_dev *pdev)
{
struct hifc_pcidev *pci_adapter = pci_get_drvdata(pdev);
pci_clear_master(pdev);
pci_release_regions(pdev);
// pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(pci_adapter);
}
static int hifc_func_init(struct pci_dev *pdev,
struct hifc_pcidev *pci_adapter)
{
struct hifc_init_para init_para;
int err;
init_para.adapter_hdl = pci_adapter;
init_para.pcidev_hdl = pdev;
init_para.dev_hdl = &pdev->dev;
init_para.cfg_reg_base = pci_adapter->cfg_reg_base;
init_para.intr_reg_base = pci_adapter->intr_reg_base;
init_para.db_base = pci_adapter->db_base;
init_para.db_base_phy = pci_adapter->db_base_phy;
init_para.dwqe_mapping = pci_adapter->dwqe_mapping;
init_para.hwdev = &pci_adapter->hwdev;
init_para.chip_node = pci_adapter->chip_node;
init_para.ppf_hwdev = hifc_get_ppf_hwdev_by_pdev(pdev);
err = hifc_init_hwdev(&init_para);
if (err) {
pci_adapter->hwdev = NULL;
sdk_err(&pdev->dev, "Failed to initialize hardware device\n");
return -EFAULT;
}
pci_adapter->init_state = HIFC_INIT_STATE_HWDEV_INITED;
pci_adapter->lld_dev.pdev = pdev;
pci_adapter->lld_dev.hwdev = pci_adapter->hwdev;
hifc_event_register(pci_adapter->hwdev, pci_adapter,
hifc_event_process);
hifc_sync_time_to_fmw(pci_adapter);
lld_lock_chip_node();
err = hifc_dbgtool_knl_init(pci_adapter->hwdev, pci_adapter->chip_node);
if (err) {
lld_unlock_chip_node();
sdk_err(&pdev->dev, "Failed to initialize dbgtool\n");
hifc_event_unregister(pci_adapter->hwdev);
return err;
}
lld_unlock_chip_node();
pci_adapter->init_state = HIFC_INIT_STATE_DBGTOOL_INITED;
attach_uld(pci_adapter);
sdk_info(&pdev->dev, "Pcie device probed\n");
pci_adapter->init_state = HIFC_INIT_STATE_ALL_INITED;
return 0;
}
static void hifc_func_deinit(struct pci_dev *pdev)
{
struct hifc_pcidev *pci_adapter = pci_get_drvdata(pdev);
/* When function deinit, disable mgmt initiative report events firstly,
* then flush mgmt work-queue.
*/
if (pci_adapter->init_state >= HIFC_INIT_STATE_ALL_INITED)
detach_uld(pci_adapter);
hifc_disable_mgmt_msg_report(pci_adapter->hwdev);
if (pci_adapter->init_state >= HIFC_INIT_STATE_HW_PART_INITED)
hifc_flush_mgmt_workq(pci_adapter->hwdev);
hifc_set_func_deinit_flag(pci_adapter->hwdev);
if (pci_adapter->init_state >= HIFC_INIT_STATE_DBGTOOL_INITED) {
lld_lock_chip_node();
hifc_dbgtool_knl_deinit(pci_adapter->hwdev, pci_adapter->chip_node);
lld_unlock_chip_node();
hifc_event_unregister(pci_adapter->hwdev);
}
if (pci_adapter->init_state >= HIFC_INIT_STATE_HW_IF_INITED) {
/*Remove the current node from node-list first,
* then it's safe to free hwdev
*/
lld_lock_chip_node();
list_del(&pci_adapter->node);
lld_unlock_chip_node();
hifc_free_hwdev(pci_adapter->hwdev);
}
}
static void remove_func(struct hifc_pcidev *pci_adapter)
{
struct pci_dev *pdev = pci_adapter->pcidev;
switch (pci_adapter->init_state) {
case HIFC_INIT_STATE_ALL_INITED:
/*lint -fallthrough*/
case HIFC_INIT_STATE_DBGTOOL_INITED:
case HIFC_INIT_STATE_HWDEV_INITED:
case HIFC_INIT_STATE_HW_PART_INITED:
case HIFC_INIT_STATE_HW_IF_INITED:
case HIFC_INIT_STATE_PCI_INITED:
set_bit(HIFC_FUNC_IN_REMOVE, &pci_adapter->flag);
if (pci_adapter->init_state >= HIFC_INIT_STATE_HW_IF_INITED)
hifc_func_deinit(pdev);
lld_lock_chip_node();
if (pci_adapter->init_state < HIFC_INIT_STATE_HW_IF_INITED)
list_del(&pci_adapter->node);
hifc_tool_k_uninit();
free_chip_node(pci_adapter);
lld_unlock_chip_node();
unmapping_bar(pci_adapter);
hifc_pci_deinit(pdev);
/*lint -fallthrough*/
break;
default:
break;
}
}
static void hifc_hwdev_remove(struct pci_dev *pdev)
{
struct hifc_pcidev *pci_adapter = pci_get_drvdata(pdev);
if (!pci_adapter)
return;
sdk_info(&pdev->dev, "Pcie device remove begin\n");
if (pci_adapter->init_state >= HIFC_INIT_STATE_HW_IF_INITED)
hifc_detect_hw_present(pci_adapter->hwdev);
remove_func(pci_adapter);
sdk_info(&pdev->dev, "Pcie device removed\n");
}
static int hifc_hwdev_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct hifc_pcidev *pci_adapter;
int err;
sdk_info(&pdev->dev, "Pcie device probe begin\n");
err = hifc_pci_init(pdev);
if (err)
return err;
pci_adapter = pci_get_drvdata(pdev);
clear_bit(HIFC_FUNC_PRB_ERR, &pci_adapter->flag);
clear_bit(HIFC_FUNC_PRB_DELAY, &pci_adapter->flag);
err = mapping_bar(pdev, pci_adapter);
if (err) {
sdk_err(&pdev->dev, "Failed to map bar\n");
goto map_bar_failed;
}
pci_adapter->id = *id;
/* if chip information of pcie function exist,
* add the function into chip
*/
lld_lock_chip_node();
err = alloc_chip_node(pci_adapter);
if (err) {
sdk_err(&pdev->dev,
"Failed to add new chip node to global list\n");
goto alloc_chip_node_fail;
}
err = hifc_tool_k_init();
if (err) {
sdk_warn(&pdev->dev, "Failed to init nictool");
goto init_nictool_err;
}
list_add_tail(&pci_adapter->node, &pci_adapter->chip_node->func_list);
lld_unlock_chip_node();
pci_adapter->init_state = HIFC_INIT_STATE_PCI_INITED;
err = hifc_func_init(pdev, pci_adapter);
if (err)
goto func_init_err;
return 0;
func_init_err:
if (!test_bit(HIFC_FUNC_PRB_DELAY, &pci_adapter->flag))
set_bit(HIFC_FUNC_PRB_ERR, &pci_adapter->flag);
return 0;
init_nictool_err:
free_chip_node(pci_adapter);
alloc_chip_node_fail:
lld_unlock_chip_node();
unmapping_bar(pci_adapter);
map_bar_failed:
hifc_pci_deinit(pdev);
sdk_err(&pdev->dev, "Pcie device probe failed\n");
return err;
}
#define PCI_VENDOR_ID_HUAWEI 0x19e5
#define HIFC_DEV_ID_1822_8G 0x0212
#define HIFC_DEV_ID_1822_16G 0x0203
#define HIFC_DEV_ID_1822_32G 0x0202
/*lint -save -e133 -e10*/
static const struct pci_device_id hifc_pci_table[] = {
{PCI_VDEVICE(HUAWEI, HIFC_DEV_ID_1822_8G), 0},
{PCI_VDEVICE(HUAWEI, HIFC_DEV_ID_1822_16G), 0},
{PCI_VDEVICE(HUAWEI, HIFC_DEV_ID_1822_32G), 0},
{0, 0}
};
/*lint -restore*/
MODULE_DEVICE_TABLE(pci, hifc_pci_table);
static void hifc_shutdown(struct pci_dev *pdev)
{
sdk_err(&pdev->dev, "Shutdown device\n");
pci_disable_device(pdev);
}
static struct pci_driver hifc_driver = {
.name = HIFC_DRV_NAME,
.id_table = hifc_pci_table,
.probe = hifc_hwdev_probe,
.remove = hifc_hwdev_remove,
.shutdown = hifc_shutdown,
};
extern int hifc_init_module(void);
extern void hifc_exit_module(void);
static int __init hifc_lld_init(void)
{
pr_info("%s - version %s\n", HIFC_DRV_DESC, HIFC_DRV_VERSION);
hifc_lld_lock_init();
hifc_init_module();
return pci_register_driver(&hifc_driver);
}
static void __exit hifc_lld_exit(void)
{
pci_unregister_driver(&hifc_driver);
hifc_exit_module();
}
module_init(hifc_lld_init);
module_exit(hifc_lld_exit);